QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
QQmlContextData *ctxt, QObject *scope, const QString &expression,
const QString &fileName, quint16 line, quint16 column,
- const QString &handlerName)
+ const QString &handlerName,
+ const QString ¶meterString)
: QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable),
m_fileName(fileName),
m_line(line),
{
init(ctxt, scope);
m_handlerName = handlerName;
+ m_parameterString = parameterString;
m_expression = expression;
}
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
{
if (!m_expressionFunctionValid) {
-
- //TODO: look at using the property cache here (as in the compiler)
- // for further optimization
- QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
-
QString expression;
expression = QStringLiteral("(function ");
expression += m_handlerName;
expression += QLatin1Char('(');
- QString error;
-
- bool unnamedParameter = false;
- const QV4::IdentifierHash<bool> &illegalNames = ep->v8engine()->illegalNames();
-
- const QList<QByteArray> parameters = signal.parameterNames();
- for (int i = 0; i < parameters.count(); ++i) {
- if (i > 0)
- expression += QLatin1Char(',');
- const QByteArray ¶m = parameters.at(i);
- if (param.isEmpty())
- unnamedParameter = true;
- else if (unnamedParameter) {
- error = QCoreApplication::translate("QQmlRewrite", "Signal uses unnamed parameter followed by named parameter.");
- break;
- } else if (illegalNames.contains(param)) {
- error = QCoreApplication::translate("QQmlRewrite", "Signal parameter \"%1\" hides global variable.").arg(QString::fromUtf8(param));
- break;
+ if (m_parameterString.isEmpty()) {
+ QString error;
+ //TODO: look at using the property cache here (as in the compiler)
+ // for further optimization
+ QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
+ expression += QQmlPropertyCache::signalParameterStringForJS(engine(), signal.parameterNames(), &error);
+
+ if (!error.isEmpty()) {
+ qmlInfo(scopeObject()) << error;
+ m_invalidParameterName = true;
+ ep->dereferenceScarceResources();
+ return;
}
- expression += QString::fromUtf8(param);
- }
-
- if (!error.isEmpty()) {
- qmlInfo(scopeObject()) << error;
- m_invalidParameterName = true;
- ep->dereferenceScarceResources();
- return;
- }
+ } else
+ expression += m_parameterString;
expression += QStringLiteral(") { ");
expression += m_expression;
expression += QStringLiteral(" })");
+
m_expression.clear();
+ m_handlerName.clear();
+ m_parameterString.clear();
m_v8function = evalFunction(context(), scopeObject(), expression,
m_fileName, m_line, &m_v8qmlscope);
QQmlBoundSignalExpression(QObject *target, int index,
QQmlContextData *ctxt, QObject *scope, const QString &expression,
const QString &fileName, quint16 line, quint16 column,
- const QString &handlerName = QString());
+ const QString &handlerName = QString(),
+ const QString ¶meterString = QString());
// "inherited" from QQmlJavaScriptExpression.
QV4::PersistentValue m_v8function;
QString m_handlerName;
+ QString m_parameterString;
//once m_v8function is valid, we clear expression and
//extract it from m_v8function if needed.
QString m_expression; //only used when expression needs to be rewritten
Instruction::StoreSignal store;
store.handlerName = output->indexForString(prop->name().toString());
+ store.parameters = output->indexForString(obj->metatype->signalParameterStringForJS(prop->index));
store.signalIndex = prop->index;
store.value = output->indexForString(v->value.asScript());
store.context = v->signalExpressionContextStack;
//to ensure all parameters are available (see qqmlboundsignal constructor for more details)
prop->index = obj->metatype->originalClone(prop->index);
prop->values.first()->signalExpressionContextStack = ctxt.stack;
+
+ QString errorString;
+ obj->metatype->signalParameterStringForJS(prop->index, &errorString);
+ if (!errorString.isEmpty())
+ COMPILE_EXCEPTION(prop, errorString);
}
}
struct instr_storeSignal {
QML_INSTR_HEADER
int handlerName;
+ int parameters;
int signalIndex;
int value;
short context;
//for signal handler rewrites
QString *signalParameterStringForJS;
- int signalParameterCountForJS:30;
int parameterError:1;
int argumentsValid:1;
args->arguments[0] = argc;
args->argumentsValid = false;
args->signalParameterStringForJS = 0;
- args->signalParameterCountForJS = 0;
args->parameterError = false;
args->names = argc ? new QList<QByteArray>(names) : 0;
args->next = argumentsCache;
return args;
}
+/*! \internal
+ \a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
+ This is different from QMetaMethod::methodIndex().
+*/
+QString QQmlPropertyCache::signalParameterStringForJS(int index, QString *errorString)
+{
+ QQmlPropertyCache *c = 0;
+ QQmlPropertyData *signalData = signal(index, &c);
+ if (!signalData)
+ return QString();
+
+ typedef QQmlPropertyCacheMethodArguments A;
+
+ if (signalData->arguments) {
+ A *arguments = static_cast<A *>(signalData->arguments);
+ if (arguments->signalParameterStringForJS) {
+ if (arguments->parameterError) {
+ if (errorString)
+ *errorString = *arguments->signalParameterStringForJS;
+ return QString();
+ }
+ return *arguments->signalParameterStringForJS;
+ }
+ }
+
+ QList<QByteArray> parameterNameList = signalParameterNames(index);
+
+ if (!signalData->arguments) {
+ A *args = c->createArgumentsObject(parameterNameList.count(), parameterNameList);
+ signalData->arguments = args;
+ }
+
+ QString error;
+ QString parameters = signalParameterStringForJS(engine, parameterNameList, &error);
+
+ A *arguments = static_cast<A *>(signalData->arguments);
+ arguments->signalParameterStringForJS = new QString(!error.isEmpty() ? error : parameters);
+ if (!error.isEmpty()) {
+ arguments->parameterError = true;
+ if (errorString)
+ *errorString = *arguments->signalParameterStringForJS;
+ return QString();
+ }
+ return *arguments->signalParameterStringForJS;
+}
+
+QString QQmlPropertyCache::signalParameterStringForJS(QQmlEngine *engine, const QList<QByteArray> ¶meterNameList, QString *errorString)
+{
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ bool unnamedParameter = false;
+ const QV4::IdentifierHash<bool> &illegalNames = ep->v8engine()->illegalNames();
+ QString error;
+ QString parameters;
+
+ for (int i = 0; i < parameterNameList.count(); ++i) {
+ if (i > 0)
+ parameters += QLatin1Char(',');
+ const QByteArray ¶m = parameterNameList.at(i);
+ if (param.isEmpty())
+ unnamedParameter = true;
+ else if (unnamedParameter) {
+ if (errorString)
+ *errorString = QCoreApplication::translate("QQmlRewrite", "Signal uses unnamed parameter followed by named parameter.");
+ return QString();
+ } else if (illegalNames.contains(param)) {
+ if (errorString)
+ *errorString = QCoreApplication::translate("QQmlRewrite", "Signal parameter \"%1\" hides global variable.").arg(QString::fromUtf8(param));
+ return QString();
+ }
+ parameters += QString::fromUtf8(param);
+ }
+
+ return parameters;
+}
+
// Returns an array of the arguments for method \a index. The first entry in the array
// is the number of arguments.
int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
static int originalClone(QObject *, int index);
QList<QByteArray> signalParameterNames(int index) const;
+ QString signalParameterStringForJS(int index, QString *errorString = 0);
+ static QString signalParameterStringForJS(QQmlEngine *engine, const QList<QByteArray> ¶meterNameList, QString *errorString = 0);
const char *className() const;
new QQmlBoundSignalExpression(target, instr.signalIndex,
CTXT, context, PRIMITIVES.at(instr.value),
COMP->name, instr.line, instr.column,
- PRIMITIVES.at(instr.handlerName));
+ PRIMITIVES.at(instr.handlerName),
+ PRIMITIVES.at(instr.parameters));
bs->takeExpression(expr);
QML_END_INSTR(StoreSignal)