Merge lp:~zsombi/ubuntu-ui-toolkit/stylehints into lp:ubuntu-ui-toolkit/staging

Proposed by Zsombor Egri
Status: Merged
Approved by: Cris Dywan
Approved revision: 1533
Merged at revision: 1526
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/stylehints
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 1078 lines (+815/-20)
23 files modified
components.api (+2/-0)
modules/Ubuntu/Components/plugin/plugin.cpp (+2/-0)
modules/Ubuntu/Components/plugin/plugin.pro (+4/-2)
modules/Ubuntu/Components/plugin/propertychange_p.cpp (+30/-9)
modules/Ubuntu/Components/plugin/propertychange_p.h (+9/-0)
modules/Ubuntu/Components/plugin/ucstyleditembase.cpp (+1/-0)
modules/Ubuntu/Components/plugin/ucstyleditembase.h (+1/-0)
modules/Ubuntu/Components/plugin/ucstylehints.cpp (+259/-0)
modules/Ubuntu/Components/plugin/ucstylehints.h (+92/-0)
modules/Ubuntu/Test/plugin/uctestcase.cpp (+9/-5)
modules/Ubuntu/Test/plugin/uctestcase.h (+1/-1)
tests/unit_x11/tst_subtheming/GroupPropertyBindingHints.qml (+32/-0)
tests/unit_x11/tst_subtheming/HintedButton.qml (+24/-0)
tests/unit_x11/tst_subtheming/MoreStyleHints.qml (+34/-0)
tests/unit_x11/tst_subtheming/OverrideStyleHints.qml (+30/-0)
tests/unit_x11/tst_subtheming/PropertyBindingHints.qml (+31/-0)
tests/unit_x11/tst_subtheming/SimplePropertyHints.qml (+30/-0)
tests/unit_x11/tst_subtheming/StyleHintsElsewhere.qml (+27/-0)
tests/unit_x11/tst_subtheming/StyleHintsInvalidProperty.qml (+30/-0)
tests/unit_x11/tst_subtheming/StyleHintsWithObject.qml (+29/-0)
tests/unit_x11/tst_subtheming/StyleHintsWithSignal.qml (+29/-0)
tests/unit_x11/tst_subtheming/tst_subtheming.cpp (+98/-2)
tests/unit_x11/tst_subtheming/tst_subtheming.pro (+11/-1)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/stylehints
Reviewer Review Type Date Requested Status
Cris Dywan Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+260826@code.launchpad.net

Commit message

Introducing StyleHints to provide style specific property changes.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1532. By Zsombor Egri

documentation fixed

1533. By Zsombor Egri

accidental scrollbar style change

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Cris Dywan (kalikiana) wrote :

I wish all merge requests were this clean, every time I thought "hmm is there a test for that code" there was. Looks pretty slick, and tests pass now.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'components.api'
2--- components.api 2015-05-26 07:38:55 +0000
3+++ components.api 2015-06-02 15:25:00 +0000
4@@ -871,6 +871,8 @@
5 property bool iconFrame
6 property bool progression
7 Ubuntu.Components.StateSaver 1.0 0.1: QtObject
8+Ubuntu.Components.StyleHints 1.3: QtObject
9+ property bool ignoreUnknownProperties
10 Ubuntu.Components.StyledItem 1.3 1.1 1.0 0.1: Item
11 property bool activeFocusOnPress
12 function bool requestFocus(Qt.FocusReason reason)
13
14=== modified file 'modules/Ubuntu/Components/plugin/plugin.cpp'
15--- modules/Ubuntu/Components/plugin/plugin.cpp 2015-05-21 10:50:35 +0000
16+++ modules/Ubuntu/Components/plugin/plugin.cpp 2015-06-02 15:25:00 +0000
17@@ -50,6 +50,7 @@
18 #include "ucinversemouse.h"
19 #include "sortfiltermodel.h"
20 #include "ucstyleditembase.h"
21+#include "ucstylehints.h"
22 #include "ucaction.h"
23 #include "ucactioncontext.h"
24 #include "ucactionmanager.h"
25@@ -211,6 +212,7 @@
26 qmlRegisterType<UCStyledItemBase, 2>(uri, 1, 3, "StyledItem");
27 qmlRegisterSingletonType<UCNamespaceV13>(uri, 1, 3, "Ubuntu", registerUbuntuNamespace13);
28 qmlRegisterType<UCStyledItemBase, 2>(uri, 1, 3, "StyledItem");
29+ qmlRegisterCustomType<UCStyleHints>(uri, 1, 3, "StyleHints", new UCStyleHintsParser);
30 }
31
32 void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
33
34=== modified file 'modules/Ubuntu/Components/plugin/plugin.pro'
35--- modules/Ubuntu/Components/plugin/plugin.pro 2015-03-13 09:27:53 +0000
36+++ modules/Ubuntu/Components/plugin/plugin.pro 2015-06-02 15:25:00 +0000
37@@ -80,7 +80,8 @@
38 privates/listitemdraghandler.h \
39 ucnamespace.h \
40 ucdeprecatedtheme.h \
41- ucdefaulttheme.h
42+ ucdefaulttheme.h \
43+ ucstylehints.h
44
45 SOURCES += plugin.cpp \
46 uctheme.cpp \
47@@ -128,7 +129,8 @@
48 privates/listitemdraghandler.cpp \
49 ucnamespace.cpp \
50 ucdeprecatedtheme.cpp \
51- ucdefaulttheme.cpp
52+ ucdefaulttheme.cpp \
53+ ucstylehints.cpp
54
55 # adapters
56 SOURCES += adapters/alarmsadapter_organizer.cpp
57
58=== modified file 'modules/Ubuntu/Components/plugin/propertychange_p.cpp'
59--- modules/Ubuntu/Components/plugin/propertychange_p.cpp 2015-01-27 18:14:44 +0000
60+++ modules/Ubuntu/Components/plugin/propertychange_p.cpp 2015-06-02 15:25:00 +0000
61@@ -28,6 +28,7 @@
62 PropertyChange::PropertyChange(QObject *item, const char *property, bool autoBackup)
63 : backedUp(false)
64 , qmlProperty(item, property, qmlContext(item))
65+ , backupBinding(Q_NULLPTR)
66 {
67 if (autoBackup) {
68 backup();
69@@ -41,6 +42,7 @@
70 void PropertyChange::backup()
71 {
72 if (!backedUp) {
73+ backupBinding = QQmlPropertyPrivate::binding(qmlProperty);
74 backupValue = qmlProperty.read();
75 backedUp = true;
76 }
77@@ -56,11 +58,24 @@
78 return;
79 }
80 change->backup();
81- // write using QQmlPropertyPrivate so we can keep the bindings
82- QQmlPropertyPrivate::write(change->qmlProperty,
83- value,
84- QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
85-}
86+ change->qmlProperty.write(value);
87+}
88+
89+/*
90+ * Same as setValue() but setting a binding.
91+ */
92+void PropertyChange::setBinding(PropertyChange *change, QQmlAbstractBinding *binding)
93+{
94+ if (!change) {
95+ return;
96+ }
97+ change->backup();
98+ QQmlAbstractBinding *prev = QQmlPropertyPrivate::setBinding(change->qmlProperty, binding);
99+ if (prev && prev != binding && prev != change->backupBinding) {
100+ prev->destroy();
101+ }
102+}
103+
104
105 /*
106 * Restore backed up value or binding.
107@@ -71,10 +86,16 @@
108 return;
109 }
110 if (change->backedUp) {
111- // write using QQmlPropertyPrivate to keep the bindings
112- QQmlPropertyPrivate::write(change->qmlProperty,
113- change->backupValue,
114- QQmlPropertyPrivate::BypassInterceptor | QQmlPropertyPrivate::DontRemoveBinding);
115+ if (change->qmlProperty.isValid()) {
116+ if (change->backupBinding) {
117+ QQmlAbstractBinding *prev = QQmlPropertyPrivate::setBinding(change->qmlProperty, change->backupBinding);
118+ if (prev != change->backupBinding && prev) {
119+ prev->destroy();
120+ }
121+ } else {
122+ change->qmlProperty.write(change->backupValue);
123+ }
124+ }
125 change->backedUp = false;
126 }
127 }
128
129=== modified file 'modules/Ubuntu/Components/plugin/propertychange_p.h'
130--- modules/Ubuntu/Components/plugin/propertychange_p.h 2015-01-27 18:14:44 +0000
131+++ modules/Ubuntu/Components/plugin/propertychange_p.h 2015-06-02 15:25:00 +0000
132@@ -21,6 +21,7 @@
133 #include <QtCore/QObject>
134 #include <QtQml/QQmlProperty>
135
136+class QQmlAbstractBinding;
137 class PropertyChange
138 {
139 public:
140@@ -28,11 +29,19 @@
141 ~PropertyChange();
142
143 static void setValue(PropertyChange* change, const QVariant &value);
144+ static void setBinding(PropertyChange *change, QQmlAbstractBinding *binding);
145 static void restore(PropertyChange* change);
146+
147+ const QQmlProperty &property()
148+ {
149+ return qmlProperty;
150+ }
151+
152 private:
153 bool backedUp;
154 QQmlProperty qmlProperty;
155 QVariant backupValue;
156+ QQmlAbstractBinding *backupBinding;
157
158 void backup();
159 };
160
161=== modified file 'modules/Ubuntu/Components/plugin/ucstyleditembase.cpp'
162--- modules/Ubuntu/Components/plugin/ucstyleditembase.cpp 2015-05-26 15:05:46 +0000
163+++ modules/Ubuntu/Components/plugin/ucstyleditembase.cpp 2015-06-02 15:25:00 +0000
164@@ -19,6 +19,7 @@
165 #include "ucstyleditembase.h"
166 #include "ucstyleditembase_p.h"
167 #include "uctheme.h"
168+#include "ucstylehints.h"
169 #include <QtQml/QQmlEngine>
170 #include <QtQuick/private/qquickanchors_p.h>
171
172
173=== modified file 'modules/Ubuntu/Components/plugin/ucstyleditembase.h'
174--- modules/Ubuntu/Components/plugin/ucstyleditembase.h 2015-05-22 13:54:38 +0000
175+++ modules/Ubuntu/Components/plugin/ucstyleditembase.h 2015-06-02 15:25:00 +0000
176@@ -23,6 +23,7 @@
177
178 class UCStyledItemBasePrivate;
179 class UCTheme;
180+class UCStyleHints;
181 class UCStyledItemBase : public QQuickItem
182 {
183 Q_OBJECT
184
185=== added file 'modules/Ubuntu/Components/plugin/ucstylehints.cpp'
186--- modules/Ubuntu/Components/plugin/ucstylehints.cpp 1970-01-01 00:00:00 +0000
187+++ modules/Ubuntu/Components/plugin/ucstylehints.cpp 2015-06-02 15:25:00 +0000
188@@ -0,0 +1,259 @@
189+/*
190+ * Copyright 2015 Canonical Ltd.
191+ *
192+ * This program is free software; you can redistribute it and/or modify
193+ * it under the terms of the GNU Lesser General Public License as published by
194+ * the Free Software Foundation; version 3.
195+ *
196+ * This program is distributed in the hope that it will be useful,
197+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
198+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
199+ * GNU Lesser General Public License for more details.
200+ *
201+ * You should have received a copy of the GNU Lesser General Public License
202+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
203+ *
204+ * Author: Zsombor Egri <zsombor.egri@canonical.com>
205+ */
206+
207+#include "ucstylehints.h"
208+#include "ucstyleditembase_p.h"
209+#include "propertychange_p.h"
210+#include <QtQml/QQmlInfo>
211+
212+// verifies property declaration correctness
213+void UCStyleHintsParser::verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
214+{
215+ Q_FOREACH(const QV4::CompiledData::Binding *binding, bindings) {
216+ verifyProperty(qmlUnit, binding);
217+ }
218+}
219+
220+void UCStyleHintsParser::verifyProperty(const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding)
221+{
222+ if (binding->type == QV4::CompiledData::Binding::Type_Object) {
223+ error(qmlUnit->objectAt(binding->value.objectIndex), "StyleHints does not support creating state-specific objects.");
224+ return;
225+ }
226+
227+ // group properties or attached properties, we do handle those as well
228+ if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty
229+ || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
230+ const QV4::CompiledData::Object *subObj = qmlUnit->objectAt(binding->value.objectIndex);
231+ const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
232+ for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) {
233+ verifyProperty(qmlUnit, subBinding);
234+ }
235+ }
236+
237+ // filter out signals!
238+ QString propertyName = qmlUnit->stringAt(binding->propertyNameIndex);
239+ if (propertyName.startsWith("on") && propertyName.at(2).isUpper()) {
240+ error(binding, "Signal properties are not supported.");
241+ return;
242+ }
243+}
244+
245+// decodes property declarations, stores the bindings and values
246+void UCStyleHintsParser::applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
247+{
248+ UCStyleHints *hints = static_cast<UCStyleHints*>(obj);
249+ QV4::CompiledData::Unit *qmlUnit = cdata->compilationUnit->data;
250+
251+ UCStyledItemBase *styledItem = qobject_cast<UCStyledItemBase*>(hints->parent());
252+ if (!styledItem) {
253+ // error will be reported in componentCompleted
254+ return;
255+ }
256+
257+ Q_FOREACH(const QV4::CompiledData::Binding *binding, bindings) {
258+ hints->decodeBinding(QString(), qmlUnit, binding);
259+ }
260+
261+ hints->m_cdata = cdata;
262+ hints->m_decoded = true;
263+}
264+
265+void UCStyleHints::decodeBinding(const QString &propertyPrefix, const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding)
266+{
267+ QString propertyName = propertyPrefix + qmlUnit->stringAt(binding->propertyNameIndex);
268+
269+ // handle grouped properties first
270+ if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty
271+ || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
272+
273+ const QV4::CompiledData::Object *subObj = qmlUnit->objectAt(binding->value.objectIndex);
274+ const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
275+ QString pre = propertyName + ".";
276+ for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) {
277+ decodeBinding(pre, qmlUnit, subBinding);
278+ }
279+ return;
280+ }
281+
282+ switch (binding->type) {
283+ case QV4::CompiledData::Binding::Type_Script:
284+ {
285+ QString expression = binding->valueAsScriptString(qmlUnit);
286+ QUrl url = QUrl();
287+ int line = -1;
288+ int column = -1;
289+
290+ QQmlData *ddata = QQmlData::get(this);
291+ if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
292+ url = ddata->outerContext->url;
293+ line = ddata->lineNumber;
294+ column = ddata->columnNumber;
295+ }
296+ m_expressions << Expression(propertyName, binding->value.compiledScriptIndex, expression, url, line, column);
297+ break;
298+ }
299+ case QV4::CompiledData::Binding::Type_Translation:
300+ case QV4::CompiledData::Binding::Type_TranslationById:
301+ case QV4::CompiledData::Binding::Type_String:
302+ {
303+ m_values << qMakePair(propertyName, binding->valueAsString(qmlUnit));
304+ break;
305+ }
306+ case QV4::CompiledData::Binding::Type_Number:
307+ {
308+ m_values << qMakePair(propertyName, binding->valueAsNumber());
309+ break;
310+ }
311+ case QV4::CompiledData::Binding::Type_Boolean:
312+ {
313+ m_values << qMakePair(propertyName, binding->valueAsBoolean());
314+ break;
315+ }
316+ }
317+}
318+
319+void UCStyleHints::propertyNotFound(const QString &styleName, const QString &property)
320+{
321+ if (!m_ignoreUnknownProperties) {
322+ qmlInfo(this) << QString("Style '%1' has no property called '%2'.").arg(styleName).arg(property);
323+ }
324+}
325+
326+/*!
327+ * \qmltype StyleHints
328+ * \instantiates UCStyleHints
329+ * \inmodule Ubuntu Components 1.3
330+ * \ingroup ubuntu
331+ * \since Ubuntu.Components 1.3
332+ * \brief Component holding style specific properties to configure a particular
333+ * StyledItem's style runtime.
334+ *
335+ * StyleHints is a custom parser, meaning style properties can be listed without
336+ * any property declaration, same way as in PropertyChanges or Connections, which
337+ * are similar custom parsers. Properties enumerated do not have to be present in
338+ * the component's style as default, behavior which can be chenged by setting \l
339+ * ignoreUnknownProperties to true. In this case properties not found in the style
340+ * will be displayed as warnings.
341+ *
342+ * In the following example the Button will be drawn as white when not pressed, and
343+ * colored as blue when pressed.
344+ * \qml
345+ * Button {
346+ * id: button
347+ * StyleHints {
348+ * defaultColor: button.pressed ? "blue" : "white"
349+ * }
350+ * }
351+ * \endqml
352+ *
353+ * StyleHints does not support signal properties (i.e signal handlers) and object
354+ * declarations as property values.
355+ *
356+ * StyleHints can be only declared in a \l StyledItem or as a derivate of it.
357+ */
358+
359+/*!
360+ * \qmlproperty bool StyleHints::ignoreUnknownProperties
361+ * The property drives whether component should warn on properties not found in
362+ * the component's style. The default setting is not to warn.
363+ */
364+UCStyleHints::UCStyleHints(QObject *parent)
365+ : QObject(parent)
366+ , m_decoded(false)
367+ , m_completed(false)
368+ , m_ignoreUnknownProperties(true)
369+{
370+}
371+
372+UCStyleHints::~UCStyleHints()
373+{
374+ qDeleteAll(m_propertyBackup);
375+ m_propertyBackup.clear();
376+}
377+
378+void UCStyleHints::classBegin()
379+{
380+ m_styledItem = qobject_cast<UCStyledItemBase*>(parent());
381+ if (m_styledItem) {
382+ connect(m_styledItem, SIGNAL(styleInstanceChanged()),
383+ this, SLOT(_q_applyStyleHints()));
384+ } else {
385+ qmlInfo(this) << "StyleHints must be declared in a StyledItem or a derivate of it.";
386+ }
387+}
388+
389+void UCStyleHints::componentComplete()
390+{
391+ m_completed = (m_styledItem != Q_NULLPTR);
392+ _q_applyStyleHints();
393+}
394+
395+// apply the style hints and check each property existence
396+void UCStyleHints::_q_applyStyleHints()
397+{
398+ if (!m_completed || !m_decoded || !m_styledItem || !UCStyledItemBasePrivate::get(m_styledItem)->styleItem) {
399+ return;
400+ }
401+
402+ // restore properties first
403+ qDeleteAll(m_propertyBackup);
404+ m_propertyBackup.clear();
405+
406+ QQuickItem *item = UCStyledItemBasePrivate::get(m_styledItem)->styleItem;
407+ const QMetaObject *mo = item->metaObject();
408+ const QString styleName = UCStyledItemBasePrivate::get(m_styledItem)->styleName();
409+ // apply values first
410+ for (int i = 0; i < m_values.size(); i++) {
411+ if (mo->indexOfProperty(m_values[i].first.toUtf8()) < 0) {
412+ propertyNotFound(styleName, m_values[i].first);
413+ continue;
414+ }
415+ PropertyChange *change = new PropertyChange(item, m_values[i].first.toUtf8());
416+ PropertyChange::setValue(change, m_values[i].second);
417+ m_propertyBackup << change;
418+ }
419+
420+ QQmlContext *context = qmlContext(this);
421+ // then apply expressions/bindings
422+ for (int ii = 0; ii < m_expressions.count(); ii++) {
423+ Expression e = m_expressions[ii];
424+ PropertyChange *change = new PropertyChange(item, e.name.toUtf8());
425+ if (!change->property().isValid()) {
426+ propertyNotFound(styleName, e.name);
427+ delete change;
428+ continue;
429+ }
430+
431+ // create a binding object from the expression using the palette context
432+ QQmlContextData *cdata = QQmlContextData::get(context);
433+ QQmlBinding *newBinding = 0;
434+ if (e.id != QQmlBinding::Invalid) {
435+ QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this)));
436+ QV4::ScopedValue function(scope, QV4::QmlBindingWrapper::createQmlCallableForFunction(cdata, item, m_cdata->compilationUnit->runtimeFunctions[e.id]));
437+ newBinding = new QQmlBinding(function, item, cdata);
438+ }
439+ if (!newBinding) {
440+ newBinding = new QQmlBinding(e.expression, item, cdata, e.url.toString(), e.line, e.column);
441+ }
442+
443+ newBinding->setTarget(change->property());
444+ PropertyChange::setBinding(change, newBinding);
445+ }
446+}
447+
448
449=== added file 'modules/Ubuntu/Components/plugin/ucstylehints.h'
450--- modules/Ubuntu/Components/plugin/ucstylehints.h 1970-01-01 00:00:00 +0000
451+++ modules/Ubuntu/Components/plugin/ucstylehints.h 2015-06-02 15:25:00 +0000
452@@ -0,0 +1,92 @@
453+/*
454+ * Copyright 2015 Canonical Ltd.
455+ *
456+ * This program is free software; you can redistribute it and/or modify
457+ * it under the terms of the GNU Lesser General Public License as published by
458+ * the Free Software Foundation; version 3.
459+ *
460+ * This program is distributed in the hope that it will be useful,
461+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
462+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
463+ * GNU Lesser General Public License for more details.
464+ *
465+ * You should have received a copy of the GNU Lesser General Public License
466+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
467+ *
468+ * Author: Zsombor Egri <zsombor.egri@canonical.com>
469+ */
470+
471+#ifndef UCSTYLEHINTS_H
472+#define UCSTYLEHINTS_H
473+
474+#include <QtCore/QObject>
475+#define foreach Q_FOREACH
476+#include <QtQml/private/qqmlcustomparser_p.h>
477+#include <private/qv4engine_p.h>
478+#include <private/qpodvector_p.h>
479+#undef foreach
480+#include <QtQml/private/qqmlcompiler_p.h>
481+
482+class UCStyleHintsParser;
483+class UCStyledItemBase;
484+class QQuickItem;
485+class PropertyChange;
486+class UCStyleHints : public QObject, public QQmlParserStatus
487+{
488+ Q_OBJECT
489+ Q_INTERFACES(QQmlParserStatus)
490+ Q_PROPERTY(bool ignoreUnknownProperties MEMBER m_ignoreUnknownProperties)
491+
492+public:
493+ explicit UCStyleHints(QObject *parent = 0);
494+ ~UCStyleHints();
495+
496+private Q_SLOTS:
497+ void _q_applyStyleHints();
498+
499+protected:
500+ void classBegin();
501+ void componentComplete();
502+
503+private:
504+ class Expression {
505+ public:
506+ Expression(const QString &name, QQmlBinding::Identifier id, const QString& expr,
507+ const QUrl &url, int line, int column)
508+ : name(name), id(id), expression(expr), url(url), line(line), column(column) {}
509+ QString name;
510+ QQmlBinding::Identifier id;
511+ QString expression;
512+ QUrl url;
513+ int line;
514+ int column;
515+ };
516+
517+ bool m_decoded:1;
518+ bool m_completed:1;
519+ bool m_ignoreUnknownProperties:1;
520+ QPointer<UCStyledItemBase> m_styledItem;
521+ QList<Expression> m_expressions;
522+ QList< QPair<QString, QVariant> > m_values;
523+ QList< PropertyChange* > m_propertyBackup;
524+ QQmlRefPointer<QQmlCompiledData> m_cdata;
525+
526+ friend class UCStyleHintsParser;
527+
528+ void propertyNotFound(const QString &styleName, const QString &property);
529+ void decodeBinding(const QString &propertyPrefix, const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding);
530+};
531+
532+class UCStyleHintsParser : public QQmlCustomParser
533+{
534+public:
535+ UCStyleHintsParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {}
536+
537+ virtual void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
538+ virtual void applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings);
539+
540+private:
541+ void verifyProperty(const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding);
542+};
543+
544+#endif // UCSTYLEHINTS_H
545
546=== modified file 'modules/Ubuntu/Test/plugin/uctestcase.cpp'
547--- modules/Ubuntu/Test/plugin/uctestcase.cpp 2014-11-25 09:58:33 +0000
548+++ modules/Ubuntu/Test/plugin/uctestcase.cpp 2015-06-02 15:25:00 +0000
549@@ -32,7 +32,7 @@
550 * \ingroup ubuntu
551 * \brief UbuntuTestCase is the C++ pendant to the QML UbuntuTestCase.
552 */
553-UbuntuTestCase::UbuntuTestCase(const QString& file, QWindow* parent) : QQuickView(parent)
554+UbuntuTestCase::UbuntuTestCase(const QString& file, bool assertOnFailure, QWindow* parent) : QQuickView(parent)
555 {
556 QString modules(UBUNTU_QML_IMPORT_PATH);
557 Q_ASSERT(QDir(modules).exists());
558@@ -45,10 +45,14 @@
559
560 Q_ASSERT(!file.isEmpty());
561 setSource(QUrl::fromLocalFile(file));
562- Q_ASSERT(status() == QQuickView::Ready);
563- Q_ASSERT(rootObject());
564- show();
565- QTest::qWaitForWindowExposed(this);
566+ if (assertOnFailure) {
567+ Q_ASSERT(status() == QQuickView::Ready);
568+ Q_ASSERT(rootObject());
569+ }
570+ if (rootObject()) {
571+ show();
572+ QTest::qWaitForWindowExposed(this);
573+ }
574 }
575
576 /*!
577
578=== modified file 'modules/Ubuntu/Test/plugin/uctestcase.h'
579--- modules/Ubuntu/Test/plugin/uctestcase.h 2015-03-06 14:35:53 +0000
580+++ modules/Ubuntu/Test/plugin/uctestcase.h 2015-06-02 15:25:00 +0000
581@@ -28,7 +28,7 @@
582 {
583 Q_OBJECT
584 public:
585- UbuntuTestCase(const QString& file, QWindow* parent = 0);
586+ UbuntuTestCase(const QString& file, bool assertOnFailure = true, QWindow* parent = 0);
587 int warnings() const;
588 // getter
589 template<class T>
590
591=== added file 'tests/unit_x11/tst_subtheming/GroupPropertyBindingHints.qml'
592--- tests/unit_x11/tst_subtheming/GroupPropertyBindingHints.qml 1970-01-01 00:00:00 +0000
593+++ tests/unit_x11/tst_subtheming/GroupPropertyBindingHints.qml 2015-06-02 15:25:00 +0000
594@@ -0,0 +1,32 @@
595+/*
596+ * Copyright 2015 Canonical Ltd.
597+ *
598+ * This program is free software; you can redistribute it and/or modify
599+ * it under the terms of the GNU Lesser General Public License as published by
600+ * the Free Software Foundation; version 3.
601+ *
602+ * This program is distributed in the hope that it will be useful,
603+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
604+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
605+ * GNU Lesser General Public License for more details.
606+ *
607+ * You should have received a copy of the GNU Lesser General Public License
608+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
609+ */
610+
611+import QtQuick 2.4
612+import Ubuntu.Components 1.3
613+
614+Item {
615+ width: units.gu(40)
616+ height: units.gu(71)
617+
618+ HintedButton {
619+ objectName: "Button"
620+ id: button
621+ gradient: UbuntuColors.greyGradient
622+ StyleHints {
623+ gradientProxy.topColor: button.pressed ? "tan" : "blue"
624+ }
625+ }
626+}
627
628=== added file 'tests/unit_x11/tst_subtheming/HintedButton.qml'
629--- tests/unit_x11/tst_subtheming/HintedButton.qml 1970-01-01 00:00:00 +0000
630+++ tests/unit_x11/tst_subtheming/HintedButton.qml 2015-06-02 15:25:00 +0000
631@@ -0,0 +1,24 @@
632+/*
633+ * Copyright 2015 Canonical Ltd.
634+ *
635+ * This program is free software; you can redistribute it and/or modify
636+ * it under the terms of the GNU Lesser General Public License as published by
637+ * the Free Software Foundation; version 3.
638+ *
639+ * This program is distributed in the hope that it will be useful,
640+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
641+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
642+ * GNU Lesser General Public License for more details.
643+ *
644+ * You should have received a copy of the GNU Lesser General Public License
645+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
646+ */
647+
648+import QtQuick 2.4
649+import Ubuntu.Components 1.3
650+
651+Button {
652+ StyleHints {
653+ minimumWidth: units.gu(20)
654+ }
655+}
656
657=== added file 'tests/unit_x11/tst_subtheming/MoreStyleHints.qml'
658--- tests/unit_x11/tst_subtheming/MoreStyleHints.qml 1970-01-01 00:00:00 +0000
659+++ tests/unit_x11/tst_subtheming/MoreStyleHints.qml 2015-06-02 15:25:00 +0000
660@@ -0,0 +1,34 @@
661+/*
662+ * Copyright 2015 Canonical Ltd.
663+ *
664+ * This program is free software; you can redistribute it and/or modify
665+ * it under the terms of the GNU Lesser General Public License as published by
666+ * the Free Software Foundation; version 3.
667+ *
668+ * This program is distributed in the hope that it will be useful,
669+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
670+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
671+ * GNU Lesser General Public License for more details.
672+ *
673+ * You should have received a copy of the GNU Lesser General Public License
674+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
675+ */
676+
677+import QtQuick 2.4
678+import Ubuntu.Components 1.3
679+
680+Item {
681+ width: units.gu(40)
682+ height: units.gu(71)
683+
684+ Button {
685+ objectName: "Button"
686+ StyleHints {
687+ minimumWidth: units.gu(20)
688+ }
689+
690+ StyleHints {
691+ defaultColor: "brown"
692+ }
693+ }
694+}
695
696=== added file 'tests/unit_x11/tst_subtheming/OverrideStyleHints.qml'
697--- tests/unit_x11/tst_subtheming/OverrideStyleHints.qml 1970-01-01 00:00:00 +0000
698+++ tests/unit_x11/tst_subtheming/OverrideStyleHints.qml 2015-06-02 15:25:00 +0000
699@@ -0,0 +1,30 @@
700+/*
701+ * Copyright 2015 Canonical Ltd.
702+ *
703+ * This program is free software; you can redistribute it and/or modify
704+ * it under the terms of the GNU Lesser General Public License as published by
705+ * the Free Software Foundation; version 3.
706+ *
707+ * This program is distributed in the hope that it will be useful,
708+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
709+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
710+ * GNU Lesser General Public License for more details.
711+ *
712+ * You should have received a copy of the GNU Lesser General Public License
713+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
714+ */
715+
716+import QtQuick 2.4
717+import Ubuntu.Components 1.3
718+
719+Item {
720+ width: units.gu(40)
721+ height: units.gu(71)
722+
723+ HintedButton {
724+ objectName: "Button"
725+ StyleHints {
726+ minimumWidth: 5
727+ }
728+ }
729+}
730
731=== added file 'tests/unit_x11/tst_subtheming/PropertyBindingHints.qml'
732--- tests/unit_x11/tst_subtheming/PropertyBindingHints.qml 1970-01-01 00:00:00 +0000
733+++ tests/unit_x11/tst_subtheming/PropertyBindingHints.qml 2015-06-02 15:25:00 +0000
734@@ -0,0 +1,31 @@
735+/*
736+ * Copyright 2015 Canonical Ltd.
737+ *
738+ * This program is free software; you can redistribute it and/or modify
739+ * it under the terms of the GNU Lesser General Public License as published by
740+ * the Free Software Foundation; version 3.
741+ *
742+ * This program is distributed in the hope that it will be useful,
743+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
744+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
745+ * GNU Lesser General Public License for more details.
746+ *
747+ * You should have received a copy of the GNU Lesser General Public License
748+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
749+ */
750+
751+import QtQuick 2.4
752+import Ubuntu.Components 1.3
753+
754+Item {
755+ width: units.gu(40)
756+ height: units.gu(71)
757+
758+ Button {
759+ objectName: "Button"
760+ id: button
761+ StyleHints {
762+ defaultColor: button.pressed ? "tan" : "blue"
763+ }
764+ }
765+}
766
767=== added file 'tests/unit_x11/tst_subtheming/SimplePropertyHints.qml'
768--- tests/unit_x11/tst_subtheming/SimplePropertyHints.qml 1970-01-01 00:00:00 +0000
769+++ tests/unit_x11/tst_subtheming/SimplePropertyHints.qml 2015-06-02 15:25:00 +0000
770@@ -0,0 +1,30 @@
771+/*
772+ * Copyright 2015 Canonical Ltd.
773+ *
774+ * This program is free software; you can redistribute it and/or modify
775+ * it under the terms of the GNU Lesser General Public License as published by
776+ * the Free Software Foundation; version 3.
777+ *
778+ * This program is distributed in the hope that it will be useful,
779+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
780+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
781+ * GNU Lesser General Public License for more details.
782+ *
783+ * You should have received a copy of the GNU Lesser General Public License
784+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
785+ */
786+
787+import QtQuick 2.4
788+import Ubuntu.Components 1.3
789+
790+Item {
791+ width: units.gu(40)
792+ height: units.gu(71)
793+
794+ Button {
795+ objectName: "Button"
796+ StyleHints {
797+ defaultColor: "blue"
798+ }
799+ }
800+}
801
802=== added file 'tests/unit_x11/tst_subtheming/StyleHintsElsewhere.qml'
803--- tests/unit_x11/tst_subtheming/StyleHintsElsewhere.qml 1970-01-01 00:00:00 +0000
804+++ tests/unit_x11/tst_subtheming/StyleHintsElsewhere.qml 2015-06-02 15:25:00 +0000
805@@ -0,0 +1,27 @@
806+/*
807+ * Copyright 2015 Canonical Ltd.
808+ *
809+ * This program is free software; you can redistribute it and/or modify
810+ * it under the terms of the GNU Lesser General Public License as published by
811+ * the Free Software Foundation; version 3.
812+ *
813+ * This program is distributed in the hope that it will be useful,
814+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
815+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
816+ * GNU Lesser General Public License for more details.
817+ *
818+ * You should have received a copy of the GNU Lesser General Public License
819+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
820+ */
821+
822+import QtQuick 2.4
823+import Ubuntu.Components 1.3
824+
825+Item {
826+ width: units.gu(40)
827+ height: units.gu(71)
828+
829+ StyleHints {
830+ anyProperty: true
831+ }
832+}
833
834=== added file 'tests/unit_x11/tst_subtheming/StyleHintsInvalidProperty.qml'
835--- tests/unit_x11/tst_subtheming/StyleHintsInvalidProperty.qml 1970-01-01 00:00:00 +0000
836+++ tests/unit_x11/tst_subtheming/StyleHintsInvalidProperty.qml 2015-06-02 15:25:00 +0000
837@@ -0,0 +1,30 @@
838+/*
839+ * Copyright 2015 Canonical Ltd.
840+ *
841+ * This program is free software; you can redistribute it and/or modify
842+ * it under the terms of the GNU Lesser General Public License as published by
843+ * the Free Software Foundation; version 3.
844+ *
845+ * This program is distributed in the hope that it will be useful,
846+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
847+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
848+ * GNU Lesser General Public License for more details.
849+ *
850+ * You should have received a copy of the GNU Lesser General Public License
851+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
852+ */
853+
854+import QtQuick 2.4
855+import Ubuntu.Components 1.3
856+
857+Item {
858+ width: units.gu(40)
859+ height: units.gu(71)
860+
861+ Button {
862+ StyleHints {
863+ ignoreUnknownProperties: false
864+ invalidProperty: 10
865+ }
866+ }
867+}
868
869=== added file 'tests/unit_x11/tst_subtheming/StyleHintsWithObject.qml'
870--- tests/unit_x11/tst_subtheming/StyleHintsWithObject.qml 1970-01-01 00:00:00 +0000
871+++ tests/unit_x11/tst_subtheming/StyleHintsWithObject.qml 2015-06-02 15:25:00 +0000
872@@ -0,0 +1,29 @@
873+/*
874+ * Copyright 2015 Canonical Ltd.
875+ *
876+ * This program is free software; you can redistribute it and/or modify
877+ * it under the terms of the GNU Lesser General Public License as published by
878+ * the Free Software Foundation; version 3.
879+ *
880+ * This program is distributed in the hope that it will be useful,
881+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
882+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
883+ * GNU Lesser General Public License for more details.
884+ *
885+ * You should have received a copy of the GNU Lesser General Public License
886+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
887+ */
888+
889+import QtQuick 2.4
890+import Ubuntu.Components 1.3
891+
892+Item {
893+ width: units.gu(40)
894+ height: units.gu(71)
895+
896+ Button {
897+ StyleHints {
898+ anyProperty: QtObject{}
899+ }
900+ }
901+}
902
903=== added file 'tests/unit_x11/tst_subtheming/StyleHintsWithSignal.qml'
904--- tests/unit_x11/tst_subtheming/StyleHintsWithSignal.qml 1970-01-01 00:00:00 +0000
905+++ tests/unit_x11/tst_subtheming/StyleHintsWithSignal.qml 2015-06-02 15:25:00 +0000
906@@ -0,0 +1,29 @@
907+/*
908+ * Copyright 2015 Canonical Ltd.
909+ *
910+ * This program is free software; you can redistribute it and/or modify
911+ * it under the terms of the GNU Lesser General Public License as published by
912+ * the Free Software Foundation; version 3.
913+ *
914+ * This program is distributed in the hope that it will be useful,
915+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
916+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
917+ * GNU Lesser General Public License for more details.
918+ *
919+ * You should have received a copy of the GNU Lesser General Public License
920+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
921+ */
922+
923+import QtQuick 2.4
924+import Ubuntu.Components 1.3
925+
926+Item {
927+ width: units.gu(40)
928+ height: units.gu(71)
929+
930+ Button {
931+ StyleHints {
932+ onDefaultColorChanged: {}
933+ }
934+ }
935+}
936
937=== modified file 'tests/unit_x11/tst_subtheming/tst_subtheming.cpp'
938--- tests/unit_x11/tst_subtheming/tst_subtheming.cpp 2015-05-26 15:05:46 +0000
939+++ tests/unit_x11/tst_subtheming/tst_subtheming.cpp 2015-06-02 15:25:00 +0000
940@@ -25,13 +25,14 @@
941 #include "uctestcase.h"
942 #include "ucstyleditembase_p.h"
943 #include "ucnamespace.h"
944+#include "ucunits.h"
945
946 class ThemeTestCase : public UbuntuTestCase
947 {
948 Q_OBJECT
949 public:
950- ThemeTestCase(const QString& file, QWindow* parent = 0)
951- : UbuntuTestCase(file, parent)
952+ ThemeTestCase(const QString& file, bool assertOnFailure = true, QWindow* parent = 0)
953+ : UbuntuTestCase(file, assertOnFailure, parent)
954 {
955 }
956
957@@ -741,6 +742,101 @@
958 QScopedPointer<ThemeTestCase> view(new ThemeTestCase("DeprecatedTheme.qml"));
959 view->rootObject()->setProperty("styleName", "OptionSelectorStyle.qml");
960 }
961+
962+ void test_stylehints_errors_data()
963+ {
964+ QTest::addColumn<QString>("document");
965+ QTest::addColumn<int>("row");
966+ QTest::addColumn<int>("col");
967+ QTest::addColumn<QString>("xfail");
968+
969+ QTest::newRow("No signals")
970+ << "StyleHintsWithSignal.qml" << 26 << 13 << "Signal properties are not supported. \n" \
971+" onDefaultColorChanged: {} \n" \
972+" ^";
973+ QTest::newRow("No embedded objects")
974+ << "StyleHintsWithObject.qml" << 26 << 26 << "StyleHints does not support creating state-specific objects. \n" \
975+" anyProperty: QtObject{} \n" \
976+" ^";
977+ QTest::newRow("StyleHints declared elsewhere")
978+ << "StyleHintsElsewhere.qml" << 24 << 5 << "QML StyleHints: StyleHints must be declared in a StyledItem or a derivate of it.";
979+ QTest::newRow("Invalid property")
980+ << "StyleHintsInvalidProperty.qml" << 25 << 9 << "QML StyleHints: Style 'ButtonStyle' has no property called 'invalidProperty'.";
981+ }
982+ void test_stylehints_errors()
983+ {
984+ QFETCH(QString, document);
985+ QFETCH(int, row);
986+ QFETCH(int, col);
987+ QFETCH(QString, xfail);
988+
989+ if (!xfail.isEmpty()) {
990+ ThemeTestCase::ignoreWarning(document, row, col, xfail);
991+ }
992+ QScopedPointer<ThemeTestCase> view(new ThemeTestCase(document, false));
993+ }
994+
995+ void test_stylehints_simple_property()
996+ {
997+ QScopedPointer<ThemeTestCase> view(new ThemeTestCase("SimplePropertyHints.qml"));
998+ QQuickItem *button = view->findItem<QQuickItem*>("Button");
999+ QColor color = button->property("color").value<QColor>();
1000+ QCOMPARE(color, QColor("blue"));
1001+ }
1002+
1003+ void test_stylehints_bindings()
1004+ {
1005+ QScopedPointer<ThemeTestCase> view(new ThemeTestCase("PropertyBindingHints.qml"));
1006+ QQuickItem *button = view->findItem<QQuickItem*>("Button");
1007+ QColor color = button->property("color").value<QColor>();
1008+ QCOMPARE(color, QColor("blue"));
1009+ // press the button
1010+ QPointF pressPt(button->width()/2, button->height()/2);
1011+ pressPt = view->rootObject()->mapFromItem(button, pressPt);
1012+ QTest::mousePress(view.data(), Qt::LeftButton, 0, pressPt.toPoint());
1013+ color = button->property("color").value<QColor>();
1014+ QCOMPARE(color, QColor("tan"));
1015+ QTest::mouseRelease(view.data(), Qt::LeftButton, 0, pressPt.toPoint());
1016+ }
1017+
1018+ void test_stylehints_multiple_data()
1019+ {
1020+ QTest::addColumn<QString>("document");
1021+ QTest::addColumn<QString>("colorProperty");
1022+ QTest::addColumn<QColor>("colorReleased");
1023+ QTest::addColumn<QColor>("colorPressed");
1024+ QTest::addColumn<QString>("widthProperty");
1025+ QTest::addColumn<float>("width");
1026+
1027+ QTest::newRow("Same document")
1028+ << "MoreStyleHints.qml" << "defaultColor" << QColor("brown") << QColor("brown") << "minimumWidth" << UCUnits::instance().gu(20);
1029+ QTest::newRow("Different document")
1030+ << "GroupPropertyBindingHints.qml" << "gradientProxy.topColor" << QColor("blue") << QColor("tan") << "minimumWidth" << UCUnits::instance().gu(20);
1031+ }
1032+ void test_stylehints_multiple()
1033+ {
1034+ QFETCH(QString, document);
1035+ QFETCH(QString, colorProperty);
1036+ QFETCH(QColor, colorReleased);
1037+ QFETCH(QColor, colorPressed);
1038+ QFETCH(QString, widthProperty);
1039+ QFETCH(float, width);
1040+
1041+ QScopedPointer<ThemeTestCase> view(new ThemeTestCase(document));
1042+ UCStyledItemBase *button = view->findItem<UCStyledItemBase*>("Button");
1043+ QQuickItem *styleItem = UCStyledItemBasePrivate::get(button)->styleItem;
1044+ QVERIFY(styleItem);
1045+ QQmlProperty qmlProperty(styleItem, colorProperty, qmlContext(styleItem));
1046+ QCOMPARE(qmlProperty.read().value<QColor>(), colorReleased);
1047+ QCOMPARE(styleItem->property(widthProperty.toUtf8()).toReal(), width);
1048+
1049+ QPointF pressPt(button->width()/2, button->height()/2);
1050+ pressPt = view->rootObject()->mapFromItem(button, pressPt);
1051+ QTest::mousePress(view.data(), Qt::LeftButton, 0, pressPt.toPoint());
1052+ QColor pressedColor = qmlProperty.read().value<QColor>();
1053+ QTest::mouseRelease(view.data(), Qt::LeftButton, 0, pressPt.toPoint());
1054+ QCOMPARE(pressedColor, colorPressed);
1055+ }
1056 };
1057
1058 QTEST_MAIN(tst_Subtheming)
1059
1060=== modified file 'tests/unit_x11/tst_subtheming/tst_subtheming.pro'
1061--- tests/unit_x11/tst_subtheming/tst_subtheming.pro 2015-05-22 13:54:38 +0000
1062+++ tests/unit_x11/tst_subtheming/tst_subtheming.pro 2015-06-02 15:25:00 +0000
1063@@ -33,6 +33,16 @@
1064 DeprecatedTheme.qml \
1065 StyledItemAppThemeVersioned.qml \
1066 StyleOverride.qml \
1067- StyleKept.qml
1068+ StyleKept.qml \
1069+ SimplePropertyHints.qml \
1070+ StyleHintsWithSignal.qml \
1071+ StyleHintsWithObject.qml \
1072+ StyleHintsElsewhere.qml \
1073+ StyleHintsInvalidProperty.qml \
1074+ PropertyBindingHints.qml \
1075+ MoreStyleHints.qml \
1076+ GroupPropertyBindingHints.qml \
1077+ OverrideStyleHints.qml \
1078+ HintedButton.qml
1079
1080

Subscribers

People subscribed via source and target branches