1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qdeclarativepropertychanges_p.h"
44 #include <private/qdeclarativeopenmetaobject_p.h>
45 #include <private/qdeclarativerewrite_p.h>
46 #include <private/qdeclarativeengine_p.h>
48 #include <qdeclarativeinfo.h>
49 #include <private/qdeclarativecustomparser_p.h>
50 #include <private/qdeclarativescript_p.h>
51 #include <qdeclarativeexpression.h>
52 #include <private/qdeclarativebinding_p.h>
53 #include <qdeclarativecontext.h>
54 #include <private/qdeclarativeguard_p.h>
55 #include <private/qdeclarativeproperty_p.h>
56 #include <private/qdeclarativecontext_p.h>
57 #include <private/qdeclarativestate_p_p.h>
59 #include <QtCore/qdebug.h>
61 #include <private/qobject_p.h>
66 \qmlclass PropertyChanges QDeclarativePropertyChanges
67 \inqmlmodule QtQuick 2
68 \ingroup qml-state-elements
69 \brief The PropertyChanges element describes new property bindings or values for a state.
71 PropertyChanges is used to define the property values or bindings in a
72 \l State. This enables an item's property values to be changed when it
73 \l {QML States}{changes between states}.
75 To create a PropertyChanges object, specify the \l target item whose
76 properties are to be modified, and define the new property values or
77 bindings. For example:
79 \snippet doc/src/snippets/declarative/propertychanges.qml import
81 \snippet doc/src/snippets/declarative/propertychanges.qml 0
83 When the mouse is pressed, the \l Rectangle changes to the \e resized
84 state. In this state, the PropertyChanges object sets the rectangle's
85 color to blue and the \c height value to that of \c container.height.
87 Note this automatically binds \c rect.height to \c container.height
88 in the \e resized state. If a property binding should not be
89 established, and the height should just be set to the value of
90 \c container.height at the time of the state change, set the \l explicit
93 A PropertyChanges object can also override the default signal handler
94 for an object to implement a signal handler specific to the new state:
99 onClicked: doSomethingDifferent()
103 \note PropertyChanges can be used to change anchor margins, but not other anchor
104 values; use AnchorChanges for this instead. Similarly, to change an \l Item's
105 \l {Item::}{parent} value, use ParentChanges instead.
108 \section2 Resetting property values
110 The \c undefined value can be used to reset the property value for a state.
111 In the following example, when \c myText changes to the \e widerText
112 state, its \c width property is reset, giving the text its natural width
113 and displaying the whole string on a single line.
115 \snippet doc/src/snippets/declarative/propertychanges.qml reset
118 \section2 Immediate property changes in transitions
120 When \l{QML Animation and Transitions}{Transitions} are used to animate
121 state changes, they animate properties from their values in the current
122 state to those defined in the new state (as defined by PropertyChanges
123 objects). However, it is sometimes desirable to set a property value
124 \e immediately during a \l Transition, without animation; in these cases,
125 the PropertyAction element can be used to force an immediate property
128 See the PropertyAction documentation for more details.
130 \sa {declarative/animation/states}{states example}, {qmlstate}{States}, QtDeclarative
134 \qmlproperty Object QtQuick2::PropertyChanges::target
135 This property holds the object which contains the properties to be changed.
138 class QDeclarativeReplaceSignalHandler : public QDeclarativeActionEvent
141 QDeclarativeReplaceSignalHandler() : expression(0), reverseExpression(0),
142 rewindExpression(0), ownedExpression(0) {}
143 ~QDeclarativeReplaceSignalHandler() {
144 delete ownedExpression;
147 virtual EventType type() const { return SignalHandler; }
149 QDeclarativeProperty property;
150 QDeclarativeExpression *expression;
151 QDeclarativeExpression *reverseExpression;
152 QDeclarativeExpression *rewindExpression;
153 QDeclarativeGuard<QDeclarativeExpression> ownedExpression;
155 virtual void execute(Reason) {
156 ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, expression);
157 if (ownedExpression == expression)
161 virtual bool isReversable() { return true; }
162 virtual void reverse(Reason) {
163 ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, reverseExpression);
164 if (ownedExpression == reverseExpression)
168 virtual void saveOriginals() {
170 reverseExpression = rewindExpression;
173 virtual bool needsCopy() { return true; }
174 virtual void copyOriginals(QDeclarativeActionEvent *other)
176 QDeclarativeReplaceSignalHandler *rsh = static_cast<QDeclarativeReplaceSignalHandler*>(other);
180 reverseExpression = rsh->reverseExpression;
181 if (rsh->ownedExpression == reverseExpression) {
182 ownedExpression = rsh->ownedExpression;
183 rsh->ownedExpression = 0;
187 virtual void rewind() {
188 ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, rewindExpression);
189 if (ownedExpression == rewindExpression)
192 virtual void saveCurrentValues() {
193 rewindExpression = QDeclarativePropertyPrivate::signalExpression(property);
196 virtual bool override(QDeclarativeActionEvent*other) {
199 if (other->type() != type())
201 if (static_cast<QDeclarativeReplaceSignalHandler*>(other)->property == property)
208 class QDeclarativePropertyChangesPrivate : public QDeclarativeStateOperationPrivate
210 Q_DECLARE_PUBLIC(QDeclarativePropertyChanges)
212 QDeclarativePropertyChangesPrivate() : decoded(true), restore(true),
215 QDeclarativeGuard<QObject> object;
224 class ExpressionChange {
226 ExpressionChange(const QString &_name,
227 QDeclarativeBinding::Identifier _id,
228 QDeclarativeExpression *_expr)
229 : name(_name), id(_id), expression(_expr) {}
231 QDeclarativeBinding::Identifier id;
232 QDeclarativeExpression *expression;
235 QList<QPair<QString, QVariant> > properties;
236 QList<ExpressionChange> expressions;
237 QList<QDeclarativeReplaceSignalHandler*> signalReplacements;
239 QDeclarativeProperty property(const QString &);
243 QDeclarativePropertyChangesParser::compileList(QList<QPair<QString, QVariant> > &list,
245 const QDeclarativeCustomParserProperty &prop)
247 QString propName = pre + prop.name();
249 QList<QVariant> values = prop.assignedValues();
250 for (int ii = 0; ii < values.count(); ++ii) {
251 const QVariant &value = values.at(ii);
253 if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
254 error(qvariant_cast<QDeclarativeCustomParserNode>(value),
255 QDeclarativePropertyChanges::tr("PropertyChanges does not support creating state-specific objects."));
257 } else if(value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
259 QDeclarativeCustomParserProperty prop =
260 qvariant_cast<QDeclarativeCustomParserProperty>(value);
261 QString pre = propName + QLatin1Char('.');
262 compileList(list, pre, prop);
265 list << qMakePair(propName, value);
271 QDeclarativePropertyChangesParser::compile(const QList<QDeclarativeCustomParserProperty> &props)
273 QList<QPair<QString, QVariant> > data;
274 for(int ii = 0; ii < props.count(); ++ii)
275 compileList(data, QString(), props.at(ii));
278 QDataStream ds(&rv, QIODevice::WriteOnly);
281 for(int ii = 0; ii < data.count(); ++ii) {
282 QDeclarativeScript::Variant v = qvariant_cast<QDeclarativeScript::Variant>(data.at(ii).second);
284 bool isScript = v.isScript();
285 QDeclarativeBinding::Identifier id = 0;
287 case QDeclarativeScript::Variant::Boolean:
288 var = QVariant(v.asBoolean());
290 case QDeclarativeScript::Variant::Number:
291 var = QVariant(v.asNumber());
293 case QDeclarativeScript::Variant::String:
294 var = QVariant(v.asString());
296 case QDeclarativeScript::Variant::Invalid:
297 case QDeclarativeScript::Variant::Script:
298 var = QVariant(v.asScript());
300 // Pre-rewrite the expression
301 id = rewriteBinding(v, data.at(ii).first);
306 ds << data.at(ii).first << isScript << var;
314 void QDeclarativePropertyChangesPrivate::decode()
316 Q_Q(QDeclarativePropertyChanges);
320 QDataStream ds(&data, QIODevice::ReadOnly);
324 for (int ii = 0; ii < count; ++ii) {
328 QDeclarativeBinding::Identifier id = QDeclarativeBinding::Invalid;
335 QDeclarativeProperty prop = property(name); //### better way to check for signal property?
336 if (prop.type() & QDeclarativeProperty::SignalProperty) {
337 QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(q), object, data.toString());
338 QDeclarativeData *ddata = QDeclarativeData::get(q);
339 if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
340 expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber, ddata->columnNumber);
341 QDeclarativeReplaceSignalHandler *handler = new QDeclarativeReplaceSignalHandler;
342 handler->property = prop;
343 handler->expression = expression;
344 signalReplacements << handler;
345 } else if (isScript) {
346 QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(q), object, data.toString());
347 QDeclarativeData *ddata = QDeclarativeData::get(q);
348 if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
349 expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber, ddata->columnNumber);
350 expressions << ExpressionChange(name, id, expression);
352 properties << qMakePair(name, data);
360 void QDeclarativePropertyChangesParser::setCustomData(QObject *object,
361 const QByteArray &data)
363 QDeclarativePropertyChangesPrivate *p =
364 static_cast<QDeclarativePropertyChangesPrivate *>(QObjectPrivate::get(object));
369 QDeclarativePropertyChanges::QDeclarativePropertyChanges()
370 : QDeclarativeStateOperation(*(new QDeclarativePropertyChangesPrivate))
374 QDeclarativePropertyChanges::~QDeclarativePropertyChanges()
376 Q_D(QDeclarativePropertyChanges);
377 for(int ii = 0; ii < d->expressions.count(); ++ii)
378 delete d->expressions.at(ii).expression;
379 for(int ii = 0; ii < d->signalReplacements.count(); ++ii)
380 delete d->signalReplacements.at(ii);
383 QObject *QDeclarativePropertyChanges::object() const
385 Q_D(const QDeclarativePropertyChanges);
389 void QDeclarativePropertyChanges::setObject(QObject *o)
391 Q_D(QDeclarativePropertyChanges);
396 \qmlproperty bool QtQuick2::PropertyChanges::restoreEntryValues
398 This property holds whether the previous values should be restored when
401 The default value is \c true. Setting this value to \c false creates a
402 temporary state that has permanent effects on property values.
404 bool QDeclarativePropertyChanges::restoreEntryValues() const
406 Q_D(const QDeclarativePropertyChanges);
410 void QDeclarativePropertyChanges::setRestoreEntryValues(bool v)
412 Q_D(QDeclarativePropertyChanges);
417 QDeclarativePropertyChangesPrivate::property(const QString &property)
419 Q_Q(QDeclarativePropertyChanges);
420 QDeclarativeProperty prop(object, property, qmlContext(q));
421 if (!prop.isValid()) {
422 qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to non-existent property \"%1\"").arg(property);
423 return QDeclarativeProperty();
424 } else if (!(prop.type() & QDeclarativeProperty::SignalProperty) && !prop.isWritable()) {
425 qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to read-only property \"%1\"").arg(property);
426 return QDeclarativeProperty();
431 QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions()
433 Q_D(QDeclarativePropertyChanges);
439 for (int ii = 0; ii < d->properties.count(); ++ii) {
441 QDeclarativeAction a(d->object, d->properties.at(ii).first,
442 qmlContext(this), d->properties.at(ii).second);
444 if (a.property.isValid()) {
445 a.restore = restoreEntryValues();
450 for (int ii = 0; ii < d->signalReplacements.count(); ++ii) {
452 QDeclarativeReplaceSignalHandler *handler = d->signalReplacements.at(ii);
454 if (handler->property.isValid()) {
455 QDeclarativeAction a;
461 for (int ii = 0; ii < d->expressions.count(); ++ii) {
463 const QString &property = d->expressions.at(ii).name;
464 QDeclarativeProperty prop = d->property(property);
466 if (prop.isValid()) {
467 QDeclarativeAction a;
468 a.restore = restoreEntryValues();
470 a.fromValue = a.property.read();
471 a.specifiedObject = d->object;
472 a.specifiedProperty = property;
475 a.toValue = d->expressions.at(ii).expression->evaluate();
477 QDeclarativeExpression *e = d->expressions.at(ii).expression;
479 QDeclarativeBinding::Identifier id = d->expressions.at(ii).id;
480 QDeclarativeBinding *newBinding = id != QDeclarativeBinding::Invalid ? QDeclarativeBinding::createBinding(id, object(), qmlContext(this), e->sourceFile(), e->lineNumber()) : 0;
482 newBinding = new QDeclarativeBinding(e->expression(), object(), qmlContext(this));
483 newBinding->setSourceLocation(e->sourceFile(), e->lineNumber(), e->columnNumber());
485 newBinding->setTarget(prop);
486 a.toBinding = newBinding;
487 a.deletableToBinding = true;
498 \qmlproperty bool QtQuick2::PropertyChanges::explicit
500 If explicit is set to true, any potential bindings will be interpreted as
501 once-off assignments that occur when the state is entered.
503 In the following example, the addition of explicit prevents \c myItem.width from
504 being bound to \c parent.width. Instead, it is assigned the value of \c parent.width
505 at the time of the state change.
514 By default, explicit is false.
516 bool QDeclarativePropertyChanges::isExplicit() const
518 Q_D(const QDeclarativePropertyChanges);
519 return d->isExplicit;
522 void QDeclarativePropertyChanges::setIsExplicit(bool e)
524 Q_D(QDeclarativePropertyChanges);
528 bool QDeclarativePropertyChanges::containsValue(const QString &name) const
530 Q_D(const QDeclarativePropertyChanges);
531 typedef QPair<QString, QVariant> PropertyEntry;
533 QListIterator<PropertyEntry> propertyIterator(d->properties);
534 while (propertyIterator.hasNext()) {
535 const PropertyEntry &entry = propertyIterator.next();
536 if (entry.first == name) {
544 bool QDeclarativePropertyChanges::containsExpression(const QString &name) const
546 Q_D(const QDeclarativePropertyChanges);
547 typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
549 QListIterator<ExpressionEntry> expressionIterator(d->expressions);
550 while (expressionIterator.hasNext()) {
551 const ExpressionEntry &entry = expressionIterator.next();
552 if (entry.name == name) {
560 bool QDeclarativePropertyChanges::containsProperty(const QString &name) const
562 return containsValue(name) || containsExpression(name);
565 void QDeclarativePropertyChanges::changeValue(const QString &name, const QVariant &value)
567 Q_D(QDeclarativePropertyChanges);
568 typedef QPair<QString, QVariant> PropertyEntry;
569 typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
571 QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
572 while (expressionIterator.hasNext()) {
573 const ExpressionEntry &entry = expressionIterator.next();
574 if (entry.name == name) {
575 expressionIterator.remove();
576 if (state() && state()->isStateActive()) {
577 QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
579 QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
580 oldBinding->destroy();
582 d->property(name).write(value);
585 d->properties.append(PropertyEntry(name, value));
590 QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
591 while (propertyIterator.hasNext()) {
592 PropertyEntry &entry = propertyIterator.next();
593 if (entry.first == name) {
594 entry.second = value;
595 if (state() && state()->isStateActive())
596 d->property(name).write(value);
601 QDeclarativeAction action;
602 action.restore = restoreEntryValues();
603 action.property = d->property(name);
604 action.fromValue = action.property.read();
605 action.specifiedObject = object();
606 action.specifiedProperty = name;
607 action.toValue = value;
609 propertyIterator.insert(PropertyEntry(name, value));
610 if (state() && state()->isStateActive()) {
611 state()->addEntryToRevertList(action);
612 QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property);
614 oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
615 d->property(name).write(value);
619 void QDeclarativePropertyChanges::changeExpression(const QString &name, const QString &expression)
621 Q_D(QDeclarativePropertyChanges);
622 typedef QPair<QString, QVariant> PropertyEntry;
623 typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
625 bool hadValue = false;
627 QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
628 while (propertyIterator.hasNext()) {
629 PropertyEntry &entry = propertyIterator.next();
630 if (entry.first == name) {
631 propertyIterator.remove();
637 QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
638 while (expressionIterator.hasNext()) {
639 const ExpressionEntry &entry = expressionIterator.next();
640 if (entry.name == name) {
641 entry.expression->setExpression(expression);
642 if (state() && state()->isStateActive()) {
643 QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
645 QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
646 oldBinding->destroy();
649 QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this));
650 newBinding->setTarget(d->property(name));
651 QDeclarativePropertyPrivate::setBinding(d->property(name), newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
657 QDeclarativeExpression *newExpression = new QDeclarativeExpression(qmlContext(this), d->object, expression);
658 expressionIterator.insert(ExpressionEntry(name, QDeclarativeBinding::Invalid, newExpression));
660 if (state() && state()->isStateActive()) {
662 QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
664 oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
665 state()->changeBindingInRevertList(object(), name, oldBinding);
668 QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this));
669 newBinding->setTarget(d->property(name));
670 QDeclarativePropertyPrivate::setBinding(d->property(name), newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
672 QDeclarativeAction action;
673 action.restore = restoreEntryValues();
674 action.property = d->property(name);
675 action.fromValue = action.property.read();
676 action.specifiedObject = object();
677 action.specifiedProperty = name;
681 action.toValue = newExpression->evaluate();
683 QDeclarativeBinding *newBinding = new QDeclarativeBinding(newExpression->expression(), object(), qmlContext(this));
684 newBinding->setTarget(d->property(name));
685 action.toBinding = newBinding;
686 action.deletableToBinding = true;
688 state()->addEntryToRevertList(action);
689 QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property);
691 oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
693 QDeclarativePropertyPrivate::setBinding(action.property, newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
697 // what about the signal handler?
700 QVariant QDeclarativePropertyChanges::property(const QString &name) const
702 Q_D(const QDeclarativePropertyChanges);
703 typedef QPair<QString, QVariant> PropertyEntry;
704 typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
706 QListIterator<PropertyEntry> propertyIterator(d->properties);
707 while (propertyIterator.hasNext()) {
708 const PropertyEntry &entry = propertyIterator.next();
709 if (entry.first == name) {
714 QListIterator<ExpressionEntry> expressionIterator(d->expressions);
715 while (expressionIterator.hasNext()) {
716 const ExpressionEntry &entry = expressionIterator.next();
717 if (entry.name == name) {
718 return QVariant(entry.expression->expression());
725 void QDeclarativePropertyChanges::removeProperty(const QString &name)
727 Q_D(QDeclarativePropertyChanges);
728 typedef QPair<QString, QVariant> PropertyEntry;
729 typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
731 QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
732 while (expressionIterator.hasNext()) {
733 const ExpressionEntry &entry = expressionIterator.next();
734 if (entry.name == name) {
735 expressionIterator.remove();
736 state()->removeEntryFromRevertList(object(), name);
741 QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
742 while (propertyIterator.hasNext()) {
743 const PropertyEntry &entry = propertyIterator.next();
744 if (entry.first == name) {
745 propertyIterator.remove();
746 state()->removeEntryFromRevertList(object(), name);
752 QVariant QDeclarativePropertyChanges::value(const QString &name) const
754 Q_D(const QDeclarativePropertyChanges);
755 typedef QPair<QString, QVariant> PropertyEntry;
757 QListIterator<PropertyEntry> propertyIterator(d->properties);
758 while (propertyIterator.hasNext()) {
759 const PropertyEntry &entry = propertyIterator.next();
760 if (entry.first == name) {
768 QString QDeclarativePropertyChanges::expression(const QString &name) const
770 Q_D(const QDeclarativePropertyChanges);
771 typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
773 QListIterator<ExpressionEntry> expressionIterator(d->expressions);
774 while (expressionIterator.hasNext()) {
775 const ExpressionEntry &entry = expressionIterator.next();
776 if (entry.name == name) {
777 return entry.expression->expression();
784 void QDeclarativePropertyChanges::detachFromState()
787 state()->removeAllEntriesFromRevertList(object());
790 void QDeclarativePropertyChanges::attachToState()
793 state()->addEntriesToRevertList(actions());