Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / util / qdeclarativepropertychanges.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativepropertychanges_p.h"
43
44 #include "private/qdeclarativeopenmetaobject_p.h"
45 #include "private/qdeclarativerewrite_p.h"
46 #include "private/qdeclarativeengine_p.h"
47 #include "private/qdeclarativecompiler_p.h"
48
49 #include <qdeclarativeinfo.h>
50 #include <qdeclarativecustomparser_p.h>
51 #include <qdeclarativeparser_p.h>
52 #include <qdeclarativeexpression.h>
53 #include <qdeclarativebinding_p.h>
54 #include <qdeclarativecontext.h>
55 #include <qdeclarativeguard_p.h>
56 #include <qdeclarativeproperty_p.h>
57 #include <qdeclarativecontext_p.h>
58 #include <qdeclarativestate_p_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 QDeclarativePropertyChanges
68     \ingroup qml-state-elements
69     \since 4.7
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 {QML 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/declarative/propertychanges.qml import 
81     \codeline
82     \snippet doc/src/snippets/declarative/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 theText 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/declarative/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}, QtDeclarative
132 */
133
134 /*!
135     \qmlproperty Object PropertyChanges::target
136     This property holds the object which contains the properties to be changed.
137 */
138
139 class QDeclarativeReplaceSignalHandler : public QDeclarativeActionEvent
140 {
141 public:
142     QDeclarativeReplaceSignalHandler() : expression(0), reverseExpression(0),
143                                 rewindExpression(0), ownedExpression(0) {}
144     ~QDeclarativeReplaceSignalHandler() {
145         delete ownedExpression;
146     }
147
148     virtual QString typeName() const { return QLatin1String("ReplaceSignalHandler"); }
149
150     QDeclarativeProperty property;
151     QDeclarativeExpression *expression;
152     QDeclarativeExpression *reverseExpression;
153     QDeclarativeExpression *rewindExpression;
154     QDeclarativeGuard<QDeclarativeExpression> ownedExpression;
155
156     virtual void execute(Reason) {
157         ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, expression);
158         if (ownedExpression == expression)
159             ownedExpression = 0;
160     }
161
162     virtual bool isReversable() { return true; }
163     virtual void reverse(Reason) {
164         ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, reverseExpression);
165         if (ownedExpression == reverseExpression)
166             ownedExpression = 0;
167     }
168
169     virtual void saveOriginals() {
170         saveCurrentValues();
171         reverseExpression = rewindExpression;
172     }
173
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<QByteArray, QVariant> > &list,
244                                      const QByteArray &pre,
245                                      const QDeclarativeCustomParserProperty &prop)
246 {
247     QByteArray 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             QByteArray pre = propName + '.';
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<QByteArray, QVariant> > data;
274     for(int ii = 0; ii < props.count(); ++ii)
275         compileList(data, QByteArray(), 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         QDeclarativeParser::Variant v = qvariant_cast<QDeclarativeParser::Variant>(data.at(ii).second);
283         QVariant var;
284         bool isScript = v.isScript();
285         QDeclarativeBinding::Identifier id = 0;
286         switch(v.type()) {
287         case QDeclarativeParser::Variant::Boolean:
288             var = QVariant(v.asBoolean());
289             break;
290         case QDeclarativeParser::Variant::Number:
291             var = QVariant(v.asNumber());
292             break;
293         case QDeclarativeParser::Variant::String:
294             var = QVariant(v.asString());
295             break;
296         case QDeclarativeParser::Variant::Invalid:
297         case QDeclarativeParser::Variant::Script:
298             var = QVariant(v.asScript());
299             {
300                 // Pre-rewrite the expression
301                 QString expression = v.asScript();
302                 id = rewriteBinding(expression, data.at(ii).first); //### recreates the AST, which is slow
303             }
304             break;
305         }
306
307         ds << QString::fromUtf8(data.at(ii).first) << isScript << var;
308         if (isScript)
309             ds << id;
310     }
311
312     return rv;
313 }
314
315 void QDeclarativePropertyChangesPrivate::decode()
316 {
317     Q_Q(QDeclarativePropertyChanges);
318     if (decoded)
319         return;
320
321     QDataStream ds(&data, QIODevice::ReadOnly);
322
323     int count;
324     ds >> count;
325     for (int ii = 0; ii < count; ++ii) {
326         QString name;
327         bool isScript;
328         QVariant data;
329         QDeclarativeBinding::Identifier id = QDeclarativeBinding::Invalid;
330         ds >> name;
331         ds >> isScript;
332         ds >> data;
333         if (isScript)
334             ds >> id;
335
336         QDeclarativeProperty prop = property(name);      //### better way to check for signal property?
337         if (prop.type() & QDeclarativeProperty::SignalProperty) {
338             QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(q), object, data.toString());
339             QDeclarativeData *ddata = QDeclarativeData::get(q);
340             if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
341                 expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
342             QDeclarativeReplaceSignalHandler *handler = new QDeclarativeReplaceSignalHandler;
343             handler->property = prop;
344             handler->expression = expression;
345             signalReplacements << handler;
346         } else if (isScript) {
347             QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(q), object, data.toString());
348             QDeclarativeData *ddata = QDeclarativeData::get(q);
349             if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
350                 expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
351             expressions << ExpressionChange(name, id, expression);
352         } else {
353             properties << qMakePair(name, data);
354         }
355     }
356
357     decoded = true;
358     data.clear();
359 }
360
361 void QDeclarativePropertyChangesParser::setCustomData(QObject *object,
362                                             const QByteArray &data)
363 {
364     QDeclarativePropertyChangesPrivate *p =
365         static_cast<QDeclarativePropertyChangesPrivate *>(QObjectPrivate::get(object));
366     p->data = data;
367     p->decoded = false;
368 }
369
370 QDeclarativePropertyChanges::QDeclarativePropertyChanges()
371 : QDeclarativeStateOperation(*(new QDeclarativePropertyChangesPrivate))
372 {
373 }
374
375 QDeclarativePropertyChanges::~QDeclarativePropertyChanges()
376 {
377     Q_D(QDeclarativePropertyChanges);
378     for(int ii = 0; ii < d->expressions.count(); ++ii)
379         delete d->expressions.at(ii).expression;
380     for(int ii = 0; ii < d->signalReplacements.count(); ++ii)
381         delete d->signalReplacements.at(ii);
382 }
383
384 QObject *QDeclarativePropertyChanges::object() const
385 {
386     Q_D(const QDeclarativePropertyChanges);
387     return d->object;
388 }
389
390 void QDeclarativePropertyChanges::setObject(QObject *o)
391 {
392     Q_D(QDeclarativePropertyChanges);
393     d->object = o;
394 }
395
396 /*!
397     \qmlproperty bool PropertyChanges::restoreEntryValues
398
399     This property holds whether the previous values should be restored when
400     leaving the state. 
401
402     The default value is \c true. Setting this value to \c false creates a
403     temporary state that has permanent effects on property values.
404 */
405 bool QDeclarativePropertyChanges::restoreEntryValues() const
406 {
407     Q_D(const QDeclarativePropertyChanges);
408     return d->restore;
409 }
410
411 void QDeclarativePropertyChanges::setRestoreEntryValues(bool v)
412 {
413     Q_D(QDeclarativePropertyChanges);
414     d->restore = v;
415 }
416
417 QDeclarativeProperty
418 QDeclarativePropertyChangesPrivate::property(const QString &property)
419 {
420     Q_Q(QDeclarativePropertyChanges);
421     QDeclarativeProperty prop(object, property, qmlContext(q));
422     if (!prop.isValid()) {
423         qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to non-existent property \"%1\"").arg(property);
424         return QDeclarativeProperty();
425     } else if (!(prop.type() & QDeclarativeProperty::SignalProperty) && !prop.isWritable()) {
426         qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to read-only property \"%1\"").arg(property);
427         return QDeclarativeProperty();
428     }
429     return prop;
430 }
431
432 QDeclarativePropertyChanges::ActionList QDeclarativePropertyChanges::actions()
433 {
434     Q_D(QDeclarativePropertyChanges);
435
436     d->decode();
437
438     ActionList list;
439
440     for (int ii = 0; ii < d->properties.count(); ++ii) {
441
442         QDeclarativeAction a(d->object, d->properties.at(ii).first,
443                  qmlContext(this), d->properties.at(ii).second);
444
445         if (a.property.isValid()) {
446             a.restore = restoreEntryValues();
447             list << a;
448         }
449     }
450
451     for (int ii = 0; ii < d->signalReplacements.count(); ++ii) {
452
453         QDeclarativeReplaceSignalHandler *handler = d->signalReplacements.at(ii);
454
455         if (handler->property.isValid()) {
456             QDeclarativeAction a;
457             a.event = handler;
458             list << a;
459         }
460     }
461
462     for (int ii = 0; ii < d->expressions.count(); ++ii) {
463
464         const QString &property = d->expressions.at(ii).name;
465         QDeclarativeProperty prop = d->property(property);
466
467         if (prop.isValid()) {
468             QDeclarativeAction a;
469             a.restore = restoreEntryValues();
470             a.property = prop;
471             a.fromValue = a.property.read();
472             a.specifiedObject = d->object;
473             a.specifiedProperty = property;
474
475             if (d->isExplicit) {
476                 a.toValue = d->expressions.at(ii).expression->evaluate();
477             } else {
478                 QDeclarativeExpression *e = d->expressions.at(ii).expression;
479
480                 QDeclarativeBinding::Identifier id = d->expressions.at(ii).id;
481                 QDeclarativeBinding *newBinding = id != QDeclarativeBinding::Invalid ? QDeclarativeBinding::createBinding(id, object(), qmlContext(this), e->sourceFile(), e->lineNumber()) : 0;
482                 if (!newBinding) {
483                     newBinding = new QDeclarativeBinding(e->expression(), object(), qmlContext(this));
484                     newBinding->setSourceLocation(e->sourceFile(), e->lineNumber());
485                 }
486                 newBinding->setTarget(prop);
487                 a.toBinding = newBinding;
488                 a.deletableToBinding = true;
489             }
490
491             list << a;
492         }
493     }
494
495     return list;
496 }
497
498 /*!
499     \qmlproperty bool PropertyChanges::explicit
500
501     If explicit is set to true, any potential bindings will be interpreted as
502     once-off assignments that occur when the state is entered.
503
504     In the following example, the addition of explicit prevents \c myItem.width from
505     being bound to \c parent.width. Instead, it is assigned the value of \c parent.width
506     at the time of the state change.
507     \qml
508     PropertyChanges {
509         target: myItem
510         explicit: true
511         width: parent.width
512     }
513     \endqml
514
515     By default, explicit is false.
516 */
517 bool QDeclarativePropertyChanges::isExplicit() const
518 {
519     Q_D(const QDeclarativePropertyChanges);
520     return d->isExplicit;
521 }
522
523 void QDeclarativePropertyChanges::setIsExplicit(bool e)
524 {
525     Q_D(QDeclarativePropertyChanges);
526     d->isExplicit = e;
527 }
528
529 bool QDeclarativePropertyChanges::containsValue(const QString &name) const
530 {
531     Q_D(const QDeclarativePropertyChanges);
532     typedef QPair<QString, QVariant> PropertyEntry;
533
534     QListIterator<PropertyEntry> propertyIterator(d->properties);
535     while (propertyIterator.hasNext()) {
536         const PropertyEntry &entry = propertyIterator.next();
537         if (entry.first == name) {
538             return true;
539         }
540     }
541
542     return false;
543 }
544
545 bool QDeclarativePropertyChanges::containsExpression(const QString &name) const
546 {
547     Q_D(const QDeclarativePropertyChanges);
548     typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
549
550     QListIterator<ExpressionEntry> expressionIterator(d->expressions);
551     while (expressionIterator.hasNext()) {
552         const ExpressionEntry &entry = expressionIterator.next();
553         if (entry.name == name) {
554             return true;
555         }
556     }
557
558     return false;
559 }
560
561 bool QDeclarativePropertyChanges::containsProperty(const QString &name) const
562 {
563     return containsValue(name) || containsExpression(name);
564 }
565
566 void QDeclarativePropertyChanges::changeValue(const QString &name, const QVariant &value)
567 {
568     Q_D(QDeclarativePropertyChanges);
569     typedef QPair<QString, QVariant> PropertyEntry;
570     typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
571
572     QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
573     while (expressionIterator.hasNext()) {
574         const ExpressionEntry &entry = expressionIterator.next();
575         if (entry.name == name) {
576             expressionIterator.remove();
577             if (state() && state()->isStateActive()) {
578                 QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
579                 if (oldBinding) {
580                     QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
581                     oldBinding->destroy();
582                 }
583                 d->property(name).write(value);
584             }
585
586             d->properties.append(PropertyEntry(name, value));
587             return;
588         }
589     }
590
591     QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
592     while (propertyIterator.hasNext()) {
593         PropertyEntry &entry = propertyIterator.next();
594         if (entry.first == name) {
595             entry.second = value;
596             if (state() && state()->isStateActive())
597                 d->property(name).write(value);
598             return;
599         }
600     }
601
602     QDeclarativeAction action;
603     action.restore = restoreEntryValues();
604     action.property = d->property(name);
605     action.fromValue = action.property.read();
606     action.specifiedObject = object();
607     action.specifiedProperty = name;
608     action.toValue = value;
609
610     propertyIterator.insert(PropertyEntry(name, value));
611     if (state() && state()->isStateActive()) {
612         state()->addEntryToRevertList(action);
613         QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property);
614         if (oldBinding)
615             oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
616         d->property(name).write(value);
617     }
618 }
619
620 void QDeclarativePropertyChanges::changeExpression(const QString &name, const QString &expression)
621 {
622     Q_D(QDeclarativePropertyChanges);
623     typedef QPair<QString, QVariant> PropertyEntry;
624     typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
625
626     bool hadValue = false;
627
628     QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
629     while (propertyIterator.hasNext()) {
630         PropertyEntry &entry = propertyIterator.next();
631         if (entry.first == name) {
632             propertyIterator.remove();
633             hadValue = true;
634             break;
635         }
636     }
637
638     QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
639     while (expressionIterator.hasNext()) {
640         const ExpressionEntry &entry = expressionIterator.next();
641         if (entry.name == name) {
642             entry.expression->setExpression(expression);
643             if (state() && state()->isStateActive()) {
644                 QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
645                 if (oldBinding) {
646                        QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
647                        oldBinding->destroy();
648                 }
649
650                 QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this));
651                 newBinding->setTarget(d->property(name));
652                 QDeclarativePropertyPrivate::setBinding(d->property(name), newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
653             }
654             return;
655         }
656     }
657
658     QDeclarativeExpression *newExpression = new QDeclarativeExpression(qmlContext(this), d->object, expression);
659     expressionIterator.insert(ExpressionEntry(name, QDeclarativeBinding::Invalid, newExpression));
660
661     if (state() && state()->isStateActive()) {
662         if (hadValue) {
663             QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(d->property(name));
664             if (oldBinding) {
665                 oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
666                 state()->changeBindingInRevertList(object(), name, oldBinding);
667             }
668
669             QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this));
670             newBinding->setTarget(d->property(name));
671             QDeclarativePropertyPrivate::setBinding(d->property(name), newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
672         } else {
673             QDeclarativeAction action;
674             action.restore = restoreEntryValues();
675             action.property = d->property(name);
676             action.fromValue = action.property.read();
677             action.specifiedObject = object();
678             action.specifiedProperty = name;
679
680
681             if (d->isExplicit) {
682                 action.toValue = newExpression->evaluate();
683             } else {
684                 QDeclarativeBinding *newBinding = new QDeclarativeBinding(newExpression->expression(), object(), qmlContext(this));
685                 newBinding->setTarget(d->property(name));
686                 action.toBinding = newBinding;
687                 action.deletableToBinding = true;
688
689                 state()->addEntryToRevertList(action);
690                 QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(action.property);
691                 if (oldBinding)
692                     oldBinding->setEnabled(false, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
693
694                 QDeclarativePropertyPrivate::setBinding(action.property, newBinding, QDeclarativePropertyPrivate::DontRemoveBinding | QDeclarativePropertyPrivate::BypassInterceptor);
695             }
696         }
697     }
698     // what about the signal handler?
699 }
700
701 QVariant QDeclarativePropertyChanges::property(const QString &name) const
702 {
703     Q_D(const QDeclarativePropertyChanges);
704     typedef QPair<QString, QVariant> PropertyEntry;
705     typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
706
707     QListIterator<PropertyEntry> propertyIterator(d->properties);
708     while (propertyIterator.hasNext()) {
709         const PropertyEntry &entry = propertyIterator.next();
710         if (entry.first == name) {
711             return entry.second;
712         }
713     }
714
715     QListIterator<ExpressionEntry> expressionIterator(d->expressions);
716     while (expressionIterator.hasNext()) {
717         const ExpressionEntry &entry = expressionIterator.next();
718         if (entry.name == name) {
719             return QVariant(entry.expression->expression());
720         }
721     }
722
723     return QVariant();
724 }
725
726 void QDeclarativePropertyChanges::removeProperty(const QString &name)
727 {
728     Q_D(QDeclarativePropertyChanges);
729     typedef QPair<QString, QVariant> PropertyEntry;
730     typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
731
732     QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
733     while (expressionIterator.hasNext()) {
734         const ExpressionEntry &entry = expressionIterator.next();
735         if (entry.name == name) {
736             expressionIterator.remove();
737             state()->removeEntryFromRevertList(object(), name);
738             return;
739         }
740     }
741
742     QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
743     while (propertyIterator.hasNext()) {
744         const PropertyEntry &entry = propertyIterator.next();
745         if (entry.first == name) {
746             propertyIterator.remove();
747             state()->removeEntryFromRevertList(object(), name);
748             return;
749         }
750     }
751 }
752
753 QVariant QDeclarativePropertyChanges::value(const QString &name) const
754 {
755     Q_D(const QDeclarativePropertyChanges);
756     typedef QPair<QString, QVariant> PropertyEntry;
757
758     QListIterator<PropertyEntry> propertyIterator(d->properties);
759     while (propertyIterator.hasNext()) {
760         const PropertyEntry &entry = propertyIterator.next();
761         if (entry.first == name) {
762             return entry.second;
763         }
764     }
765
766     return QVariant();
767 }
768
769 QString QDeclarativePropertyChanges::expression(const QString &name) const
770 {
771     Q_D(const QDeclarativePropertyChanges);
772     typedef QDeclarativePropertyChangesPrivate::ExpressionChange ExpressionEntry;
773
774     QListIterator<ExpressionEntry> expressionIterator(d->expressions);
775     while (expressionIterator.hasNext()) {
776         const ExpressionEntry &entry = expressionIterator.next();
777         if (entry.name == name) {
778             return entry.expression->expression();
779         }
780     }
781
782     return QString();
783 }
784
785 void QDeclarativePropertyChanges::detachFromState()
786 {
787     if (state())
788         state()->removeAllEntriesFromRevertList(object());
789 }
790
791 void QDeclarativePropertyChanges::attachToState()
792 {
793     if (state())
794         state()->addEntriesToRevertList(actions());
795 }
796
797 QT_END_NAMESPACE