Initial bundle support
[profile/ivi/qtdeclarative.git] / src / quick / util / qquickpropertychanges.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickpropertychanges_p.h"
43
44 #include <private/qqmlopenmetaobject_p.h>
45 #include <private/qqmlrewrite_p.h>
46 #include <private/qqmlengine_p.h>
47
48 #include <qqmlinfo.h>
49 #include <private/qqmlcustomparser_p.h>
50 #include <private/qqmlscript_p.h>
51 #include <qqmlexpression.h>
52 #include <private/qqmlbinding_p.h>
53 #include <qqmlcontext.h>
54 #include <private/qqmlguard_p.h>
55 #include <private/qqmlproperty_p.h>
56 #include <private/qqmlcontext_p.h>
57 #include <private/qquickstate_p_p.h>
58 #include <private/qqmlboundsignal_p.h>
59
60 #include <QtCore/qdebug.h>
61
62 #include <private/qobject_p.h>
63
64 QT_BEGIN_NAMESPACE
65
66 /*!
67     \qmlclass PropertyChanges QQuickPropertyChanges
68     \inqmlmodule QtQuick 2
69     \ingroup qml-state-elements
70     \brief The PropertyChanges element describes new property bindings or values for a state.
71
72     PropertyChanges is used to define the property values or bindings in a
73     \l State. This enables an item's property values to be changed when it
74     \l {States}{changes between states}.
75
76     To create a PropertyChanges object, specify the \l target item whose
77     properties are to be modified, and define the new property values or
78     bindings. For example:
79
80     \snippet doc/src/snippets/qml/propertychanges.qml import
81     \codeline
82     \snippet doc/src/snippets/qml/propertychanges.qml 0
83
84     When the mouse is pressed, the \l Rectangle changes to the \e resized
85     state. In this state, the PropertyChanges object sets the rectangle's
86     color to blue and the \c height value to that of \c container.height.
87
88     Note this automatically binds \c rect.height to \c container.height
89     in the \e resized state. If a property binding should not be
90     established, and the height should just be set to the value of
91     \c container.height at the time of the state change, set the \l explicit
92     property to \c true.
93
94     A PropertyChanges object can also override the default signal handler
95     for an object to implement a signal handler specific to the new state:
96
97     \qml
98     PropertyChanges {
99         target: myMouseArea
100         onClicked: doSomethingDifferent()
101     }
102     \endqml
103
104     \note PropertyChanges can be used to change anchor margins, but not other anchor
105     values; use AnchorChanges for this instead. Similarly, to change an \l Item's
106     \l {Item::}{parent} value, use ParentChanges instead.
107
108
109     \section2 Resetting property values
110
111     The \c undefined value can be used to reset the property value for a state.
112     In the following example, when \c myText changes to the \e widerText
113     state, its \c width property is reset, giving the text its natural width
114     and displaying the whole string on a single line.
115
116     \snippet doc/src/snippets/qml/propertychanges.qml reset
117
118
119     \section2 Immediate property changes in transitions
120
121     When \l{QML Animation and Transitions}{Transitions} are used to animate
122     state changes, they animate properties from their values in the current
123     state to those defined in the new state (as defined by PropertyChanges
124     objects). However, it is sometimes desirable to set a property value
125     \e immediately during a \l Transition, without animation; in these cases,
126     the PropertyAction element can be used to force an immediate property
127     change.
128
129     See the PropertyAction documentation for more details.
130
131     \sa {declarative/animation/states}{states example}, {qmlstate}{States}, QtQml
132 */
133
134 /*!
135     \qmlproperty Object QtQuick2::PropertyChanges::target
136     This property holds the object which contains the properties to be changed.
137 */
138
139 class QQuickReplaceSignalHandler : public QQuickActionEvent
140 {
141 public:
142     QQuickReplaceSignalHandler() {}
143     ~QQuickReplaceSignalHandler() {}
144
145     virtual EventType type() const { return SignalHandler; }
146
147     QQmlProperty property;
148     QQmlBoundSignalExpressionPointer expression;
149     QQmlBoundSignalExpressionPointer reverseExpression;
150     QQmlBoundSignalExpressionPointer rewindExpression;
151
152     virtual void execute(Reason) {
153         QQmlPropertyPrivate::setSignalExpression(property, expression);
154     }
155
156     virtual bool isReversable() { return true; }
157     virtual void reverse(Reason) {
158         QQmlPropertyPrivate::setSignalExpression(property, reverseExpression);
159     }
160
161     virtual void saveOriginals() {
162         saveCurrentValues();
163         reverseExpression = rewindExpression;
164     }
165
166     virtual bool needsCopy() { return true; }
167     virtual void copyOriginals(QQuickActionEvent *other)
168     {
169         QQuickReplaceSignalHandler *rsh = static_cast<QQuickReplaceSignalHandler*>(other);
170         saveCurrentValues();
171         if (rsh == this)
172             return;
173         reverseExpression = rsh->reverseExpression;
174     }
175
176     virtual void rewind() {
177         QQmlPropertyPrivate::setSignalExpression(property, rewindExpression);
178     }
179     virtual void saveCurrentValues() {
180         rewindExpression = QQmlPropertyPrivate::signalExpression(property);
181     }
182
183     virtual bool override(QQuickActionEvent*other) {
184         if (other == this)
185             return true;
186         if (other->type() != type())
187             return false;
188         if (static_cast<QQuickReplaceSignalHandler*>(other)->property == property)
189             return true;
190         return false;
191     }
192 };
193
194
195 class QQuickPropertyChangesPrivate : public QQuickStateOperationPrivate
196 {
197     Q_DECLARE_PUBLIC(QQuickPropertyChanges)
198 public:
199     QQuickPropertyChangesPrivate() : decoded(true), restore(true),
200                                 isExplicit(false) {}
201
202     QQmlGuard<QObject> object;
203     QByteArray data;
204
205     bool decoded : 1;
206     bool restore : 1;
207     bool isExplicit : 1;
208
209     void decode();
210
211     class ExpressionChange {
212     public:
213         ExpressionChange(const QString &_name,
214                          QQmlBinding::Identifier _id,
215                          const QString& _expr,
216                          const QUrl &_url,
217                          int _line,
218                          int _column)
219             : name(_name), id(_id), expression(_expr), url(_url), line(_line), column(_column) {}
220         QString name;
221         QQmlBinding::Identifier id;
222         QString expression;
223         QUrl url;
224         int line;
225         int column;
226     };
227
228     QList<QPair<QString, QVariant> > properties;
229     QList<ExpressionChange> expressions;
230     QList<QQuickReplaceSignalHandler*> signalReplacements;
231
232     QQmlProperty property(const QString &);
233 };
234
235 void
236 QQuickPropertyChangesParser::compileList(QList<QPair<QString, QVariant> > &list,
237                                      const QString &pre,
238                                      const QQmlCustomParserProperty &prop)
239 {
240     QString propName = pre + prop.name();
241
242     QList<QVariant> values = prop.assignedValues();
243     for (int ii = 0; ii < values.count(); ++ii) {
244         const QVariant &value = values.at(ii);
245
246         if (value.userType() == qMetaTypeId<QQmlCustomParserNode>()) {
247             error(qvariant_cast<QQmlCustomParserNode>(value),
248                   QQuickPropertyChanges::tr("PropertyChanges does not support creating state-specific objects."));
249             continue;
250         } else if(value.userType() == qMetaTypeId<QQmlCustomParserProperty>()) {
251
252             QQmlCustomParserProperty prop =
253                 qvariant_cast<QQmlCustomParserProperty>(value);
254             QString pre = propName + QLatin1Char('.');
255             compileList(list, pre, prop);
256
257         } else {
258             list << qMakePair(propName, value);
259         }
260     }
261 }
262
263 QByteArray
264 QQuickPropertyChangesParser::compile(const QList<QQmlCustomParserProperty> &props)
265 {
266     QList<QPair<QString, QVariant> > data;
267     for(int ii = 0; ii < props.count(); ++ii)
268         compileList(data, QString(), props.at(ii));
269
270     QByteArray rv;
271     QDataStream ds(&rv, QIODevice::WriteOnly);
272
273     ds << data.count();
274     for(int ii = 0; ii < data.count(); ++ii) {
275         QQmlScript::Variant v = qvariant_cast<QQmlScript::Variant>(data.at(ii).second);
276         QVariant var;
277         bool isScript = v.isScript();
278         QQmlBinding::Identifier id = 0;
279         switch(v.type()) {
280         case QQmlScript::Variant::Boolean:
281             var = QVariant(v.asBoolean());
282             break;
283         case QQmlScript::Variant::Number:
284             var = QVariant(v.asNumber());
285             break;
286         case QQmlScript::Variant::String:
287             var = QVariant(v.asString());
288             break;
289         case QQmlScript::Variant::Invalid:
290         case QQmlScript::Variant::Script:
291             var = QVariant(v.asScript());
292             {
293                 // Pre-rewrite the expression
294                 id = rewriteBinding(v, data.at(ii).first);
295             }
296             break;
297         }
298
299         ds << data.at(ii).first << isScript << var;
300         if (isScript)
301             ds << id;
302     }
303
304     return rv;
305 }
306
307 void QQuickPropertyChangesPrivate::decode()
308 {
309     Q_Q(QQuickPropertyChanges);
310     if (decoded)
311         return;
312
313     QDataStream ds(&data, QIODevice::ReadOnly);
314
315     int count;
316     ds >> count;
317     for (int ii = 0; ii < count; ++ii) {
318         QString name;
319         bool isScript;
320         QVariant data;
321         QQmlBinding::Identifier id = QQmlBinding::Invalid;
322         ds >> name;
323         ds >> isScript;
324         ds >> data;
325         if (isScript)
326             ds >> id;
327
328         QQmlProperty prop = property(name);      //### better way to check for signal property?
329         if (prop.type() & QQmlProperty::SignalProperty) {
330             QString expression = data.toString();
331             QUrl url = QUrl();
332             int line = -1;
333             int column = -1;
334
335             QQmlData *ddata = QQmlData::get(q);
336             if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
337                 url = ddata->outerContext->url;
338                 line = ddata->lineNumber;
339                 column = ddata->columnNumber;
340             }
341
342             QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
343             handler->property = prop;
344             handler->expression.take(new QQmlBoundSignalExpression(QQmlContextData::get(qmlContext(q)), object, expression, false, url.toString(), line, column));
345             signalReplacements << handler;
346         } else if (isScript) { // binding
347             QString expression = data.toString();
348             QUrl url = QUrl();
349             int line = -1;
350             int column = -1;
351
352             QQmlData *ddata = QQmlData::get(q);
353             if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty()) {
354                 url = ddata->outerContext->url;
355                 line = ddata->lineNumber;
356                 column = ddata->columnNumber;
357             }
358
359             expressions << ExpressionChange(name, id, expression, url, line, column);
360         } else {
361             properties << qMakePair(name, data);
362         }
363     }
364     decoded = true;
365     data.clear();
366 }
367
368 void QQuickPropertyChangesParser::setCustomData(QObject *object,
369                                             const QByteArray &data)
370 {
371     QQuickPropertyChangesPrivate *p =
372         static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(object));
373     p->data = data;
374     p->decoded = false;
375 }
376
377 QQuickPropertyChanges::QQuickPropertyChanges()
378 : QQuickStateOperation(*(new QQuickPropertyChangesPrivate))
379 {
380 }
381
382 QQuickPropertyChanges::~QQuickPropertyChanges()
383 {
384     Q_D(QQuickPropertyChanges);
385     for(int ii = 0; ii < d->signalReplacements.count(); ++ii)
386         delete d->signalReplacements.at(ii);
387 }
388
389 QObject *QQuickPropertyChanges::object() const
390 {
391     Q_D(const QQuickPropertyChanges);
392     return d->object;
393 }
394
395 void QQuickPropertyChanges::setObject(QObject *o)
396 {
397     Q_D(QQuickPropertyChanges);
398     d->object = o;
399 }
400
401 /*!
402     \qmlproperty bool QtQuick2::PropertyChanges::restoreEntryValues
403
404     This property holds whether the previous values should be restored when
405     leaving the state.
406
407     The default value is \c true. Setting this value to \c false creates a
408     temporary state that has permanent effects on property values.
409 */
410 bool QQuickPropertyChanges::restoreEntryValues() const
411 {
412     Q_D(const QQuickPropertyChanges);
413     return d->restore;
414 }
415
416 void QQuickPropertyChanges::setRestoreEntryValues(bool v)
417 {
418     Q_D(QQuickPropertyChanges);
419     d->restore = v;
420 }
421
422 QQmlProperty
423 QQuickPropertyChangesPrivate::property(const QString &property)
424 {
425     Q_Q(QQuickPropertyChanges);
426     QQmlProperty prop(object, property, qmlContext(q));
427     if (!prop.isValid()) {
428         qmlInfo(q) << QQuickPropertyChanges::tr("Cannot assign to non-existent property \"%1\"").arg(property);
429         return QQmlProperty();
430     } else if (!(prop.type() & QQmlProperty::SignalProperty) && !prop.isWritable()) {
431         qmlInfo(q) << QQuickPropertyChanges::tr("Cannot assign to read-only property \"%1\"").arg(property);
432         return QQmlProperty();
433     }
434     return prop;
435 }
436
437 QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions()
438 {
439     Q_D(QQuickPropertyChanges);
440
441     d->decode();
442
443     ActionList list;
444
445     for (int ii = 0; ii < d->properties.count(); ++ii) {
446
447         QQuickAction a(d->object, d->properties.at(ii).first,
448                  qmlContext(this), d->properties.at(ii).second);
449
450         if (a.property.isValid()) {
451             a.restore = restoreEntryValues();
452             list << a;
453         }
454     }
455
456     for (int ii = 0; ii < d->signalReplacements.count(); ++ii) {
457
458         QQuickReplaceSignalHandler *handler = d->signalReplacements.at(ii);
459
460         if (handler->property.isValid()) {
461             QQuickAction a;
462             a.event = handler;
463             list << a;
464         }
465     }
466
467     for (int ii = 0; ii < d->expressions.count(); ++ii) {
468
469         QQuickPropertyChangesPrivate::ExpressionChange e = d->expressions.at(ii);
470         const QString &property = e.name;
471         QQmlProperty prop = d->property(property);
472
473         if (prop.isValid()) {
474             QQuickAction a;
475             a.restore = restoreEntryValues();
476             a.property = prop;
477             a.fromValue = a.property.read();
478             a.specifiedObject = d->object;
479             a.specifiedProperty = property;
480
481             QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this), e.url.toString(), e.column) : 0;
482             if (!newBinding)
483                 newBinding = new QQmlBinding(e.expression, false, object(), QQmlContextData::get(qmlContext(this)), e.url.toString(), e.line, e.column);
484
485             if (d->isExplicit) {
486                 // in this case, we don't want to assign a binding, per se,
487                 // so we evaluate the expression and assign the result.
488                 // XXX TODO: add a static QQmlJavaScriptExpression::evaluate(QString)
489                 // so that we can avoid creating then destroying the binding in this case.
490                 a.toValue = newBinding->evaluate();
491                 newBinding->destroy();
492             } else {
493                 newBinding->setTarget(prop);
494                 a.toBinding = QQmlAbstractBinding::getPointer(newBinding);
495                 a.deletableToBinding = true;
496             }
497
498             list << a;
499         }
500     }
501
502     return list;
503 }
504
505 /*!
506     \qmlproperty bool QtQuick2::PropertyChanges::explicit
507
508     If explicit is set to true, any potential bindings will be interpreted as
509     once-off assignments that occur when the state is entered.
510
511     In the following example, the addition of explicit prevents \c myItem.width from
512     being bound to \c parent.width. Instead, it is assigned the value of \c parent.width
513     at the time of the state change.
514     \qml
515     PropertyChanges {
516         target: myItem
517         explicit: true
518         width: parent.width
519     }
520     \endqml
521
522     By default, explicit is false.
523 */
524 bool QQuickPropertyChanges::isExplicit() const
525 {
526     Q_D(const QQuickPropertyChanges);
527     return d->isExplicit;
528 }
529
530 void QQuickPropertyChanges::setIsExplicit(bool e)
531 {
532     Q_D(QQuickPropertyChanges);
533     d->isExplicit = e;
534 }
535
536 bool QQuickPropertyChanges::containsValue(const QString &name) const
537 {
538     Q_D(const QQuickPropertyChanges);
539     typedef QPair<QString, QVariant> PropertyEntry;
540
541     QListIterator<PropertyEntry> propertyIterator(d->properties);
542     while (propertyIterator.hasNext()) {
543         const PropertyEntry &entry = propertyIterator.next();
544         if (entry.first == name) {
545             return true;
546         }
547     }
548
549     return false;
550 }
551
552 bool QQuickPropertyChanges::containsExpression(const QString &name) const
553 {
554     Q_D(const QQuickPropertyChanges);
555     typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry;
556
557     QListIterator<ExpressionEntry> expressionIterator(d->expressions);
558     while (expressionIterator.hasNext()) {
559         const ExpressionEntry &entry = expressionIterator.next();
560         if (entry.name == name) {
561             return true;
562         }
563     }
564
565     return false;
566 }
567
568 bool QQuickPropertyChanges::containsProperty(const QString &name) const
569 {
570     return containsValue(name) || containsExpression(name);
571 }
572
573 void QQuickPropertyChanges::changeValue(const QString &name, const QVariant &value)
574 {
575     Q_D(QQuickPropertyChanges);
576     typedef QPair<QString, QVariant> PropertyEntry;
577     typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry;
578
579     QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
580     while (expressionIterator.hasNext()) {
581         const ExpressionEntry &entry = expressionIterator.next();
582         if (entry.name == name) {
583             expressionIterator.remove();
584             if (state() && state()->isStateActive()) {
585                 QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(d->property(name));
586                 if (oldBinding) {
587                     QQmlPropertyPrivate::setBinding(d->property(name), 0);
588                     oldBinding->destroy();
589                 }
590                 d->property(name).write(value);
591             }
592
593             d->properties.append(PropertyEntry(name, value));
594             return;
595         }
596     }
597
598     QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
599     while (propertyIterator.hasNext()) {
600         PropertyEntry &entry = propertyIterator.next();
601         if (entry.first == name) {
602             entry.second = value;
603             if (state() && state()->isStateActive())
604                 d->property(name).write(value);
605             return;
606         }
607     }
608
609     QQuickAction action;
610     action.restore = restoreEntryValues();
611     action.property = d->property(name);
612     action.fromValue = action.property.read();
613     action.specifiedObject = object();
614     action.specifiedProperty = name;
615     action.toValue = value;
616
617     propertyIterator.insert(PropertyEntry(name, value));
618     if (state() && state()->isStateActive()) {
619         state()->addEntryToRevertList(action);
620         QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(action.property);
621         if (oldBinding)
622             oldBinding->setEnabled(false, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
623         d->property(name).write(value);
624     }
625 }
626
627 void QQuickPropertyChanges::changeExpression(const QString &name, const QString &expression)
628 {
629     Q_D(QQuickPropertyChanges);
630     typedef QPair<QString, QVariant> PropertyEntry;
631     typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry;
632
633     bool hadValue = false;
634
635     QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
636     while (propertyIterator.hasNext()) {
637         PropertyEntry &entry = propertyIterator.next();
638         if (entry.first == name) {
639             propertyIterator.remove();
640             hadValue = true;
641             break;
642         }
643     }
644
645     QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
646     while (expressionIterator.hasNext()) {
647         ExpressionEntry &entry = expressionIterator.next();
648         if (entry.name == name) {
649             entry.expression = expression;
650             if (state() && state()->isStateActive()) {
651                 QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(d->property(name));
652                 if (oldBinding) {
653                    QQmlPropertyPrivate::setBinding(d->property(name), 0);
654                    oldBinding->destroy();
655                 }
656
657                 QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this));
658                 newBinding->setTarget(d->property(name));
659                 QQmlPropertyPrivate::setBinding(d->property(name), newBinding, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
660             }
661             return;
662         }
663     }
664
665     // adding a new expression.
666     expressionIterator.insert(ExpressionEntry(name, QQmlBinding::Invalid, expression, QUrl(), -1, -1));
667
668     if (state() && state()->isStateActive()) {
669         if (hadValue) {
670             QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(d->property(name));
671             if (oldBinding) {
672                 oldBinding->setEnabled(false, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
673                 state()->changeBindingInRevertList(object(), name, oldBinding);
674             }
675
676             QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this));
677             newBinding->setTarget(d->property(name));
678             QQmlPropertyPrivate::setBinding(d->property(name), newBinding, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
679         } else {
680             QQuickAction action;
681             action.restore = restoreEntryValues();
682             action.property = d->property(name);
683             action.fromValue = action.property.read();
684             action.specifiedObject = object();
685             action.specifiedProperty = name;
686
687             QQmlBinding *newBinding = new QQmlBinding(expression, object(), qmlContext(this));
688             if (d->isExplicit) {
689                 // don't assign the binding, merely evaluate the expression.
690                 // XXX TODO: add a static QQmlJavaScriptExpression::evaluate(QString)
691                 // so that we can avoid creating then destroying the binding in this case.
692                 action.toValue = newBinding->evaluate();
693                 newBinding->destroy();
694             } else {
695                 newBinding->setTarget(d->property(name));
696                 action.toBinding = QQmlAbstractBinding::getPointer(newBinding);
697                 action.deletableToBinding = true;
698
699                 state()->addEntryToRevertList(action);
700                 QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(action.property);
701                 if (oldBinding)
702                     oldBinding->setEnabled(false, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
703
704                 QQmlPropertyPrivate::setBinding(action.property, newBinding, QQmlPropertyPrivate::DontRemoveBinding | QQmlPropertyPrivate::BypassInterceptor);
705             }
706         }
707     }
708     // what about the signal handler?
709 }
710
711 QVariant QQuickPropertyChanges::property(const QString &name) const
712 {
713     Q_D(const QQuickPropertyChanges);
714     typedef QPair<QString, QVariant> PropertyEntry;
715     typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry;
716
717     QListIterator<PropertyEntry> propertyIterator(d->properties);
718     while (propertyIterator.hasNext()) {
719         const PropertyEntry &entry = propertyIterator.next();
720         if (entry.first == name) {
721             return entry.second;
722         }
723     }
724
725     QListIterator<ExpressionEntry> expressionIterator(d->expressions);
726     while (expressionIterator.hasNext()) {
727         const ExpressionEntry &entry = expressionIterator.next();
728         if (entry.name == name) {
729             return QVariant(entry.expression);
730         }
731     }
732
733     return QVariant();
734 }
735
736 void QQuickPropertyChanges::removeProperty(const QString &name)
737 {
738     Q_D(QQuickPropertyChanges);
739     typedef QPair<QString, QVariant> PropertyEntry;
740     typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry;
741
742     QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
743     while (expressionIterator.hasNext()) {
744         const ExpressionEntry &entry = expressionIterator.next();
745         if (entry.name == name) {
746             expressionIterator.remove();
747             state()->removeEntryFromRevertList(object(), name);
748             return;
749         }
750     }
751
752     QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
753     while (propertyIterator.hasNext()) {
754         const PropertyEntry &entry = propertyIterator.next();
755         if (entry.first == name) {
756             propertyIterator.remove();
757             state()->removeEntryFromRevertList(object(), name);
758             return;
759         }
760     }
761 }
762
763 QVariant QQuickPropertyChanges::value(const QString &name) const
764 {
765     Q_D(const QQuickPropertyChanges);
766     typedef QPair<QString, QVariant> PropertyEntry;
767
768     QListIterator<PropertyEntry> propertyIterator(d->properties);
769     while (propertyIterator.hasNext()) {
770         const PropertyEntry &entry = propertyIterator.next();
771         if (entry.first == name) {
772             return entry.second;
773         }
774     }
775
776     return QVariant();
777 }
778
779 QString QQuickPropertyChanges::expression(const QString &name) const
780 {
781     Q_D(const QQuickPropertyChanges);
782     typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry;
783
784     QListIterator<ExpressionEntry> expressionIterator(d->expressions);
785     while (expressionIterator.hasNext()) {
786         const ExpressionEntry &entry = expressionIterator.next();
787         if (entry.name == name) {
788             return entry.expression;
789         }
790     }
791
792     return QString();
793 }
794
795 void QQuickPropertyChanges::detachFromState()
796 {
797     if (state())
798         state()->removeAllEntriesFromRevertList(object());
799 }
800
801 void QQuickPropertyChanges::attachToState()
802 {
803     if (state())
804         state()->addEntriesToRevertList(actions());
805 }
806
807 QT_END_NAMESPACE