src/declarative/qml/qdeclarativebinding.cpp
changeset 33 3e2da88830cd
parent 30 5dc02b23752f
equal deleted inserted replaced
30:5dc02b23752f 33:3e2da88830cd
    52 #include <QVariant>
    52 #include <QVariant>
    53 #include <QtCore/qdebug.h>
    53 #include <QtCore/qdebug.h>
    54 
    54 
    55 QT_BEGIN_NAMESPACE
    55 QT_BEGIN_NAMESPACE
    56 
    56 
    57 QDeclarativeBindingData::QDeclarativeBindingData()
    57 void QDeclarativeBindingPrivate::refresh()
    58 : updating(false), enabled(false)
    58 {
    59 {
    59     Q_Q(QDeclarativeBinding);
    60 }
    60     q->update();
    61 
       
    62 QDeclarativeBindingData::~QDeclarativeBindingData()
       
    63 {
       
    64     removeError();
       
    65 }
       
    66 
       
    67 void QDeclarativeBindingData::refresh()
       
    68 {
       
    69     if (enabled && !updating && q) {
       
    70         QDeclarativeBinding *b = static_cast<QDeclarativeBinding *>(QDeclarativeExpressionPrivate::get(q));
       
    71         b->update();
       
    72     }
       
    73 }
    61 }
    74 
    62 
    75 QDeclarativeBindingPrivate::QDeclarativeBindingPrivate()
    63 QDeclarativeBindingPrivate::QDeclarativeBindingPrivate()
    76 : QDeclarativeExpressionPrivate(new QDeclarativeBindingData)
    64 : updating(false), enabled(false), deleted(0)
    77 {
    65 {
       
    66 }
       
    67 
       
    68 QDeclarativeBindingPrivate::~QDeclarativeBindingPrivate()
       
    69 {
       
    70     if (deleted) *deleted = true;
    78 }
    71 }
    79 
    72 
    80 QDeclarativeBinding::QDeclarativeBinding(void *data, QDeclarativeRefCount *rc, QObject *obj, 
    73 QDeclarativeBinding::QDeclarativeBinding(void *data, QDeclarativeRefCount *rc, QObject *obj, 
    81                                          QDeclarativeContextData *ctxt, const QString &url, int lineNumber, 
    74                                          QDeclarativeContextData *ctxt, const QString &url, int lineNumber, 
    82                                          QObject *parent)
    75                                          QObject *parent)
   107 }
   100 }
   108 
   101 
   109 void QDeclarativeBinding::setTarget(const QDeclarativeProperty &prop)
   102 void QDeclarativeBinding::setTarget(const QDeclarativeProperty &prop)
   110 {
   103 {
   111     Q_D(QDeclarativeBinding);
   104     Q_D(QDeclarativeBinding);
   112     d->bindingData()->property = prop;
   105     d->property = prop;
   113 
   106 
   114     update();
   107     update();
   115 }
   108 }
   116 
   109 
   117 QDeclarativeProperty QDeclarativeBinding::property() const 
   110 QDeclarativeProperty QDeclarativeBinding::property() const 
   118 {
   111 {
   119    Q_D(const QDeclarativeBinding);
   112    Q_D(const QDeclarativeBinding);
   120    return d->bindingData()->property; 
   113    return d->property; 
   121 }
   114 }
   122 
   115 
   123 void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
   116 void QDeclarativeBinding::update(QDeclarativePropertyPrivate::WriteFlags flags)
   124 {
   117 {
   125     Q_D(QDeclarativeBinding);
   118     Q_D(QDeclarativeBinding);
   126 
   119 
   127     QDeclarativeBindingData *data = d->bindingData();
   120     if (!d->enabled || !d->context() || !d->context()->isValid()) 
   128 
       
   129     if (!data->enabled || !data->context() || !data->context()->isValid())
       
   130         return;
   121         return;
   131 
   122 
   132     data->addref();
   123     if (!d->updating) {
   133 
   124         d->updating = true;
   134     if (!data->updating) {
   125         bool wasDeleted = false;
   135         data->updating = true;
   126         d->deleted = &wasDeleted;
   136 
   127 
   137         if (data->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) {
   128         if (d->property.propertyType() == qMetaTypeId<QDeclarativeBinding *>()) {
   138 
   129 
   139             int idx = data->property.index();
   130             int idx = d->property.index();
   140             Q_ASSERT(idx != -1);
   131             Q_ASSERT(idx != -1);
   141 
       
   142 
   132 
   143             QDeclarativeBinding *t = this;
   133             QDeclarativeBinding *t = this;
   144             int status = -1;
   134             int status = -1;
   145             void *a[] = { &t, 0, &status, &flags };
   135             void *a[] = { &t, 0, &status, &flags };
   146             QMetaObject::metacall(data->property.object(),
   136             QMetaObject::metacall(d->property.object(),
   147                                   QMetaObject::WriteProperty,
   137                                   QMetaObject::WriteProperty,
   148                                   idx, a);
   138                                   idx, a);
   149 
   139 
       
   140             if (wasDeleted)
       
   141                 return;
       
   142 
   150         } else {
   143         } else {
   151             QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(data->context()->engine);
   144             QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(d->context()->engine);
   152 
   145 
   153             bool isUndefined = false;
   146             bool isUndefined = false;
   154             QVariant value;
   147             QVariant value;
   155 
   148 
   156             QScriptValue scriptValue = d->scriptValue(0, &isUndefined);
   149             QScriptValue scriptValue = d->scriptValue(0, &isUndefined);
   157             if (data->property.propertyTypeCategory() == QDeclarativeProperty::List) {
   150             if (wasDeleted)
       
   151                 return;
       
   152 
       
   153             if (d->property.propertyTypeCategory() == QDeclarativeProperty::List) {
   158                 value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >());
   154                 value = ep->scriptValueToVariant(scriptValue, qMetaTypeId<QList<QObject *> >());
   159             } else if (scriptValue.isNull() && 
   155             } else if (scriptValue.isNull() && 
   160                        data->property.propertyTypeCategory() == QDeclarativeProperty::Object) {
   156                        d->property.propertyTypeCategory() == QDeclarativeProperty::Object) {
   161                 value = QVariant::fromValue((QObject *)0);
   157                 value = QVariant::fromValue((QObject *)0);
   162             } else {
   158             } else {
   163                 value = ep->scriptValueToVariant(scriptValue, data->property.propertyType());
   159                 value = ep->scriptValueToVariant(scriptValue, d->property.propertyType());
   164                 if (value.userType() == QMetaType::QObjectStar && !qvariant_cast<QObject*>(value)) {
   160                 if (value.userType() == QMetaType::QObjectStar && !qvariant_cast<QObject*>(value)) {
   165                     // If the object is null, we extract the predicted type.  While this isn't
   161                     // If the object is null, we extract the predicted type.  While this isn't
   166                     // 100% reliable, in many cases it gives us better error messages if we
   162                     // 100% reliable, in many cases it gives us better error messages if we
   167                     // assign this null-object to an incompatible property
   163                     // assign this null-object to an incompatible property
   168                     int type = ep->objectClass->objectType(scriptValue);
   164                     int type = ep->objectClass->objectType(scriptValue);
   170                     value = QVariant(type, (void *)&o);
   166                     value = QVariant(type, (void *)&o);
   171                 }
   167                 }
   172             }
   168             }
   173 
   169 
   174 
   170 
   175             if (data->error.isValid()) {
   171             if (d->error.isValid()) {
   176 
   172 
   177             } else if (isUndefined && data->property.isResettable()) {
   173             } else if (isUndefined && d->property.isResettable()) {
   178 
   174 
   179                 data->property.reset();
   175                 d->property.reset();
   180 
   176 
   181             } else if (isUndefined && data->property.propertyType() == qMetaTypeId<QVariant>()) {
   177             } else if (isUndefined && d->property.propertyType() == qMetaTypeId<QVariant>()) {
   182 
   178 
   183                 QDeclarativePropertyPrivate::write(data->property, QVariant(), flags);
   179                 QDeclarativePropertyPrivate::write(d->property, QVariant(), flags);
   184 
   180 
   185             } else if (isUndefined) {
   181             } else if (isUndefined) {
   186 
   182 
   187                 QUrl url = QUrl(data->url);
   183                 QUrl url = QUrl(d->url);
   188                 int line = data->line;
   184                 int line = d->line;
   189                 if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
   185                 if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
   190 
   186 
   191                 data->error.setUrl(url);
   187                 d->error.setUrl(url);
   192                 data->error.setLine(line);
   188                 d->error.setLine(line);
   193                 data->error.setColumn(-1);
   189                 d->error.setColumn(-1);
   194                 data->error.setDescription(QLatin1String("Unable to assign [undefined] to ")
   190                 d->error.setDescription(QLatin1String("Unable to assign [undefined] to ") +
   195                     + QLatin1String(QMetaType::typeName(data->property.propertyType()))
   191                                         QLatin1String(QMetaType::typeName(d->property.propertyType())) +
   196                     + QLatin1String(" ") + data->property.name());
   192                                         QLatin1String(" ") + d->property.name());
   197 
   193 
   198             } else if (!scriptValue.isRegExp() && scriptValue.isFunction()) {
   194             } else if (!scriptValue.isRegExp() && scriptValue.isFunction()) {
   199 
   195 
   200                 QUrl url = QUrl(data->url);
   196                 QUrl url = QUrl(d->url);
   201                 int line = data->line;
   197                 int line = d->line;
   202                 if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
   198                 if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
   203 
   199 
   204                 data->error.setUrl(url);
   200                 d->error.setUrl(url);
   205                 data->error.setLine(line);
   201                 d->error.setLine(line);
   206                 data->error.setColumn(-1);
   202                 d->error.setColumn(-1);
   207                 data->error.setDescription(QLatin1String("Unable to assign a function to a property."));
   203                 d->error.setDescription(QLatin1String("Unable to assign a function to a property."));
   208 
   204 
   209             } else if (data->property.object() &&
   205             } else if (d->property.object() &&
   210                        !QDeclarativePropertyPrivate::write(data->property, value, flags)) {
   206                        !QDeclarativePropertyPrivate::write(d->property, value, flags)) {
   211 
   207 
   212                 QUrl url = QUrl(data->url);
   208                 if (wasDeleted)
   213                 int line = data->line;
   209                     return;
       
   210 
       
   211                 QUrl url = QUrl(d->url);
       
   212                 int line = d->line;
   214                 if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
   213                 if (url.isEmpty()) url = QUrl(QLatin1String("<Unknown File>"));
   215 
   214 
   216                 const char *valueType = 0;
   215                 const char *valueType = 0;
   217                 if (value.userType() == QVariant::Invalid) valueType = "null";
   216                 if (value.userType() == QVariant::Invalid) valueType = "null";
   218                 else valueType = QMetaType::typeName(value.userType());
   217                 else valueType = QMetaType::typeName(value.userType());
   219 
   218 
   220                 data->error.setUrl(url);
   219                 d->error.setUrl(url);
   221                 data->error.setLine(line);
   220                 d->error.setLine(line);
   222                 data->error.setColumn(-1);
   221                 d->error.setColumn(-1);
   223                 data->error.setDescription(QLatin1String("Unable to assign ") +
   222                 d->error.setDescription(QLatin1String("Unable to assign ") +
   224                                            QLatin1String(valueType) +
   223                                         QLatin1String(valueType) +
   225                                            QLatin1String(" to ") +
   224                                         QLatin1String(" to ") +
   226                                            QLatin1String(QMetaType::typeName(data->property.propertyType())));
   225                                         QLatin1String(QMetaType::typeName(d->property.propertyType())));
   227             }
   226             }
   228 
   227 
   229             if (data->error.isValid()) {
   228             if (wasDeleted)
   230                if (!data->addError(ep)) ep->warning(this->error());
   229                 return;
       
   230 
       
   231             if (d->error.isValid()) {
       
   232                if (!d->addError(ep)) ep->warning(this->error());
   231             } else {
   233             } else {
   232                 data->removeError();
   234                 d->removeError();
   233             }
   235             }
   234         }
   236         }
   235 
   237 
   236         data->updating = false;
   238         d->updating = false;
       
   239         d->deleted = 0;
   237     } else {
   240     } else {
   238         qmlInfo(data->property.object()) << tr("Binding loop detected for property \"%1\"").arg(data->property.name());
   241         qmlInfo(d->property.object()) << tr("Binding loop detected for property \"%1\"").arg(d->property.name());
   239     }
   242     }
   240 
       
   241     data->release();
       
   242 }
   243 }
   243 
   244 
   244 void QDeclarativeBindingPrivate::emitValueChanged()
   245 void QDeclarativeBindingPrivate::emitValueChanged()
   245 {
   246 {
   246     Q_Q(QDeclarativeBinding);
   247     Q_Q(QDeclarativeBinding);
   248 }
   249 }
   249 
   250 
   250 void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
   251 void QDeclarativeBinding::setEnabled(bool e, QDeclarativePropertyPrivate::WriteFlags flags)
   251 {
   252 {
   252     Q_D(QDeclarativeBinding);
   253     Q_D(QDeclarativeBinding);
   253     d->bindingData()->enabled = e;
   254     d->enabled = e;
   254     setNotifyOnValueChanged(e);
   255     setNotifyOnValueChanged(e);
   255 
   256 
   256     QDeclarativeAbstractBinding::setEnabled(e, flags);
   257     QDeclarativeAbstractBinding::setEnabled(e, flags);
   257 
   258 
   258     if (e) {
   259     if (e) {
   259         addToObject(d->bindingData()->property.object());
   260         addToObject(d->property.object());
   260         update(flags);
   261         update(flags);
   261     } else {
   262     } else {
   262         removeFromObject();
   263         removeFromObject();
   263     }
   264     }
   264 }
   265 }
   265 
   266 
   266 int QDeclarativeBinding::propertyIndex()
   267 int QDeclarativeBinding::propertyIndex()
   267 {
   268 {
   268     Q_D(QDeclarativeBinding);
   269     Q_D(QDeclarativeBinding);
   269     return QDeclarativePropertyPrivate::bindingIndex(d->bindingData()->property);
   270     return QDeclarativePropertyPrivate::bindingIndex(d->property);
   270 }
   271 }
   271 
   272 
   272 bool QDeclarativeBinding::enabled() const
   273 bool QDeclarativeBinding::enabled() const
   273 {
   274 {
   274     Q_D(const QDeclarativeBinding);
   275     Q_D(const QDeclarativeBinding);
   275 
   276 
   276     return d->bindingData()->enabled;
   277     return d->enabled;
   277 }
   278 }
   278 
   279 
   279 QString QDeclarativeBinding::expression() const
   280 QString QDeclarativeBinding::expression() const
   280 {
   281 {
   281     return QDeclarativeExpression::expression();
   282     return QDeclarativeExpression::expression();