Qt 4.8
qdeclarativepropertychanges.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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>
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 
65 
146 {
147 public:
151  delete ownedExpression;
152  }
153 
154  virtual QString typeName() const { return QLatin1String("ReplaceSignalHandler"); }
155 
161 
162  virtual void execute(Reason) {
163  ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, expression);
164  if (ownedExpression == expression)
165  ownedExpression = 0;
166  }
167 
168  virtual bool isReversable() { return true; }
169  virtual void reverse(Reason) {
170  ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, reverseExpression);
171  if (ownedExpression == reverseExpression)
172  ownedExpression = 0;
173  }
174 
175  virtual void saveOriginals() {
177  reverseExpression = rewindExpression;
178  }
179 
180  virtual bool needsCopy() { return true; }
182  {
185  if (rsh == this)
186  return;
187  reverseExpression = rsh->reverseExpression;
188  if (rsh->ownedExpression == reverseExpression) {
189  ownedExpression = rsh->ownedExpression;
190  rsh->ownedExpression = 0;
191  }
192  }
193 
194  virtual void rewind() {
195  ownedExpression = QDeclarativePropertyPrivate::setSignalExpression(property, rewindExpression);
196  if (ownedExpression == rewindExpression)
197  ownedExpression = 0;
198  }
199  virtual void saveCurrentValues() {
200  rewindExpression = QDeclarativePropertyPrivate::signalExpression(property);
201  }
202 
203  virtual bool override(QDeclarativeActionEvent*other) {
204  if (other == this)
205  return true;
206  if (other->typeName() != typeName())
207  return false;
208  if (static_cast<QDeclarativeReplaceSignalHandler*>(other)->property == property)
209  return true;
210  return false;
211  }
212 };
213 
214 
216 {
218 public:
219  QDeclarativePropertyChangesPrivate() : decoded(true), restore(true),
220  isExplicit(false) {}
221 
224 
225  bool decoded : 1;
226  bool restore : 1;
227  bool isExplicit : 1;
228 
229  void decode();
230 
232  public:
233  ExpressionChange(const QString &_name,
235  QDeclarativeExpression *_expr)
236  : name(_name), id(_id), expression(_expr) {}
240  };
241 
245 
247 };
248 
249 void
251  const QByteArray &pre,
253 {
254  QByteArray propName = pre + prop.name();
255 
257  for (int ii = 0; ii < values.count(); ++ii) {
258  const QVariant &value = values.at(ii);
259 
260  if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) {
261  error(qvariant_cast<QDeclarativeCustomParserNode>(value),
262  QDeclarativePropertyChanges::tr("PropertyChanges does not support creating state-specific objects."));
263  continue;
264  } else if(value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) {
265 
268  QByteArray pre = propName + '.';
269  compileList(list, pre, prop);
270 
271  } else {
272  list << qMakePair(propName, value);
273  }
274  }
275 }
276 
279 {
281  for(int ii = 0; ii < props.count(); ++ii)
282  compileList(data, QByteArray(), props.at(ii));
283 
284  QByteArray rv;
286 
287  ds << data.count();
288  for(int ii = 0; ii < data.count(); ++ii) {
290  QVariant var;
291  bool isScript = v.isScript();
293  switch(v.type()) {
295  var = QVariant(v.asBoolean());
296  break;
298  var = QVariant(v.asNumber());
299  break;
301  var = QVariant(v.asString());
302  break;
305  var = QVariant(v.asScript());
306  {
307  // Pre-rewrite the expression
309  id = rewriteBinding(expression, data.at(ii).first); //### recreates the AST, which is slow
310  }
311  break;
312  }
313 
314  ds << QString::fromUtf8(data.at(ii).first) << isScript << var;
315  if (isScript)
316  ds << id;
317  }
318 
319  return rv;
320 }
321 
323 {
325  if (decoded)
326  return;
327 
329 
330  int count;
331  ds >> count;
332  for (int ii = 0; ii < count; ++ii) {
333  QString name;
334  bool isScript;
335  QVariant data;
337  ds >> name;
338  ds >> isScript;
339  ds >> data;
340  if (isScript)
341  ds >> id;
342 
343  QDeclarativeProperty prop = property(name); //### better way to check for signal property?
345  QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(q), object, data.toString());
347  if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
348  expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
350  handler->property = prop;
351  handler->expression = expression;
352  signalReplacements << handler;
353  } else if (isScript) {
354  QDeclarativeExpression *expression = new QDeclarativeExpression(qmlContext(q), object, data.toString());
356  if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
357  expression->setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
358  expressions << ExpressionChange(name, id, expression);
359  } else {
360  properties << qMakePair(name, data);
361  }
362  }
363 
364  decoded = true;
365  data.clear();
366 }
367 
369  const QByteArray &data)
370 {
373  p->data = data;
374  p->decoded = false;
375 }
376 
379 {
380 }
381 
383 {
385  for(int ii = 0; ii < d->expressions.count(); ++ii)
386  delete d->expressions.at(ii).expression;
387  for(int ii = 0; ii < d->signalReplacements.count(); ++ii)
388  delete d->signalReplacements.at(ii);
389 }
390 
392 {
394  return d->object;
395 }
396 
398 {
400  d->object = o;
401 }
402 
416 {
418  return d->restore;
419 }
420 
422 {
424  d->restore = v;
425 }
426 
429 {
431  QDeclarativeProperty prop(object, property, qmlContext(q));
432  if (!prop.isValid()) {
433  qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to non-existent property \"%1\"").arg(property);
434  return QDeclarativeProperty();
435  } else if (!(prop.type() & QDeclarativeProperty::SignalProperty) && !prop.isWritable()) {
436  qmlInfo(q) << QDeclarativePropertyChanges::tr("Cannot assign to read-only property \"%1\"").arg(property);
437  return QDeclarativeProperty();
438  }
439  return prop;
440 }
441 
443 {
445 
446  d->decode();
447 
448  ActionList list;
449 
450  for (int ii = 0; ii < d->properties.count(); ++ii) {
451 
452  QDeclarativeAction a(d->object, d->properties.at(ii).first,
453  qmlContext(this), d->properties.at(ii).second);
454 
455  if (a.property.isValid()) {
456  a.restore = restoreEntryValues();
457  list << a;
458  }
459  }
460 
461  for (int ii = 0; ii < d->signalReplacements.count(); ++ii) {
462 
463  QDeclarativeReplaceSignalHandler *handler = d->signalReplacements.at(ii);
464 
465  if (handler->property.isValid()) {
467  a.event = handler;
468  list << a;
469  }
470  }
471 
472  for (int ii = 0; ii < d->expressions.count(); ++ii) {
473 
474  const QString &property = d->expressions.at(ii).name;
475  QDeclarativeProperty prop = d->property(property);
476 
477  if (prop.isValid()) {
480  a.property = prop;
481  a.fromValue = a.property.read();
482  a.specifiedObject = d->object;
484 
485  if (d->isExplicit) {
486  a.toValue = d->expressions.at(ii).expression->evaluate();
487  } else {
488  QDeclarativeExpression *e = d->expressions.at(ii).expression;
489 
490  QDeclarativeBinding::Identifier id = d->expressions.at(ii).id;
492  if (!newBinding) {
493  newBinding = new QDeclarativeBinding(e->expression(), object(), qmlContext(this));
494  newBinding->setSourceLocation(e->sourceFile(), e->lineNumber());
495  }
496  newBinding->setTarget(prop);
497  a.toBinding = newBinding;
498  a.deletableToBinding = true;
499  }
500 
501  list << a;
502  }
503  }
504 
505  return list;
506 }
507 
531 {
533  return d->isExplicit;
534 }
535 
537 {
539  d->isExplicit = e;
540 }
541 
543 {
545  typedef QPair<QString, QVariant> PropertyEntry;
546 
547  QListIterator<PropertyEntry> propertyIterator(d->properties);
548  while (propertyIterator.hasNext()) {
549  const PropertyEntry &entry = propertyIterator.next();
550  if (entry.first == name) {
551  return true;
552  }
553  }
554 
555  return false;
556 }
557 
559 {
562 
563  QListIterator<ExpressionEntry> expressionIterator(d->expressions);
564  while (expressionIterator.hasNext()) {
565  const ExpressionEntry &entry = expressionIterator.next();
566  if (entry.name == name) {
567  return true;
568  }
569  }
570 
571  return false;
572 }
573 
575 {
576  return containsValue(name) || containsExpression(name);
577 }
578 
580 {
582  typedef QPair<QString, QVariant> PropertyEntry;
584 
585  QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
586  while (expressionIterator.hasNext()) {
587  const ExpressionEntry &entry = expressionIterator.next();
588  if (entry.name == name) {
589  expressionIterator.remove();
590  if (state() && state()->isStateActive()) {
592  if (oldBinding) {
593  QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
594  oldBinding->destroy();
595  }
596  d->property(name).write(value);
597  }
598 
599  d->properties.append(PropertyEntry(name, value));
600  return;
601  }
602  }
603 
604  QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
605  while (propertyIterator.hasNext()) {
606  PropertyEntry &entry = propertyIterator.next();
607  if (entry.first == name) {
608  entry.second = value;
609  if (state() && state()->isStateActive())
610  d->property(name).write(value);
611  return;
612  }
613  }
614 
615  QDeclarativeAction action;
616  action.restore = restoreEntryValues();
617  action.property = d->property(name);
618  action.fromValue = action.property.read();
619  action.specifiedObject = object();
620  action.specifiedProperty = name;
621  action.toValue = value;
622 
623  propertyIterator.insert(PropertyEntry(name, value));
624  if (state() && state()->isStateActive()) {
625  state()->addEntryToRevertList(action);
627  if (oldBinding)
629  d->property(name).write(value);
630  }
631 }
632 
634 {
636  typedef QPair<QString, QVariant> PropertyEntry;
638 
639  bool hadValue = false;
640 
641  QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
642  while (propertyIterator.hasNext()) {
643  PropertyEntry &entry = propertyIterator.next();
644  if (entry.first == name) {
645  propertyIterator.remove();
646  hadValue = true;
647  break;
648  }
649  }
650 
651  QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
652  while (expressionIterator.hasNext()) {
653  const ExpressionEntry &entry = expressionIterator.next();
654  if (entry.name == name) {
655  entry.expression->setExpression(expression);
656  if (state() && state()->isStateActive()) {
658  if (oldBinding) {
659  QDeclarativePropertyPrivate::setBinding(d->property(name), 0);
660  oldBinding->destroy();
661  }
662 
663  QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this));
664  newBinding->setTarget(d->property(name));
666  }
667  return;
668  }
669  }
670 
671  QDeclarativeExpression *newExpression = new QDeclarativeExpression(qmlContext(this), d->object, expression);
672  expressionIterator.insert(ExpressionEntry(name, QDeclarativeBinding::Invalid, newExpression));
673 
674  if (state() && state()->isStateActive()) {
675  if (hadValue) {
677  if (oldBinding) {
679  state()->changeBindingInRevertList(object(), name, oldBinding);
680  }
681 
682  QDeclarativeBinding *newBinding = new QDeclarativeBinding(expression, object(), qmlContext(this));
683  newBinding->setTarget(d->property(name));
685  } else {
686  QDeclarativeAction action;
687  action.restore = restoreEntryValues();
688  action.property = d->property(name);
689  action.fromValue = action.property.read();
690  action.specifiedObject = object();
691  action.specifiedProperty = name;
692 
693 
694  if (d->isExplicit) {
695  action.toValue = newExpression->evaluate();
696  } else {
697  QDeclarativeBinding *newBinding = new QDeclarativeBinding(newExpression->expression(), object(), qmlContext(this));
698  newBinding->setTarget(d->property(name));
699  action.toBinding = newBinding;
700  action.deletableToBinding = true;
701 
702  state()->addEntryToRevertList(action);
704  if (oldBinding)
706 
708  }
709  }
710  }
711  // what about the signal handler?
712 }
713 
715 {
717  typedef QPair<QString, QVariant> PropertyEntry;
719 
720  QListIterator<PropertyEntry> propertyIterator(d->properties);
721  while (propertyIterator.hasNext()) {
722  const PropertyEntry &entry = propertyIterator.next();
723  if (entry.first == name) {
724  return entry.second;
725  }
726  }
727 
728  QListIterator<ExpressionEntry> expressionIterator(d->expressions);
729  while (expressionIterator.hasNext()) {
730  const ExpressionEntry &entry = expressionIterator.next();
731  if (entry.name == name) {
732  return QVariant(entry.expression->expression());
733  }
734  }
735 
736  return QVariant();
737 }
738 
740 {
742  typedef QPair<QString, QVariant> PropertyEntry;
744 
745  QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions);
746  while (expressionIterator.hasNext()) {
747  const ExpressionEntry &entry = expressionIterator.next();
748  if (entry.name == name) {
749  expressionIterator.remove();
750  state()->removeEntryFromRevertList(object(), name);
751  return;
752  }
753  }
754 
755  QMutableListIterator<PropertyEntry> propertyIterator(d->properties);
756  while (propertyIterator.hasNext()) {
757  const PropertyEntry &entry = propertyIterator.next();
758  if (entry.first == name) {
759  propertyIterator.remove();
760  state()->removeEntryFromRevertList(object(), name);
761  return;
762  }
763  }
764 }
765 
767 {
769  typedef QPair<QString, QVariant> PropertyEntry;
770 
771  QListIterator<PropertyEntry> propertyIterator(d->properties);
772  while (propertyIterator.hasNext()) {
773  const PropertyEntry &entry = propertyIterator.next();
774  if (entry.first == name) {
775  return entry.second;
776  }
777  }
778 
779  return QVariant();
780 }
781 
783 {
786 
787  QListIterator<ExpressionEntry> expressionIterator(d->expressions);
788  while (expressionIterator.hasNext()) {
789  const ExpressionEntry &entry = expressionIterator.next();
790  if (entry.name == name) {
791  return entry.expression->expression();
792  }
793  }
794 
795  return QString();
796 }
797 
799 {
800  if (state())
802 }
803 
805 {
806  if (state())
808 }
809 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
virtual QByteArray compile(const QList< QDeclarativeCustomParserProperty > &)
double d
Definition: qnumeric_p.h:62
void changeValue(const QString &name, const QVariant &value)
virtual void copyOriginals(QDeclarativeActionEvent *other)
virtual void setCustomData(QObject *, const QByteArray &)
QDeclarativeGuard< QDeclarativeExpression > ownedExpression
static QDeclarativeData * get(const QObject *object, bool create=false)
QDeclarativeProperty property
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
void compileList(QList< QPair< QByteArray, QVariant > > &list, const QByteArray &pre, const QDeclarativeCustomParserProperty &prop)
#define error(msg)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
void removeProperty(const QString &name)
void setTarget(const QDeclarativeProperty &)
bool containsProperty(const QString &name) const
virtual void destroy(DestroyMode mode=DisconnectBinding)
Destroy the binding.
static QDeclarativeAbstractBinding * binding(QObject *, int coreIndex, int valueTypeIndex)
void removeAllEntriesFromRevertList(QObject *target)
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
long ASN1_INTEGER_get ASN1_INTEGER * a
QVariant evaluate(bool *valueIsUndefined=0)
Evaulates the expression, returning the result of the evaluation, or an invalid QVariant if the expre...
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
Type type() const
Returns the type of the property.
The QString class provides a Unicode character string.
Definition: qstring.h:83
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
Q_DECLARATIVE_EXPORT QDeclarativeContext * qmlContext(const QObject *)
#define Q_D(Class)
Definition: qglobal.h:2482
bool isValid() const
Returns true if the QDeclarativeProperty refers to a valid property, otherwise false.
bool containsValue(const QString &name) const
static QObjectPrivate * get(QObject *o)
Definition: qobject_p.h:177
void addEntriesToRevertList(const QList< QDeclarativeAction > &actions)
#define Q_Q(Class)
Definition: qglobal.h:2483
static Identifier Invalid
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
const char * name
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
static QString fromUtf8(const char *, int size=-1)
Returns a QString initialized with the first size bytes of the UTF-8 string str.
Definition: qstring.cpp:4302
QDeclarativeState * state() const
static const char * data(const QByteArray &arr)
static QDeclarativeExpression * signalExpression(const QDeclarativeProperty &that)
Returns the expression associated with this signal property, or 0 if no signal expression exists...
QWeakPointer< QDeclarativeAbstractBinding > toBinding
static QDeclarativeAbstractBinding * setBinding(QObject *, int coreIndex, int valueTypeIndex, QDeclarativeAbstractBinding *, WriteFlags flags=DontRemoveBinding)
quint16 values[128]
ExpressionChange(const QString &_name, QDeclarativeBinding::Identifier _id, QDeclarativeExpression *_expr)
bool changeBindingInRevertList(QObject *target, const QString &name, QDeclarativeAbstractBinding *binding)
QString expression() const
Returns the expression string.
int lineNumber() const
Returns the source file line number for this expression.
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
QVariant value(const QString &name) const
int userType() const
Returns the storage type of the value stored in the variant.
Definition: qvariant.cpp:1913
#define Q_DECLARE_PUBLIC(Class)
Definition: qglobal.h:2477
QVariant property(const QString &name) const
bool removeEntryFromRevertList(QObject *target, const QString &name)
QString expression(const QString &name) const
void addEntryToRevertList(const QDeclarativeAction &action)
QDeclarativeProperty property(const QString &)
Q_OUTOFLINE_TEMPLATE QPair< T1, T2 > qMakePair(const T1 &x, const T2 &y)
Definition: qpair.h:102
QString sourceFile() const
Returns the source file URL for this expression.
void changeExpression(const QString &name, const QString &expression)
bool isWritable() const
Returns true if the property is writable, otherwise false.
T qvariant_cast(const QVariant &)
Definition: qvariant.h:571
static const QCssKnownValue properties[NumProperties - 1]
Definition: qcssparser.cpp:67
void setSourceLocation(const QString &fileName, int line)
Set the location of this expression to line of url.
The QDeclarativeProperty class abstracts accessing properties on objects created from QML...
static QDeclarativeExpression * setSignalExpression(const QDeclarativeProperty &that, QDeclarativeExpression *)
Set the signal expression associated with this signal property to expr.
QDeclarativeActionEvent * event
The QDataStream class provides serialization of binary data to a QIODevice.
Definition: qdatastream.h:71
The QDeclarativeExpression class evaluates JavaScript in a QML context.
QDeclarativeInfo qmlInfo(const QObject *me)
QImageIOHandler * handler
bool containsExpression(const QString &name) const
static QDeclarativeBinding * createBinding(Identifier, QObject *, QDeclarativeContext *, const QString &, int, QObject *parent=0)
QList< QPair< QString, QVariant > > properties
QVariant read() const
Returns the property value.
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
QList< QDeclarativeReplaceSignalHandler * > signalReplacements