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