diff options
author | Chris Adams <christopher.adams@nokia.com> | 2012-07-13 15:53:04 +1000 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2012-08-08 06:04:03 +0200 |
commit | 92562eacbc3c614a83a734f1108ed7df02415eae (patch) | |
tree | 05fc063849e032cb03e4f919811d8ea4da147773 /src/qml | |
parent | b2120f68683b7948891d72fe077f44ab7e6baf18 (diff) |
Allow signal parameters which are custom QML object-types
This commit allows lazy resolution of signal parameter types, which
allows QML object types to be used as signal parameters. If a signal
is emitted with an incorrect parameter type, it will be passed through
as a null parameter.
Task-number: QTBUG-14550
Change-Id: I7e899ad57452826cc405bed10c541f8d35789d04
Reviewed-by: Martin Jones <martin.jones@nokia.com>
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/qml/qqmlboundsignal.cpp | 9 | ||||
-rw-r--r-- | src/qml/qml/qqmlcompiler.cpp | 30 | ||||
-rw-r--r-- | src/qml/qml/qqmlscript.cpp | 37 | ||||
-rw-r--r-- | src/qml/qml/qqmlscript_p.h | 1 |
4 files changed, 62 insertions, 15 deletions
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index 6c4465eb96..5f5e7b09af 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -186,7 +186,7 @@ class QQmlBoundSignalParameters : public QObject { Q_OBJECT public: - QQmlBoundSignalParameters(const QMetaMethod &, QQmlAbstractBoundSignal*); + QQmlBoundSignalParameters(const QMetaMethod &, QQmlAbstractBoundSignal*, QQmlEngine*); ~QQmlBoundSignalParameters(); void setValues(void **); @@ -344,7 +344,7 @@ void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a) QList<QByteArray> names = QQmlPropertyCache::signalParameterNames(*s->m_scope, s->m_index); if (!names.isEmpty()) { QMetaMethod signal = QMetaObjectPrivate::signal(s->m_scope->metaObject(), s->m_index); - s->m_params = new QQmlBoundSignalParameters(signal, s); + s->m_params = new QQmlBoundSignalParameters(signal, s, s->m_expression->engine()); } s->setParamsValid(true); @@ -364,7 +364,8 @@ void QQmlBoundSignal_callback(QQmlNotifierEndpoint *e, void **a) } QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method, - QQmlAbstractBoundSignal *owner) + QQmlAbstractBoundSignal *owner, + QQmlEngine *engine) : types(0), values(0) { MetaObject *mo = new MetaObject(this); @@ -389,7 +390,7 @@ QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method, name = "__qt_anonymous_param_" + QByteArray::number(ii); int t = QMetaType::type(type.constData()); - if (QQmlMetaType::isQObject(t)) { + if (QQmlEnginePrivate::get(engine)->isQObject(t)) { types[ii] = QMetaType::QObjectStar; QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*"); prop.setWritable(false); diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index 453ee0841b..af8448001e 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -2978,9 +2978,33 @@ bool QQmlCompiler::buildDynamicMeta(QQmlScript::Object *obj, DynamicMetaMode mod paramTypes[0] = paramCount; for (int i = 0; i < paramCount; ++i) { - Q_ASSERT(s->parameterTypes.at(i) < builtinTypeCount); - paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType; - names.append(s->parameterNames.at(i).toString().toUtf8()); + if (s->parameterTypes.at(i) < builtinTypeCount) { + // built-in type + paramTypes[i + 1] = builtinTypes[s->parameterTypes.at(i)].metaType; + names.append(s->parameterNames.at(i).toString().toUtf8()); + } else { + // lazily resolved type + Q_ASSERT(s->parameterTypes.at(i) == Object::DynamicProperty::Custom); + QQmlType *qmltype = 0; + QString url; + if (!unit->imports().resolveType(s->parameterTypeNames.at(i).toString(), &qmltype, &url, 0, 0, 0)) + COMPILE_EXCEPTION(s, tr("Invalid signal parameter type: %1").arg(s->parameterTypeNames.at(i).toString())); + + if (!qmltype) { + QQmlTypeData *tdata = enginePrivate->typeLoader.getType(QUrl(url)); + Q_ASSERT(tdata); + Q_ASSERT(tdata->isComplete()); + + QQmlCompiledData *data = tdata->compiledData(); + + paramTypes[i + 1] = data->metaTypeId; + + tdata->release(); + } else { + paramTypes[i + 1] = qmltype->typeId(); + } + names.append(s->parameterNames.at(i).toString().toUtf8()); + } } } diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp index a237f9a2f8..985b6b6181 100644 --- a/src/qml/qml/qqmlscript.cpp +++ b/src/qml/qml/qqmlscript.cpp @@ -937,6 +937,7 @@ bool ProcessAST::visit(AST::UiPublicMember *node) if (paramLength) { signal->parameterTypes = _parser->_pool.NewRawList<Object::DynamicProperty::Type>(paramLength); + signal->parameterTypeNames = _parser->_pool.NewRawList<QHashedStringRef>(paramLength); signal->parameterNames = _parser->_pool.NewRawList<QHashedStringRef>(paramLength); } @@ -944,6 +945,15 @@ bool ProcessAST::visit(AST::UiPublicMember *node) while (p) { const QStringRef &memberType = p->type; + if (memberType.isEmpty()) { + QQmlError error; + error.setDescription(QCoreApplication::translate("QQmlParser","Expected parameter type")); + error.setLine(node->typeToken.startLine); + error.setColumn(node->typeToken.startColumn); + _parser->_errors << error; + return false; + } + const TypeNameToType *type = 0; for(int typeIndex = 0; typeIndex < propTypeNameToTypesCount; ++typeIndex) { const TypeNameToType *t = propTypeNameToTypes + typeIndex; @@ -955,15 +965,26 @@ bool ProcessAST::visit(AST::UiPublicMember *node) } if (!type) { - QQmlError error; - error.setDescription(QCoreApplication::translate("QQmlParser","Expected parameter type")); - error.setLine(node->typeToken.startLine); - error.setColumn(node->typeToken.startColumn); - _parser->_errors << error; - return false; + if (memberType.at(0).isUpper()) { + // Must be a QML object type. + // Lazily determine type during compilation. + signal->parameterTypes[index] = Object::DynamicProperty::Custom; + signal->parameterTypeNames[index] = QHashedStringRef(p->type); + } else { + QQmlError error; + QString errStr = QCoreApplication::translate("QQmlParser","Invalid signal parameter type: "); + errStr.append(memberType.toString()); + error.setDescription(errStr); + error.setLine(node->typeToken.startLine); + error.setColumn(node->typeToken.startColumn); + _parser->_errors << error; + return false; + } + } else { + // the parameter is a known basic type + signal->parameterTypes[index] = type->type; } - - signal->parameterTypes[index] = type->type; + signal->parameterNames[index] = QHashedStringRef(p->name); p = p->next; index++; diff --git a/src/qml/qml/qqmlscript_p.h b/src/qml/qml/qqmlscript_p.h index e08afa8ee3..60e667e4ea 100644 --- a/src/qml/qml/qqmlscript_p.h +++ b/src/qml/qml/qqmlscript_p.h @@ -409,6 +409,7 @@ public: QHashedStringRef name; QQmlPool::List<DynamicProperty::Type> parameterTypes; + QQmlPool::List<QHashedStringRef> parameterTypeNames; QQmlPool::List<QHashedStringRef> parameterNames; // Used by Object::DynamicSignalList |