16293d564969d7b7c8ab428b6808e7fb2a9b9bbf
[profile/ivi/qtdeclarative.git] / src / quick / util / qdeclarativepropertychanges.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qdeclarativepropertychanges_p.h"
43
44 #include <private/qdeclarativeopenmetaobject_p.h>
45 #include <private/qdeclarativerewrite_p.h>
46 #include <private/qdeclarativeengine_p.h>
47
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>
58
59 #include <QtCore/qdebug.h>
60
61 #include <private/qobject_p.h>
62
63 QT_BEGIN_NAMESPACE
64
65 /*!
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.
70
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}.
74
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:
78     
79     \snippet doc/src/snippets/declarative/propertychanges.qml import 
80     \codeline
81     \snippet doc/src/snippets/declarative/propertychanges.qml 0
82
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.
86
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
91     property to \c true.
92    
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:
95
96     \qml
97     PropertyChanges {
98         target: myMouseArea
99         onClicked: doSomethingDifferent()
100     }
101     \endqml
102
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.
106
107
108     \section2 Resetting property values
109
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.
114
115     \snippet doc/src/snippets/declarative/propertychanges.qml reset
116
117
118     \section2 Immediate property changes in transitions
119
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
126     change.
127
128     See the PropertyAction documentation for more details.
129
130     \sa {declarative/animation/states}{states example}, {qmlstate}{States}, QtDeclarative
131 */
132
133 /*!
134     \qmlproperty Object QtQuick2::PropertyChanges::target
135     This property holds the object which contains the properties to be changed.
136 */
137
138 class QDeclarativeReplaceSignalHandler : public QDeclarativeActionEvent
139 {
140 public:
141     QDeclarativeReplaceSignalHandler() : expression(0), reverseExpression(0),
142                                 rewindExpression(0), ownedExpression(0) {}
143     ~QDeclarativeReplaceSignalHandler() {
144         delete ownedExpression;
145     }
146
147     virtual QString typeName() const { return QLatin1String("ReplaceSignalHandler"); }
148
149     QDeclarativeProperty property;
150     QDeclarativeExpression *expression;
151     QDeclarativeExpression *reverseExpression;
152     QDeclarativeExpression *rewindExpression;
153     QDeclarativeGuard<QDeclarativeExpression> ownedExpression;
154
155     virtual void execute(Reason) {
156         ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, expression);
157         if (ownedExpression == expression)
158             ownedExpression = 0;
159     }
160
161     virtual bool isReversable() { return true; }
162     virtual void reverse(Reason) {
163         ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, reverseExpression);
164         if (ownedExpression == reverseExpression)
165             ownedExpression = 0;
166     }
167
168     virtual void saveOriginals() {
169         saveCurrentValues();
170         reverseExpression = rewindExpression;
171     }
172
173     virtual bool needsCopy() { return true; }
174     virtual void copyOriginals(QDeclarativeActionEvent *other)
175     {
176         QDeclarativeReplaceSignalHandler *rsh = static_cast<QDeclarativeReplaceSignalHandler*>(other);
177         saveCurrentValues();
178         if (rsh == this)
179             return;
180         reverseExpression = rsh->reverseExpression;
181         if (rsh->ownedExpression == reverseExpression) {
182             ownedExpression = rsh->ownedExpression;
183             rsh->ownedExpression = 0;
184         }
185     }
186
187     virtual void rewind() {
188         ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, rewindExpression);
189         if (ownedExpression == rewindExpression)
190             ownedExpression = 0;
191     }
192     virtual void saveCurrentValues() { 
193         rewindExpression = QDeclarativePropertyPrivate::signalExpression(property);
194     }
195
196     virtual bool override(QDeclarativeActionEvent*other) {
197         if (other == this)
198             return true;
199         if (other->typeName() != typeName())
200             return false;
201         if (static_cast<QDeclarativeReplaceSignalHandler*>(other)->property == property)
202             return true;
203         return false;
204     }
205 };
206
207
208 class QDeclarativePropertyChangesPrivate : public QDeclarativeStateOperationPrivate
209 {
210     Q_DECLARE_PUBLIC(QDeclarativePropertyChanges)
211 public:
212     QDeclarativePropertyChangesPrivate() : decoded(true), restore(true),
213                                 isExplicit(false) {}
214
215     QDeclarativeGuard<QObject> object;
216     QByteArray data;
217
218     bool decoded : 1;
219     bool restore : 1;
220     bool isExplicit : 1;
221
222     void decode();
223
224     class ExpressionChange {
225     public:
226         ExpressionChange(const QString &_name,
227                          QDeclarativeBinding::Identifier _id,
228                          QDeclarativeExpression *_expr)
229             : name(_name), id(_id), expression(_expr) {}
230         QString name;
231         QDeclarativeBinding::Identifier id;
232         QDeclarativeExpression *expression;
233     };
234
235     QList<QPair<QString, QVariant> > properties;
236     QList<ExpressionChange> expressions;
237     QList<QDeclarativeReplaceSignalHandler*> signalReplacements;
238
239     QDeclarativeProperty property(const QString &);
240 };
241
242 void
243 QDeclarativePropertyChangesParser::compileList(QList<QPair<QString, QVariant> > &list,
244                                      const QString &pre,
245                                      const QDeclarativeCustomParserProperty &prop)
246 {
247     QString propName = pre + prop.name();
248
249     QList<QVariant> values = prop.assignedValues();
250     for (int ii = 0; ii < values.count(); ++ii) {
251         const QVariant &value = values.at(ii);
252
253         if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
254             error(qvariant_cast<QDeclarativeCustomParserNode>(value),
255                   QDeclarativePropertyChanges::tr("PropertyChanges does not support creating state-specific objects."));
256             continue;
257         } else if(value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
258
259             QDeclarativeCustomParserProperty prop =
260                 qvariant_cast<QDeclarativeCustomParserProperty>(value);
261             QString pre = propName + QLatin1Char('.');
262             compileList(list, pre, prop);
263
264         } else {
265             list << qMakePair(propName, value);
266         }
267     }
268 }
269
270 QByteArray
271 QDeclarativePropertyChangesParser::compile(const QList<QDeclarativeCustomParserProperty> &props)
272 {
273     QList<QPair<QString, QVariant> > data;
274     for(int ii = 0; ii < props.count(); ++ii)
275         compileList(data, QString(), props.at(ii));
276
277     QByteArray rv;
278     QDataStream ds(&rv, QIODevice::WriteOnly);
279
280     ds << data.count();
281     for(int ii = 0; ii < data.count(); ++ii) {
282         QDeclarativeScript::Variant v = qvariant_cast<QDeclarativeScript::Variant>(data.at(ii).second);
283         QVariant var;
284         bool isScript = v.isScript();
285         QDeclarativeBinding::Identifier id = 0;
286         switch(v.type()) {
287         case QDeclarativeScript::Variant::Boolean:
288             var = QVariant(v.asBoolean());
289             break;
290         case QDeclarativeScript::Variant::Number:
291             var = QVariant(v.asNumber());
292             break;
293         case QDeclarativeScript::Variant::String:
294             var = QVariant(v.asString());
295             break;
296         case QDeclarativeScript::Variant::Invalid:
297         case QDeclarativeScript::Variant::Script:
298             var = QVariant(v.asScript());
299             {
300                 // Pre-rewrite the expression
301                 id = rewriteBinding(v, data.at(ii).first);
302             }
303             break;
304         }
305
306         ds << data.at(ii).first << isScript << var;
307         if (isScript)
308             ds << id;
309     }
310
311     return rv;
312 }
313
314 void QDeclarativePropertyChangesPrivate::decode()
315 {
316     Q_Q(QDeclarativePropertyChanges);
317     if (decoded)
318         return;
319
320     QDataStream ds(&data, QIODevice::ReadOnly);
321
322     int count;
323     ds >> count;
324     for (int ii = 0; ii < count; ++ii) {
325         QString name;
326         bool isScript;
327         QVariant data;
328         QDeclarativeBinding::Identifier id = QDeclarativeBinding::Invalid;
329         ds >> name;
330         ds >> isScript;
331         ds >> data;
332         if (isScript)
333             ds >> id;
334
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);
351         } else {
352             properties << qMakePair(name, data);
353         }
354     }
355
356     decoded = true;
357     data.clear();
358 }
359
360 void QDeclarativePropertyChangesParser::setCustomData(QObject *object,
361                                             const QByteArray &data)
362 {
363     QDeclarativePropertyChangesPrivate *p =
364         static_cast<QDeclarativePropertyChangesPrivate *>(QObjectPrivate::get(object));
365     p->data = data;
366     p->decoded = false;
367 }
368
369 QDeclarativePropertyChanges::QDeclarativePropertyChanges()
370 : QDeclarativeStateOperation(*(new QDeclarativePropertyChangesPrivate))
371 {
372 }
373
374 QDeclarativePropertyChanges::~QDeclarativePropertyChanges()
375 {
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);
381 }
382
383 QObject *QDeclarativePropertyChanges::object() const
384 {
385     Q_D(const QDeclarativePropertyChanges);
386     return d->object;
387 }
388
389 void QDeclarativePropertyChanges::setObject(QObject *o)
390 {
391     Q_D(QDeclarativePropertyChanges);
392     d->object = o;
393 }
394
395 /*!
396     \qmlproperty bool QtQuick2::PropertyChanges::restoreEntryValues
397
398     This property holds whether the previous values should be restored when
399     leaving the state. 
400
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.
403 */
404 bool QDeclarativePropertyChanges::restoreEntryValues() const
405 {
406     Q_D(const QDeclarativePropertyChanges);
407     return d->restore;
408 }
409
410 void QDeclarativePropertyChanges::setRestoreEntryValues(bool v)
411 {
412     Q_D(QDeclarativePropertyChanges);
413     d->restore = v;
414 }
415
416 QDeclarativeProperty
417 QDeclarativePropertyChangesPrivate::property(const QString &property)
418 {
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();
427     }
428     return prop;
429 }
430
431 QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions()
432 {
433     Q_D(QDeclarativePropertyChanges);
434
435     d->decode();
436
437     ActionList list;
438
439     for (int ii = 0; ii < d->properties.count(); ++ii) {
440
441         QDeclarativeAction a(d->object, d->properties.at(ii).first,
442                  qmlContext(this), d->properties.at(ii).second);
443
444         if (a.property.isValid()) {
445             a.restore = restoreEntryValues();
446             list << a;
447         }
448     }
449
450     for (int ii = 0; ii < d->signalReplacements.count(); ++ii) {
451
452         QDeclarativeReplaceSignalHandler *handler = d->signalReplacements.at(ii);
453
454         if (handler->property.isValid()) {
455             QDeclarativeAction a;
456             a.event = handler;
457             list << a;
458         }
459     }
460
461     for (int ii = 0; ii < d->expressions.count(); ++ii) {
462
463         const QString &property = d->expressions.at(ii).name;
464         QDeclarativeProperty prop = d->property(property);
465
466         if (prop.isValid()) {
467             QDeclarativeAction a;
468             a.restore = restoreEntryValues();
469             a.property = prop;
470             a.fromValue = a.property.read();
471             a.specifiedObject = d->object;
472             a.specifiedProperty = property;
473
474             if (d->isExplicit) {
475                 a.toValue = d->expressions.at(ii).expression->evaluate();
476             } else {
477                 QDeclarativeExpression *e = d->expressions.at(ii).expression;
478
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;
481                 if (!newBinding) {
482                     newBinding = new QDeclarativeBinding(e->expression(), object(), qmlContext(this));
483                     newBinding->setSourceLocation(e->sourceFile(), e->lineNumber(), e->columnNumber());
484                 }
485                 newBinding->setTarget(prop);
486                 a.toBinding = newBinding;
487                 a.deletableToBinding = true;
488             }
489
490             list << a;
491         }
492     }
493
494     return list;
495 }
496
497 /*!
498     \qmlproperty bool QtQuick2::PropertyChanges::explicit
499
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.
502
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.
506     \qml
507     PropertyChanges {
508         target: myItem
509         explicit: true
510         width: parent.width
511     }
512     \endqml
513
514     By default, explicit is false.
515 */
516 bool QDeclarativePropertyChanges::isExplicit() const
517 {
518     Q_D(const QDeclarativePropertyChanges);
519     return d->isExplicit;
520 }
521
522 void QDeclarativePropertyChanges::setIsExplicit(bool e)
523 {
524     Q_D(QDeclarativePropertyChanges);
525     d->isExplicit = e;
526 }
527
528 bool QDeclarativePropertyChanges::containsValue(const QString &name) const
529 {
530     Q_D(const QDeclarativePropertyChanges);
531     typedef QPair<QString, QVariant> PropertyEntry;
532
533     QListIterator<PropertyEntry> propertyIterator(d->properties);
534     while (propertyIterator.hasNext()) {
535         const PropertyEntry &entry = propertyIterator.next();
536         if (entry.first == name) {
537             return true;
538         }
539     }
540
541     return false;
542 }
543
544 bool QDeclarativePropertyChanges::containsExpression(const QString &name) const
545 {
546     Q_D(const QDeclarativePropertyChanges);
547     typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
548
549     QListIterator<ExpressionEntry> expressionIterator(d->expressions);
550     while (expressionIterator.hasNext()) {
551         const ExpressionEntry &entry = expressionIterator.next();
552         if (entry.name == name) {
553             return true;
554         }
555     }
556
557     return false;
558 }
559
560 bool QDeclarativePropertyChanges::containsProperty(const QString &name) const
561 {
562     return containsValue(name) || containsExpression(name);
563 }
564
565 void QDeclarativePropertyChanges::changeValue(const QString &name, const QVariant &value)
566 {
567     Q_D(QDeclarativePropertyChanges);
568     typedef QPair<QString, QVariant> PropertyEntry;
569     typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
570
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));
578                 if (oldBinding) {
579                     QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
580                     oldBinding->destroy();
581                 }
582                 d->property(name).write(value);
583             }
584
585             d->properties.append(PropertyEntry(name, value));
586             return;
587         }
588     }
589
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);
597             return;
598         }
599     }
600
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;
608
609     propertyIterator.insert(PropertyEntry(name, value));
610     if (state() && state()->isStateActive()) {
611         state()->addEntryToRevertList(action);
612         QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property);
613         if (oldBinding)
614             oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
615         d->property(name).write(value);
616     }
617 }
618
619 void QDeclarativePropertyChanges::changeExpression(const QString &name, const QString &expression)
620 {
621     Q_D(QDeclarativePropertyChanges);
622     typedef QPair<QString, QVariant> PropertyEntry;
623     typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
624
625     bool hadValue = false;
626
627     QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
628     while (propertyIterator.hasNext()) {
629         PropertyEntry &entry = propertyIterator.next();
630         if (entry.first == name) {
631             propertyIterator.remove();
632             hadValue = true;
633             break;
634         }
635     }
636
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));
644                 if (oldBinding) {
645                        QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
646                        oldBinding->destroy();
647                 }
648
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);
652             }
653             return;
654         }
655     }
656
657     QDeclarativeExpression *newExpression = new QDeclarativeExpression(qmlContext(this), d->object, expression);
658     expressionIterator.insert(ExpressionEntry(name, QDeclarativeBinding::Invalid, newExpression));
659
660     if (state() && state()->isStateActive()) {
661         if (hadValue) {
662             QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
663             if (oldBinding) {
664                 oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
665                 state()->changeBindingInRevertList(object(), name, oldBinding);
666             }
667
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);
671         } else {
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;
678
679
680             if (d->isExplicit) {
681                 action.toValue = newExpression->evaluate();
682             } else {
683                 QDeclarativeBinding *newBinding = new QDeclarativeBinding(newExpression->expression(), object(), qmlContext(this));
684                 newBinding->setTarget(d->property(name));
685                 action.toBinding = newBinding;
686                 action.deletableToBinding = true;
687
688                 state()->addEntryToRevertList(action);
689                 QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property);
690                 if (oldBinding)
691                     oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
692
693                 QDeclarativePropertyPrivate::setBinding(action.property, newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
694             }
695         }
696     }
697     // what about the signal handler?
698 }
699
700 QVariant QDeclarativePropertyChanges::property(const QString &name) const
701 {
702     Q_D(const QDeclarativePropertyChanges);
703     typedef QPair<QString, QVariant> PropertyEntry;
704     typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
705
706     QListIterator<PropertyEntry> propertyIterator(d->properties);
707     while (propertyIterator.hasNext()) {
708         const PropertyEntry &entry = propertyIterator.next();
709         if (entry.first == name) {
710             return entry.second;
711         }
712     }
713
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());
719         }
720     }
721
722     return QVariant();
723 }
724
725 void QDeclarativePropertyChanges::removeProperty(const QString &name)
726 {
727     Q_D(QDeclarativePropertyChanges);
728     typedef QPair<QString, QVariant> PropertyEntry;
729     typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
730
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);
737             return;
738         }
739     }
740
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);
747             return;
748         }
749     }
750 }
751
752 QVariant QDeclarativePropertyChanges::value(const QString &name) const
753 {
754     Q_D(const QDeclarativePropertyChanges);
755     typedef QPair<QString, QVariant> PropertyEntry;
756
757     QListIterator<PropertyEntry> propertyIterator(d->properties);
758     while (propertyIterator.hasNext()) {
759         const PropertyEntry &entry = propertyIterator.next();
760         if (entry.first == name) {
761             return entry.second;
762         }
763     }
764
765     return QVariant();
766 }
767
768 QString QDeclarativePropertyChanges::expression(const QString &name) const
769 {
770     Q_D(const QDeclarativePropertyChanges);
771     typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
772
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();
778         }
779     }
780
781     return QString();
782 }
783
784 void QDeclarativePropertyChanges::detachFromState()
785 {
786     if (state())
787         state()->removeAllEntriesFromRevertList(object());
788 }
789
790 void QDeclarativePropertyChanges::attachToState()
791 {
792     if (state())
793         state()->addEntriesToRevertList(actions());
794 }
795
796 QT_END_NAMESPACE