Qt 4.8
qdeclarativebinding.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/qdeclarativebinding_p.h"
43 #include "private/qdeclarativebinding_p_p.h"
44 
45 #include "qdeclarative.h"
46 #include "qdeclarativecontext.h"
47 #include "qdeclarativeinfo.h"
48 #include "private/qdeclarativecontext_p.h"
49 #include "private/qdeclarativecompiler_p.h"
50 #include "private/qdeclarativedata_p.h"
51 #include "private/qdeclarativestringconverters_p.h"
52 #include "private/qdeclarativestate_p_p.h"
53 #include "private/qdeclarativedebugtrace_p.h"
54 
55 #include <QVariant>
56 #include <QtCore/qdebug.h>
57 
59 
61 : m_object(0), m_propertyIndex(-1), m_mePtr(0), m_prevBinding(0), m_nextBinding(0)
62 {
63 }
64 
66 {
67  Q_ASSERT(m_prevBinding == 0);
68  Q_ASSERT(m_mePtr == 0);
69 }
70 
79 {
80  if (mode == DisconnectBinding)
82 
84  clear();
85 
86  delete this;
87 }
88 
98 {
99  Q_ASSERT(object);
100 
101  if (m_object == object && m_propertyIndex == index)
102  return;
103 
105 
107 
108  m_object = object;
110 
112 
113  if (index & 0xFF000000) {
114  // Value type
115 
116  int coreIndex = index & 0xFFFFFF;
117 
118  // Find the value type proxy (if there is one)
120  if (data->hasBindingBit(coreIndex)) {
122  while (b && b->propertyIndex() != coreIndex)
123  b = b->m_nextBinding;
125  proxy = static_cast<QDeclarativeValueTypeProxyBinding *>(b);
126  }
127 
128  if (!proxy) {
129  proxy = new QDeclarativeValueTypeProxyBinding(object, coreIndex);
130  proxy->addToObject(object, coreIndex);
131  }
132 
133  m_nextBinding = proxy->m_bindings;
135  m_prevBinding = &proxy->m_bindings;
136  proxy->m_bindings = this;
137 
138  } else {
139  m_nextBinding = data->bindings;
141  m_prevBinding = &data->bindings;
142  data->bindings = this;
143 
144  data->setBindingBit(m_object, index);
145  }
146 }
147 
152 {
153  if (m_prevBinding) {
154  int index = propertyIndex();
155 
158  m_prevBinding = 0;
159  m_nextBinding = 0;
160 
161  if (index & 0xFF000000) {
162  // Value type - we don't remove the proxy from the object. It will sit their happily
163  // doing nothing until it is removed by a write, a binding change or it is reused
164  // to hold more sub-bindings.
165  } else if (m_object) {
167  if (data) data->clearBindingBit(index);
168  }
169 
170  m_object = 0;
171  m_propertyIndex = -1;
172  }
173 }
174 
176 {
177 }
178 
180 {
181  if (m_selfPointer.isNull())
183 
184  return m_selfPointer.toWeakRef();
185 }
186 
188 {
189  if (m_mePtr) {
190  *m_mePtr = 0;
191  m_mePtr = 0;
192  }
193 }
194 
196 {
197  return QLatin1String("<Unknown>");
198 }
199 
201 {
202  return m_object;
203 }
204 
206 {
207  return m_propertyIndex;
208 }
209 
210 void QDeclarativeAbstractBinding::setEnabled(bool enabled, QDeclarativePropertyPrivate::WriteFlags flags)
211 {
212  if (enabled) update(flags);
213 }
214 
216 
218 {
220  q->update();
221 }
222 
224 : updating(false), enabled(false), deleted(0)
225 {
226 }
227 
229 {
230  if (deleted) *deleted = true;
231 }
232 
234  QDeclarativeContextData *ctxt, const QString &url, int lineNumber,
235  QObject *parent)
236 : QDeclarativeExpression(ctxt, data, rc, obj, url, lineNumber, *new QDeclarativeBindingPrivate)
237 {
238  setParent(parent);
240 }
241 
244  const QString &url, int lineNumber, QObject *parent)
245 {
246  if (id < 0)
247  return 0;
248 
249  Q_ASSERT(ctxt);
251 
253  QDeclarativeCompiledData *cdata = 0;
254  QDeclarativeTypeData *typeData = 0;
255  if (!ctxtdata->url.isEmpty()) {
256  typeData = engine->typeLoader.get(ctxtdata->url);
257  cdata = typeData->compiledData();
258  }
259  QDeclarativeBinding *rv = cdata ? new QDeclarativeBinding((void*)cdata->datas.at(id).constData(), cdata, obj, ctxtdata, url, lineNumber, parent) : 0;
260  if (cdata)
261  cdata->release();
262  if (typeData)
263  typeData->release();
264  return rv;
265 }
266 
268  QObject *parent)
270 {
271  setParent(parent);
273 }
274 
276  QObject *parent)
278 {
279  setParent(parent);
281 }
282 
284 : QDeclarativeExpression(ctxt, obj, func, *new QDeclarativeBindingPrivate)
285 {
286  setParent(parent);
288 }
289 
291 {
292 }
293 
295 {
297  d->property = prop;
298 
299  update();
300 }
301 
303 {
304  Q_D(const QDeclarativeBinding);
305  return d->property;
306 }
307 
308 void QDeclarativeBinding::setEvaluateFlags(EvaluateFlags flags)
309 {
311  d->setEvaluateFlags(QDeclarativeQtScriptExpression::EvaluateFlags(static_cast<int>(flags)));
312 }
313 
314 QDeclarativeBinding::EvaluateFlags QDeclarativeBinding::evaluateFlags() const
315 {
316  Q_D(const QDeclarativeBinding);
317  return QDeclarativeBinding::EvaluateFlags(static_cast<int>(d->evaluateFlags()));
318 }
319 
320 
322 public:
324  {
328  }
329 
331  {
333  }
334 };
335 
336 void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
337 {
339 
340  if (!d->enabled || !d->context() || !d->context()->isValid())
341  return;
342 
343  if (!d->updating) {
344  QDeclarativeBindingProfiler prof(this);
345  d->updating = true;
346  bool wasDeleted = false;
347  d->deleted = &wasDeleted;
348 
349  if (d->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) {
350 
351  int idx = d->property.index();
352  Q_ASSERT(idx != -1);
353 
354  QDeclarativeBinding *t = this;
355  int status = -1;
356  void *a[] = { &t, 0, &status, &flags };
357  QMetaObject::metacall(d->property.object(),
359  idx, a);
360 
361  if (wasDeleted)
362  return;
363 
364  } else {
366 
367  bool isUndefined = false;
368  QVariant value;
369 
370  QScriptValue scriptValue = d->scriptValue(0, &isUndefined);
371  if (wasDeleted)
372  return;
373 
374  if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) {
375  value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >());
376  } else if (scriptValue.isNull() &&
377  d->property.propertyTypeCategory() == QDeclarativeProperty::Object) {
378  value = QVariant::fromValue((QObject *)0);
379  } else {
380  value = ep->scriptValueToVariant(scriptValue, d->property.propertyType());
381  if (value.userType() == QMetaType::QObjectStar && !qvariant_cast<QObject*>(value)) {
382  // If the object is null, we extract the predicted type. While this isn't
383  // 100% reliable, in many cases it gives us better error messages if we
384  // assign this null-object to an incompatible property
385  int type = ep->objectClass->objectType(scriptValue);
386  QObject *o = 0;
387  value = QVariant(type, (void *)&o);
388  }
389  }
390 
391 
392  if (d->error.isValid()) {
393 
394  } else if (isUndefined && d->property.isResettable()) {
395 
396  d->property.reset();
397 
398  } else if (isUndefined && d->property.propertyType() == qMetaTypeId<QVariant>()) {
399 
400  QDeclarativePropertyPrivate::write(d->property, QVariant(), flags);
401 
402  } else if (isUndefined) {
403 
404  QUrl url = QUrl(d->url);
405  int line = d->line;
406  if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
407 
408  d->error.setUrl(url);
409  d->error.setLine(line);
410  d->error.setColumn(-1);
411  d->error.setDescription(QLatin1String("Unable to assign [undefined] to ") +
412  QLatin1String(QMetaType::typeName(d->property.propertyType())) +
413  QLatin1String(" ") + d->property.name());
414 
415  } else if (!scriptValue.isRegExp() && scriptValue.isFunction()) {
416 
417  QUrl url = QUrl(d->url);
418  int line = d->line;
419  if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
420 
421  d->error.setUrl(url);
422  d->error.setLine(line);
423  d->error.setColumn(-1);
424  d->error.setDescription(QLatin1String("Unable to assign a function to a property."));
425 
426  } else if (d->property.object() &&
427  !QDeclarativePropertyPrivate::write(d->property, value, flags)) {
428 
429  if (wasDeleted)
430  return;
431 
432  QUrl url = QUrl(d->url);
433  int line = d->line;
434  if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
435 
436  const char *valueType = 0;
437  if (value.userType() == QVariant::Invalid) valueType = "null";
438  else valueType = QMetaType::typeName(value.userType());
439 
440  d->error.setUrl(url);
441  d->error.setLine(line);
442  d->error.setColumn(-1);
443  d->error.setDescription(QLatin1String("Unable to assign ") +
444  QLatin1String(valueType) +
445  QLatin1String(" to ") +
446  QLatin1String(QMetaType::typeName(d->property.propertyType())));
447  }
448 
449  if (wasDeleted)
450  return;
451 
452  if (d->error.isValid()) {
453  if (!d->addError(ep)) ep->warning(this->error());
454  } else {
455  d->removeError();
456  }
457  }
458 
459  d->updating = false;
460  d->deleted = 0;
461  } else {
462  qmlInfo(d->property.object()) << tr("Binding loop detected for property \"%1\"").arg(d->property.name());
463  }
464 }
465 
467 {
469  q->update();
470 }
471 
472 void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
473 {
475  d->enabled = e;
477 
478  if (e)
479  update(flags);
480 }
481 
483 {
484  Q_D(const QDeclarativeBinding);
485 
486  return d->enabled;
487 }
488 
490 {
492 }
493 
495 {
496  Q_UNUSED(disconnectMode);
498 }
499 
501 : m_object(o), m_index(index), m_bindings(0)
502 {
503 }
504 
506 {
507  while (m_bindings) {
509  binding->setEnabled(false, 0);
510  binding->destroy();
511  }
512 }
513 
514 void QDeclarativeValueTypeProxyBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
515 {
516  if (e) {
518  recursiveEnable(bindings, flags);
519  } else {
521  recursiveDisable(bindings);
522  }
523 }
524 
525 void QDeclarativeValueTypeProxyBinding::recursiveEnable(QDeclarativeAbstractBinding *b, QDeclarativePropertyPrivate::WriteFlags flags)
526 {
527  if (!b)
528  return;
529 
530  recursiveEnable(b->m_nextBinding, flags);
531 
532  if (b)
533  b->setEnabled(true, flags);
534 }
535 
537 {
538  if (!b)
539  return;
540 
542 
543  if (b)
544  b->setEnabled(false, 0);
545 }
546 
547 void QDeclarativeValueTypeProxyBinding::update(QDeclarativePropertyPrivate::WriteFlags)
548 {
549 }
550 
552 {
553  Q_UNUSED(disconnectMode);
554  // Nothing to do
555 }
556 
558 {
560 
561  while (binding && binding->propertyIndex() != propertyIndex)
562  binding = binding->m_nextBinding;
563 
564  return binding;
565 }
566 
571 {
573  while (binding) {
574  if (mask & (1 << (binding->propertyIndex() >> 24))) {
576  binding = remove->m_nextBinding;
577  *remove->m_prevBinding = remove->m_nextBinding;
578  if (remove->m_nextBinding) remove->m_nextBinding->m_prevBinding = remove->m_prevBinding;
579  remove->m_prevBinding = 0;
580  remove->m_nextBinding = 0;
581  remove->destroy();
582  } else {
583  binding = binding->m_nextBinding;
584  }
585  }
586 }
587 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
double d
Definition: qnumeric_p.h:62
void setBindingBit(QObject *obj, int)
bool isNull() const
Returns true if this QScriptValue is of the primitive type Null; otherwise returns false...
static QDeclarativeData * get(const QObject *object, bool create=false)
int type
Definition: qmetatype.cpp:239
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
bool isFunction() const
Returns true if this QScriptValue is a function; otherwise returns false.
QDeclarativeEngine * engine
QDeclarativeEngine * engine() const
Returns the QDeclarativeEngine this expression is associated with, or 0 if there is no association or...
static void rangeLocation(RangeType, const QString &, int)
static int metacall(QObject *, Call, int, void **)
bool isEmpty() const
Returns true if the URL has no data; otherwise returns false.
Definition: qurl.cpp:4317
QDeclarativeCompiledData * compiledData() const
void addToObject(QObject *, int)
Add this binding to object.
void setTarget(const QDeclarativeProperty &)
virtual void destroy(DestroyMode mode=DisconnectBinding)
Destroy the binding.
QWeakPointer< T > toWeakRef() const
Returns a weak reference object that shares the pointer referenced by this object.
QDeclarativeAbstractBinding * bindings
int qMetaTypeId()
Definition: qmetatype.h:224
static LibLoadStatus status
Definition: qlocale_icu.cpp:69
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
QDeclarativeBindingProfiler(QDeclarativeBinding *bind)
QDeclarativeValueTypeProxyBinding(QObject *o, int coreIndex)
The QUrl class provides a convenient interface for working with URLs.
Definition: qurl.h:61
QDeclarativeTypeLoader typeLoader
The QString class provides a Unicode character string.
Definition: qstring.h:83
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
#define Q_D(Class)
Definition: qglobal.h:2482
void recursiveEnable(QDeclarativeAbstractBinding *, QDeclarativePropertyPrivate::WriteFlags)
bool hasBindingBit(int) const
virtual void disconnect(DisconnectMode disconnectMode)
static QDeclarativeEnginePrivate * get(QDeclarativeEngine *e)
void setNotifyOnValueChanged(bool)
Sets whether the valueChanged() signal is emitted when the expression&#39;s evaluated value changes...
void setParent(QObject *)
Makes the object a child of parent.
Definition: qobject.cpp:1950
QVariant scriptValueToVariant(const QScriptValue &, int hint=QVariant::Invalid)
#define Q_Q(Class)
Definition: qglobal.h:2483
static Identifier Invalid
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QDeclarativeBinding(const QString &, QObject *, QDeclarativeContext *, QObject *parent=0)
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
static const char * data(const QByteArray &arr)
virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags)
QDeclarativeAbstractBinding * m_nextBinding
void setEvaluateFlags(EvaluateFlags flags)
static QVariant fromValue(const T &value)
Returns a QVariant containing a copy of value.
Definition: qvariant.h:336
QDeclarativeAbstractBinding * binding(int propertyIndex)
QDeclarativeObjectScriptClass * objectClass
static void endRange(RangeType)
void removeBindings(quint32 mask)
Removes a collection of bindings, corresponding to the set bits in mask.
static void startRange(RangeType)
QString expression() const
Returns the expression string.
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
virtual void disconnect(DisconnectMode disconnectMode)=0
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
int userType() const
Returns the storage type of the value stored in the variant.
Definition: qvariant.cpp:1913
static void bindingDummyDeleter(QDeclarativeAbstractBinding *)
virtual void disconnect(DisconnectMode disconnectMode)
void removeFromObject()
Remove the binding from the object.
int objectType(const QScriptValue &) const
bool isRegExp() const
Returns true if this QScriptValue is an object of the RegExp class; otherwise returns false...
static const char * typeName(int type)
Returns the type name associated with the given type, or 0 if no matching type was found...
Definition: qmetatype.cpp:406
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
QDeclarativeAbstractBinding * m_bindings
QString sourceFile() const
Returns the source file URL for this expression.
virtual QString expression() const
unsigned int quint32
Definition: qglobal.h:938
virtual QString expression() const
static void rangeData(RangeType, const QString &)
static const char * get(QDBusError::ErrorType code)
Definition: qdbuserror.cpp:141
T qvariant_cast(const QVariant &)
Definition: qvariant.h:571
The QDeclarativeContext class defines a context within a QML engine.
quint16 index
QObject * parent
Definition: qobject.h:92
void recursiveDisable(QDeclarativeAbstractBinding *)
QDeclarativeTypeData * get(const QUrl &url)
Returns a QDeclarativeTypeData for the specified url.
The QDeclarativeProperty class abstracts accessing properties on objects created from QML...
QSharedPointer< QDeclarativeAbstractBinding > m_selfPointer
QDeclarativeProperty property() const
The QDeclarativeExpression class evaluates JavaScript in a QML context.
QDeclarativeAbstractBinding ** m_prevBinding
QDeclarativeInfo qmlInfo(const QObject *me)
void warning(const QDeclarativeError &)
The QScriptValue class acts as a container for the Qt Script data types.
Definition: qscriptvalue.h:57
bool isNull() const
Returns true if this object is holding a reference to a null pointer.
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
#define enabled
virtual void setEnabled(bool, QDeclarativePropertyPrivate::WriteFlags flags)
static QDeclarativeBinding * createBinding(Identifier, QObject *, QDeclarativeContext *, const QString &, int, QObject *parent=0)
EvaluateFlags evaluateFlags() const
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
static bool write(QObject *, const QDeclarativePropertyCache::Data &, const QVariant &, QDeclarativeContextData *, WriteFlags flags=0)
QDeclarativeAbstractBinding ** m_mePtr
static QDeclarativeContextData * get(QDeclarativeContext *context)