1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** Contact: Qt Software Information ([email protected])
|
---|
5 | **
|
---|
6 | ** This file is part of the QtScript module of the Qt Toolkit.
|
---|
7 | **
|
---|
8 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
9 | ** Commercial Usage
|
---|
10 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
11 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
12 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
13 | ** a written agreement between you and Nokia.
|
---|
14 | **
|
---|
15 | ** GNU Lesser General Public License Usage
|
---|
16 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
17 | ** General Public License version 2.1 as published by the Free Software
|
---|
18 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
19 | ** packaging of this file. Please review the following information to
|
---|
20 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
21 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
22 | **
|
---|
23 | ** In addition, as a special exception, Nokia gives you certain
|
---|
24 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
---|
25 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
---|
26 | ** package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you are unsure which license is appropriate for your use, please
|
---|
37 | ** contact the sales department at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include <QtCore/qglobal.h>
|
---|
43 |
|
---|
44 | #ifndef QT_NO_SCRIPT
|
---|
45 |
|
---|
46 | #include "qscriptengine_p.h"
|
---|
47 | #include "qscriptvalueimpl_p.h"
|
---|
48 | #include "qscriptcontext_p.h"
|
---|
49 | #include "qscriptmember_p.h"
|
---|
50 | #include "qscriptobject_p.h"
|
---|
51 | #include "qscriptable.h"
|
---|
52 | #include "qscriptable_p.h"
|
---|
53 | #include "qscriptextqobject_p.h"
|
---|
54 |
|
---|
55 | #include <QtCore/QtDebug>
|
---|
56 | #include <QtCore/QMetaMethod>
|
---|
57 | #include <QtCore/QRegExp>
|
---|
58 | #include <QtCore/QVarLengthArray>
|
---|
59 | #include <QtCore/QPointer>
|
---|
60 |
|
---|
61 | QT_BEGIN_NAMESPACE
|
---|
62 |
|
---|
63 | // we use bits 15..12 of property flags
|
---|
64 | enum {
|
---|
65 | PROPERTY_ID = 0 << 12,
|
---|
66 | DYNAPROPERTY_ID = 1 << 12,
|
---|
67 | METHOD_ID = 2 << 12,
|
---|
68 | CHILD_ID = 3 << 12,
|
---|
69 | ID_MASK = 7 << 12,
|
---|
70 | MAYBE_OVERLOADED = 8 << 12
|
---|
71 | };
|
---|
72 |
|
---|
73 | static const bool GeneratePropertyFunctions = true;
|
---|
74 |
|
---|
75 | int QScriptMetaType::typeId() const
|
---|
76 | {
|
---|
77 | if (isVariant())
|
---|
78 | return QMetaType::type("QVariant");
|
---|
79 | return isMetaEnum() ? 2/*int*/ : m_typeId;
|
---|
80 | }
|
---|
81 |
|
---|
82 | QByteArray QScriptMetaType::name() const
|
---|
83 | {
|
---|
84 | if (!m_name.isEmpty())
|
---|
85 | return m_name;
|
---|
86 | else if (m_kind == Variant)
|
---|
87 | return "QVariant";
|
---|
88 | return QMetaType::typeName(typeId());
|
---|
89 | }
|
---|
90 |
|
---|
91 | namespace QScript {
|
---|
92 |
|
---|
93 | class QObjectNotifyCaller : public QObject
|
---|
94 | {
|
---|
95 | public:
|
---|
96 | void callConnectNotify(const char *signal)
|
---|
97 | { connectNotify(signal); }
|
---|
98 | void callDisconnectNotify(const char *signal)
|
---|
99 | { disconnectNotify(signal); }
|
---|
100 | };
|
---|
101 |
|
---|
102 | class QtPropertyFunction: public QScriptFunction
|
---|
103 | {
|
---|
104 | public:
|
---|
105 | QtPropertyFunction(const QMetaObject *meta, int index)
|
---|
106 | : m_meta(meta), m_index(index)
|
---|
107 | { }
|
---|
108 |
|
---|
109 | ~QtPropertyFunction() { }
|
---|
110 |
|
---|
111 | virtual void execute(QScriptContextPrivate *context);
|
---|
112 |
|
---|
113 | virtual Type type() const { return QScriptFunction::QtProperty; }
|
---|
114 |
|
---|
115 | virtual QString functionName() const;
|
---|
116 |
|
---|
117 | private:
|
---|
118 | const QMetaObject *m_meta;
|
---|
119 | int m_index;
|
---|
120 | };
|
---|
121 |
|
---|
122 | class QObjectPrototype : public QObject
|
---|
123 | {
|
---|
124 | Q_OBJECT
|
---|
125 | public:
|
---|
126 | QObjectPrototype(QObject *parent = 0)
|
---|
127 | : QObject(parent) { }
|
---|
128 | ~QObjectPrototype() { }
|
---|
129 | };
|
---|
130 |
|
---|
131 | static inline QByteArray methodName(const QMetaMethod &method)
|
---|
132 | {
|
---|
133 | QByteArray signature = method.signature();
|
---|
134 | return signature.left(signature.indexOf('('));
|
---|
135 | }
|
---|
136 |
|
---|
137 | static inline QVariant variantFromValue(QScriptEnginePrivate *eng,
|
---|
138 | int targetType, const QScriptValueImpl &value)
|
---|
139 | {
|
---|
140 | QVariant v(targetType, (void *)0);
|
---|
141 | Q_ASSERT(eng);
|
---|
142 | if (QScriptEnginePrivate::convert(value, targetType, v.data(), eng))
|
---|
143 | return v;
|
---|
144 | if (uint(targetType) == QVariant::LastType)
|
---|
145 | return value.toVariant();
|
---|
146 | if (value.isVariant()) {
|
---|
147 | v = value.toVariant();
|
---|
148 | if (v.canConvert(QVariant::Type(targetType))) {
|
---|
149 | v.convert(QVariant::Type(targetType));
|
---|
150 | return v;
|
---|
151 | }
|
---|
152 | QByteArray typeName = v.typeName();
|
---|
153 | if (typeName.endsWith('*')
|
---|
154 | && (QMetaType::type(typeName.left(typeName.size()-1)) == targetType)) {
|
---|
155 | return QVariant(targetType, *reinterpret_cast<void* *>(v.data()));
|
---|
156 | }
|
---|
157 | }
|
---|
158 |
|
---|
159 | return QVariant();
|
---|
160 | }
|
---|
161 |
|
---|
162 | void ExtQObject::Instance::finalize(QScriptEnginePrivate *eng)
|
---|
163 | {
|
---|
164 | switch (ownership) {
|
---|
165 | case QScriptEngine::QtOwnership:
|
---|
166 | break;
|
---|
167 | case QScriptEngine::ScriptOwnership:
|
---|
168 | if (value)
|
---|
169 | eng->disposeQObject(value);
|
---|
170 | break;
|
---|
171 | case QScriptEngine::AutoOwnership:
|
---|
172 | if (value && !value->parent())
|
---|
173 | eng->disposeQObject(value);
|
---|
174 | break;
|
---|
175 | }
|
---|
176 | }
|
---|
177 |
|
---|
178 | ExtQObject::Instance *ExtQObject::Instance::get(const QScriptValueImpl &object, QScriptClassInfo *klass)
|
---|
179 | {
|
---|
180 | if (! klass || klass == object.classInfo())
|
---|
181 | return static_cast<Instance*> (object.objectData());
|
---|
182 |
|
---|
183 | return 0;
|
---|
184 | }
|
---|
185 |
|
---|
186 |
|
---|
187 | static inline QScriptable *scriptableFromQObject(QObject *qobj)
|
---|
188 | {
|
---|
189 | void *ptr = qobj->qt_metacast("QScriptable");
|
---|
190 | return reinterpret_cast<QScriptable*>(ptr);
|
---|
191 | }
|
---|
192 |
|
---|
193 | static bool isObjectProperty(const QScriptValueImpl &object, const char *name)
|
---|
194 | {
|
---|
195 | QScriptEnginePrivate *eng = object.engine();
|
---|
196 | QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name));
|
---|
197 | QScript::Member member;
|
---|
198 | QScriptValueImpl base;
|
---|
199 | return object.resolve(nameId, &member, &base, QScriptValue::ResolveLocal, QScript::Read)
|
---|
200 | && member.testFlags(QScript::Member::ObjectProperty);
|
---|
201 | }
|
---|
202 |
|
---|
203 | static bool hasMethodAccess(const QMetaMethod &method, int index, const QScriptEngine::QObjectWrapOptions &opt)
|
---|
204 | {
|
---|
205 | return (method.access() != QMetaMethod::Private)
|
---|
206 | && ((index != 2) || !(opt & QScriptEngine::ExcludeDeleteLater));
|
---|
207 | }
|
---|
208 |
|
---|
209 | static bool isEnumerableMetaProperty(const QMetaProperty &prop,
|
---|
210 | const QMetaObject *mo, int index)
|
---|
211 | {
|
---|
212 | return prop.isScriptable() && prop.isValid()
|
---|
213 | // the following lookup is to ensure that we have the
|
---|
214 | // "most derived" occurrence of the property with this name
|
---|
215 | && (mo->indexOfProperty(prop.name()) == index);
|
---|
216 | }
|
---|
217 |
|
---|
218 | static uint flagsForMetaProperty(const QMetaProperty &prop)
|
---|
219 | {
|
---|
220 | return (QScriptValue::Undeletable
|
---|
221 | | (!prop.isWritable()
|
---|
222 | ? QScriptValue::ReadOnly
|
---|
223 | : QScriptValue::PropertyFlag(0))
|
---|
224 | | (GeneratePropertyFunctions
|
---|
225 | ? (QScriptValue::PropertyGetter
|
---|
226 | | QScriptValue::PropertySetter)
|
---|
227 | : QScriptValue::PropertyFlag(0))
|
---|
228 | | QScriptValue::QObjectMember
|
---|
229 | | PROPERTY_ID);
|
---|
230 | }
|
---|
231 |
|
---|
232 |
|
---|
233 | static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
|
---|
234 | {
|
---|
235 | QByteArray scope;
|
---|
236 | QByteArray name;
|
---|
237 | int scopeIdx = str.lastIndexOf("::");
|
---|
238 | if (scopeIdx != -1) {
|
---|
239 | scope = str.left(scopeIdx);
|
---|
240 | name = str.mid(scopeIdx + 2);
|
---|
241 | } else {
|
---|
242 | name = str;
|
---|
243 | }
|
---|
244 | for (int i = meta->enumeratorCount() - 1; i >= 0; --i) {
|
---|
245 | QMetaEnum m = meta->enumerator(i);
|
---|
246 | if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope)))
|
---|
247 | return i;
|
---|
248 | }
|
---|
249 | return -1;
|
---|
250 | }
|
---|
251 |
|
---|
252 | static QMetaMethod metaMethod(const QMetaObject *meta,
|
---|
253 | QMetaMethod::MethodType type,
|
---|
254 | int index)
|
---|
255 | {
|
---|
256 | if (type != QMetaMethod::Constructor)
|
---|
257 | return meta->method(index);
|
---|
258 | else
|
---|
259 | return meta->constructor(index);
|
---|
260 | }
|
---|
261 |
|
---|
262 | static void callQtMethod(QScriptContextPrivate *context, QMetaMethod::MethodType callType,
|
---|
263 | QObject *thisQObject, const QMetaObject *meta, int initialIndex,
|
---|
264 | bool maybeOverloaded)
|
---|
265 | {
|
---|
266 | QScriptValueImpl result;
|
---|
267 | QScriptEnginePrivate *engine = context->engine();
|
---|
268 |
|
---|
269 | int limit;
|
---|
270 | #ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
|
---|
271 | int lastFoundIndex = initialIndex;
|
---|
272 | QScriptMetaObject *metaCache = engine->cachedMetaObject(meta);
|
---|
273 | if (callType != QMetaMethod::Constructor)
|
---|
274 | limit = metaCache->methodLowerBound(initialIndex);
|
---|
275 | else
|
---|
276 | limit = 0;
|
---|
277 | #else
|
---|
278 | limit = 0;
|
---|
279 | #endif
|
---|
280 |
|
---|
281 | QByteArray funName;
|
---|
282 | QScriptMetaMethod chosenMethod;
|
---|
283 | int chosenIndex = -1;
|
---|
284 | QVarLengthArray<QVariant, 9> args;
|
---|
285 | QVector<QScriptMetaArguments> candidates;
|
---|
286 | QVector<QScriptMetaArguments> unresolved;
|
---|
287 | QVector<int> tooFewArgs;
|
---|
288 | QVector<int> conversionFailed;
|
---|
289 | int index;
|
---|
290 | for (index = initialIndex; index >= limit; --index) {
|
---|
291 | QScriptMetaMethod mtd;
|
---|
292 | #ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
|
---|
293 | if (callType != QMetaMethod::Constructor)
|
---|
294 | mtd = metaCache->findMethod(index);
|
---|
295 | if (!mtd.isValid())
|
---|
296 | #endif
|
---|
297 | {
|
---|
298 | QMetaMethod method = metaMethod(meta, callType, index);
|
---|
299 |
|
---|
300 | QVector<QScriptMetaType> types;
|
---|
301 | // resolve return type
|
---|
302 | QByteArray returnTypeName = method.typeName();
|
---|
303 | int rtype = QMetaType::type(returnTypeName);
|
---|
304 | if ((rtype == 0) && !returnTypeName.isEmpty()) {
|
---|
305 | if (returnTypeName == "QVariant") {
|
---|
306 | types.append(QScriptMetaType::variant());
|
---|
307 | } else {
|
---|
308 | int enumIndex = indexOfMetaEnum(meta, returnTypeName);
|
---|
309 | if (enumIndex != -1)
|
---|
310 | types.append(QScriptMetaType::metaEnum(enumIndex, returnTypeName));
|
---|
311 | else
|
---|
312 | types.append(QScriptMetaType::unresolved(returnTypeName));
|
---|
313 | }
|
---|
314 | } else {
|
---|
315 | if (callType == QMetaMethod::Constructor)
|
---|
316 | types.append(QScriptMetaType::metaType(QMetaType::QObjectStar, "QObject*"));
|
---|
317 | else if (returnTypeName == "QVariant")
|
---|
318 | types.append(QScriptMetaType::variant());
|
---|
319 | else
|
---|
320 | types.append(QScriptMetaType::metaType(rtype, returnTypeName));
|
---|
321 | }
|
---|
322 | // resolve argument types
|
---|
323 | QList<QByteArray> parameterTypeNames = method.parameterTypes();
|
---|
324 | for (int i = 0; i < parameterTypeNames.count(); ++i) {
|
---|
325 | QByteArray argTypeName = parameterTypeNames.at(i);
|
---|
326 | int atype = QMetaType::type(argTypeName);
|
---|
327 | if (atype == 0) {
|
---|
328 | if (argTypeName == "QVariant") {
|
---|
329 | types.append(QScriptMetaType::variant());
|
---|
330 | } else {
|
---|
331 | int enumIndex = indexOfMetaEnum(meta, argTypeName);
|
---|
332 | if (enumIndex != -1)
|
---|
333 | types.append(QScriptMetaType::metaEnum(enumIndex, argTypeName));
|
---|
334 | else
|
---|
335 | types.append(QScriptMetaType::unresolved(argTypeName));
|
---|
336 | }
|
---|
337 | } else {
|
---|
338 | if (argTypeName == "QVariant")
|
---|
339 | types.append(QScriptMetaType::variant());
|
---|
340 | else
|
---|
341 | types.append(QScriptMetaType::metaType(atype, argTypeName));
|
---|
342 | }
|
---|
343 | }
|
---|
344 |
|
---|
345 | mtd = QScriptMetaMethod(methodName(method), types);
|
---|
346 |
|
---|
347 | #ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
|
---|
348 | if (mtd.fullyResolved() && (callType != QMetaMethod::Constructor))
|
---|
349 | metaCache->registerMethod(index, mtd);
|
---|
350 | #endif
|
---|
351 | }
|
---|
352 |
|
---|
353 | if (index == initialIndex)
|
---|
354 | funName = mtd.name();
|
---|
355 | else {
|
---|
356 | if (mtd.name() != funName)
|
---|
357 | continue;
|
---|
358 | #ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
|
---|
359 | lastFoundIndex = index;
|
---|
360 | #endif
|
---|
361 | }
|
---|
362 |
|
---|
363 | if (context->argumentCount() < mtd.argumentCount()) {
|
---|
364 | tooFewArgs.append(index);
|
---|
365 | continue;
|
---|
366 | }
|
---|
367 |
|
---|
368 | if (!mtd.fullyResolved()) {
|
---|
369 | // remember it so we can give an error message later, if necessary
|
---|
370 | unresolved.append(QScriptMetaArguments(/*matchDistance=*/INT_MAX, index,
|
---|
371 | mtd, QVarLengthArray<QVariant, 9>()));
|
---|
372 | if (mtd.hasUnresolvedReturnType())
|
---|
373 | continue;
|
---|
374 | }
|
---|
375 |
|
---|
376 | if (args.count() != mtd.count())
|
---|
377 | args.resize(mtd.count());
|
---|
378 |
|
---|
379 | QScriptMetaType retType = mtd.returnType();
|
---|
380 | args[0] = QVariant(retType.typeId(), (void *)0); // the result
|
---|
381 |
|
---|
382 | // try to convert arguments
|
---|
383 | bool converted = true;
|
---|
384 | int matchDistance = 0;
|
---|
385 | for (int i = 0; converted && i < mtd.argumentCount(); ++i) {
|
---|
386 | QScriptValueImpl actual = context->argument(i);
|
---|
387 | QScriptMetaType argType = mtd.argumentType(i);
|
---|
388 | int tid = -1;
|
---|
389 | QVariant v;
|
---|
390 | if (argType.isUnresolved()) {
|
---|
391 | v = QVariant(QMetaType::QObjectStar, (void *)0);
|
---|
392 | converted = engine->convertToNativeQObject(
|
---|
393 | actual, argType.name(), reinterpret_cast<void* *>(v.data()));
|
---|
394 | } else if (argType.isVariant()) {
|
---|
395 | if (actual.isVariant()) {
|
---|
396 | v = actual.variantValue();
|
---|
397 | } else {
|
---|
398 | v = actual.toVariant();
|
---|
399 | converted = v.isValid() || actual.isUndefined() || actual.isNull();
|
---|
400 | }
|
---|
401 | } else {
|
---|
402 | tid = argType.typeId();
|
---|
403 | v = QVariant(tid, (void *)0);
|
---|
404 | converted = QScriptEnginePrivate::convert(actual, tid, v.data(), engine);
|
---|
405 | if (engine->hasUncaughtException())
|
---|
406 | return;
|
---|
407 | }
|
---|
408 |
|
---|
409 | if (!converted) {
|
---|
410 | if (actual.isVariant()) {
|
---|
411 | if (tid == -1)
|
---|
412 | tid = argType.typeId();
|
---|
413 | QVariant &vv = actual.variantValue();
|
---|
414 | if (vv.canConvert(QVariant::Type(tid))) {
|
---|
415 | v = vv;
|
---|
416 | converted = v.convert(QVariant::Type(tid));
|
---|
417 | if (converted && (vv.userType() != tid))
|
---|
418 | matchDistance += 10;
|
---|
419 | } else {
|
---|
420 | QByteArray vvTypeName = vv.typeName();
|
---|
421 | if (vvTypeName.endsWith('*')
|
---|
422 | && (vvTypeName.left(vvTypeName.size()-1) == argType.name())) {
|
---|
423 | v = QVariant(tid, *reinterpret_cast<void* *>(vv.data()));
|
---|
424 | converted = true;
|
---|
425 | matchDistance += 10;
|
---|
426 | }
|
---|
427 | }
|
---|
428 | } else if (actual.isNumber()) {
|
---|
429 | // see if it's an enum value
|
---|
430 | QMetaEnum m;
|
---|
431 | if (argType.isMetaEnum()) {
|
---|
432 | m = meta->enumerator(argType.enumeratorIndex());
|
---|
433 | } else {
|
---|
434 | int mi = indexOfMetaEnum(meta, argType.name());
|
---|
435 | if (mi != -1)
|
---|
436 | m = meta->enumerator(mi);
|
---|
437 | }
|
---|
438 | if (m.isValid()) {
|
---|
439 | int ival = actual.toInt32();
|
---|
440 | if (m.valueToKey(ival) != 0) {
|
---|
441 | qVariantSetValue(v, ival);
|
---|
442 | converted = true;
|
---|
443 | matchDistance += 10;
|
---|
444 | }
|
---|
445 | }
|
---|
446 | }
|
---|
447 | } else {
|
---|
448 | // determine how well the conversion matched
|
---|
449 | if (actual.isNumber()) {
|
---|
450 | switch (tid) {
|
---|
451 | case QMetaType::Double:
|
---|
452 | // perfect
|
---|
453 | break;
|
---|
454 | case QMetaType::Float:
|
---|
455 | matchDistance += 1;
|
---|
456 | break;
|
---|
457 | case QMetaType::LongLong:
|
---|
458 | case QMetaType::ULongLong:
|
---|
459 | matchDistance += 2;
|
---|
460 | break;
|
---|
461 | case QMetaType::Long:
|
---|
462 | case QMetaType::ULong:
|
---|
463 | matchDistance += 3;
|
---|
464 | break;
|
---|
465 | case QMetaType::Int:
|
---|
466 | case QMetaType::UInt:
|
---|
467 | matchDistance += 4;
|
---|
468 | break;
|
---|
469 | case QMetaType::Short:
|
---|
470 | case QMetaType::UShort:
|
---|
471 | matchDistance += 5;
|
---|
472 | break;
|
---|
473 | case QMetaType::Char:
|
---|
474 | case QMetaType::UChar:
|
---|
475 | matchDistance += 6;
|
---|
476 | break;
|
---|
477 | default:
|
---|
478 | matchDistance += 10;
|
---|
479 | break;
|
---|
480 | }
|
---|
481 | } else if (actual.isString()) {
|
---|
482 | switch (tid) {
|
---|
483 | case QMetaType::QString:
|
---|
484 | // perfect
|
---|
485 | break;
|
---|
486 | default:
|
---|
487 | matchDistance += 10;
|
---|
488 | break;
|
---|
489 | }
|
---|
490 | } else if (actual.isBoolean()) {
|
---|
491 | switch (tid) {
|
---|
492 | case QMetaType::Bool:
|
---|
493 | // perfect
|
---|
494 | break;
|
---|
495 | default:
|
---|
496 | matchDistance += 10;
|
---|
497 | break;
|
---|
498 | }
|
---|
499 | } else if (actual.isDate()) {
|
---|
500 | switch (tid) {
|
---|
501 | case QMetaType::QDateTime:
|
---|
502 | // perfect
|
---|
503 | break;
|
---|
504 | case QMetaType::QDate:
|
---|
505 | matchDistance += 1;
|
---|
506 | break;
|
---|
507 | case QMetaType::QTime:
|
---|
508 | matchDistance += 2;
|
---|
509 | break;
|
---|
510 | default:
|
---|
511 | matchDistance += 10;
|
---|
512 | break;
|
---|
513 | }
|
---|
514 | } else if (actual.isRegExp()) {
|
---|
515 | switch (tid) {
|
---|
516 | case QMetaType::QRegExp:
|
---|
517 | // perfect
|
---|
518 | break;
|
---|
519 | default:
|
---|
520 | matchDistance += 10;
|
---|
521 | break;
|
---|
522 | }
|
---|
523 | } else if (actual.isVariant()) {
|
---|
524 | if (argType.isVariant()
|
---|
525 | || (actual.variantValue().userType() == tid)) {
|
---|
526 | // perfect
|
---|
527 | } else {
|
---|
528 | matchDistance += 10;
|
---|
529 | }
|
---|
530 | } else if (actual.isArray()) {
|
---|
531 | switch (tid) {
|
---|
532 | case QMetaType::QStringList:
|
---|
533 | case QMetaType::QVariantList:
|
---|
534 | matchDistance += 5;
|
---|
535 | break;
|
---|
536 | default:
|
---|
537 | matchDistance += 10;
|
---|
538 | break;
|
---|
539 | }
|
---|
540 | } else if (actual.isQObject()) {
|
---|
541 | switch (tid) {
|
---|
542 | case QMetaType::QObjectStar:
|
---|
543 | case QMetaType::QWidgetStar:
|
---|
544 | // perfect
|
---|
545 | break;
|
---|
546 | default:
|
---|
547 | matchDistance += 10;
|
---|
548 | break;
|
---|
549 | }
|
---|
550 | } else if (actual.isNull()) {
|
---|
551 | switch (tid) {
|
---|
552 | case QMetaType::VoidStar:
|
---|
553 | case QMetaType::QObjectStar:
|
---|
554 | case QMetaType::QWidgetStar:
|
---|
555 | // perfect
|
---|
556 | break;
|
---|
557 | default:
|
---|
558 | if (!argType.name().endsWith('*'))
|
---|
559 | matchDistance += 10;
|
---|
560 | break;
|
---|
561 | }
|
---|
562 | } else {
|
---|
563 | matchDistance += 10;
|
---|
564 | }
|
---|
565 | }
|
---|
566 |
|
---|
567 | if (converted)
|
---|
568 | args[i+1] = v;
|
---|
569 | }
|
---|
570 |
|
---|
571 | if (converted) {
|
---|
572 | if ((context->argumentCount() == mtd.argumentCount())
|
---|
573 | && (matchDistance == 0)) {
|
---|
574 | // perfect match, use this one
|
---|
575 | chosenMethod = mtd;
|
---|
576 | chosenIndex = index;
|
---|
577 | break;
|
---|
578 | } else {
|
---|
579 | bool redundant = false;
|
---|
580 | if ((callType != QMetaMethod::Constructor)
|
---|
581 | && (index < meta->methodOffset())) {
|
---|
582 | // it is possible that a virtual method is redeclared in a subclass,
|
---|
583 | // in which case we want to ignore the superclass declaration
|
---|
584 | for (int i = 0; i < candidates.size(); ++i) {
|
---|
585 | const QScriptMetaArguments &other = candidates.at(i);
|
---|
586 | if (mtd.types() == other.method.types()) {
|
---|
587 | redundant = true;
|
---|
588 | break;
|
---|
589 | }
|
---|
590 | }
|
---|
591 | }
|
---|
592 | if (!redundant) {
|
---|
593 | QScriptMetaArguments metaArgs(matchDistance, index, mtd, args);
|
---|
594 | if (candidates.isEmpty()) {
|
---|
595 | candidates.append(metaArgs);
|
---|
596 | } else {
|
---|
597 | const QScriptMetaArguments &otherArgs = candidates.at(0);
|
---|
598 | if ((args.count() > otherArgs.args.count())
|
---|
599 | || ((args.count() == otherArgs.args.count())
|
---|
600 | && (matchDistance <= otherArgs.matchDistance))) {
|
---|
601 | candidates.prepend(metaArgs);
|
---|
602 | } else {
|
---|
603 | candidates.append(metaArgs);
|
---|
604 | }
|
---|
605 | }
|
---|
606 | }
|
---|
607 | }
|
---|
608 | } else if (mtd.fullyResolved()) {
|
---|
609 | conversionFailed.append(index);
|
---|
610 | }
|
---|
611 |
|
---|
612 | if (!maybeOverloaded)
|
---|
613 | break;
|
---|
614 | }
|
---|
615 |
|
---|
616 | #ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
|
---|
617 | if ((index == -1) && (lastFoundIndex != limit) && maybeOverloaded
|
---|
618 | && (callType != QMetaMethod::Constructor)) {
|
---|
619 | metaCache->setMethodLowerBound(initialIndex, lastFoundIndex);
|
---|
620 | }
|
---|
621 | #endif
|
---|
622 |
|
---|
623 | if ((chosenIndex == -1) && candidates.isEmpty()) {
|
---|
624 | context->calleeMetaIndex = initialIndex;
|
---|
625 | #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
|
---|
626 | engine->notifyFunctionEntry(context);
|
---|
627 | #endif
|
---|
628 | if (!conversionFailed.isEmpty()) {
|
---|
629 | QString message = QString::fromLatin1("incompatible type of argument(s) in call to %0(); candidates were\n")
|
---|
630 | .arg(QLatin1String(funName));
|
---|
631 | for (int i = 0; i < conversionFailed.size(); ++i) {
|
---|
632 | if (i > 0)
|
---|
633 | message += QLatin1String("\n");
|
---|
634 | QMetaMethod mtd = metaMethod(meta, callType, conversionFailed.at(i));
|
---|
635 | message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
|
---|
636 | }
|
---|
637 | result = context->throwError(QScriptContext::TypeError, message);
|
---|
638 | } else if (!unresolved.isEmpty()) {
|
---|
639 | QScriptMetaArguments argsInstance = unresolved.first();
|
---|
640 | int unresolvedIndex = argsInstance.method.firstUnresolvedIndex();
|
---|
641 | Q_ASSERT(unresolvedIndex != -1);
|
---|
642 | QScriptMetaType unresolvedType = argsInstance.method.type(unresolvedIndex);
|
---|
643 | QString unresolvedTypeName = QString::fromLatin1(unresolvedType.name());
|
---|
644 | QString message = QString::fromLatin1("cannot call %0(): ")
|
---|
645 | .arg(QString::fromLatin1(funName));
|
---|
646 | if (unresolvedIndex > 0) {
|
---|
647 | message.append(QString::fromLatin1("argument %0 has unknown type `%1'").
|
---|
648 | arg(unresolvedIndex).arg(unresolvedTypeName));
|
---|
649 | } else {
|
---|
650 | message.append(QString::fromLatin1("unknown return type `%0'")
|
---|
651 | .arg(unresolvedTypeName));
|
---|
652 | }
|
---|
653 | message.append(QString::fromLatin1(" (register the type with qScriptRegisterMetaType())"));
|
---|
654 | result = context->throwError(QScriptContext::TypeError, message);
|
---|
655 | } else {
|
---|
656 | QString message = QString::fromLatin1("too few arguments in call to %0(); candidates are\n")
|
---|
657 | .arg(QLatin1String(funName));
|
---|
658 | for (int i = 0; i < tooFewArgs.size(); ++i) {
|
---|
659 | if (i > 0)
|
---|
660 | message += QLatin1String("\n");
|
---|
661 | QMetaMethod mtd = metaMethod(meta, callType, tooFewArgs.at(i));
|
---|
662 | message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
|
---|
663 | }
|
---|
664 | result = context->throwError(QScriptContext::SyntaxError, message);
|
---|
665 | }
|
---|
666 | } else {
|
---|
667 | if (chosenIndex == -1) {
|
---|
668 | QScriptMetaArguments metaArgs = candidates.at(0);
|
---|
669 | if ((candidates.size() > 1)
|
---|
670 | && (metaArgs.args.count() == candidates.at(1).args.count())
|
---|
671 | && (metaArgs.matchDistance == candidates.at(1).matchDistance)) {
|
---|
672 | // ambiguous call
|
---|
673 | QString message = QString::fromLatin1("ambiguous call of overloaded function %0(); candidates were\n")
|
---|
674 | .arg(QLatin1String(funName));
|
---|
675 | for (int i = 0; i < candidates.size(); ++i) {
|
---|
676 | if (i > 0)
|
---|
677 | message += QLatin1String("\n");
|
---|
678 | QMetaMethod mtd = metaMethod(meta, callType, candidates.at(i).index);
|
---|
679 | message += QString::fromLatin1(" %0").arg(QString::fromLatin1(mtd.signature()));
|
---|
680 | }
|
---|
681 | result = context->throwError(QScriptContext::TypeError, message);
|
---|
682 | } else {
|
---|
683 | chosenMethod = metaArgs.method;
|
---|
684 | chosenIndex = metaArgs.index;
|
---|
685 | args = metaArgs.args;
|
---|
686 | }
|
---|
687 | }
|
---|
688 |
|
---|
689 | if (chosenIndex != -1) {
|
---|
690 | // call it
|
---|
691 | context->calleeMetaIndex = chosenIndex;
|
---|
692 |
|
---|
693 | QVarLengthArray<void*, 9> array(args.count());
|
---|
694 | void **params = array.data();
|
---|
695 | for (int i = 0; i < args.count(); ++i) {
|
---|
696 | const QVariant &v = args[i];
|
---|
697 | switch (chosenMethod.type(i).kind()) {
|
---|
698 | case QScriptMetaType::Variant:
|
---|
699 | params[i] = const_cast<QVariant*>(&v);
|
---|
700 | break;
|
---|
701 | case QScriptMetaType::MetaType:
|
---|
702 | case QScriptMetaType::MetaEnum:
|
---|
703 | case QScriptMetaType::Unresolved:
|
---|
704 | params[i] = const_cast<void*>(v.constData());
|
---|
705 | break;
|
---|
706 | default:
|
---|
707 | Q_ASSERT(0);
|
---|
708 | }
|
---|
709 | }
|
---|
710 |
|
---|
711 | QScriptable *scriptable = 0;
|
---|
712 | if (thisQObject)
|
---|
713 | scriptable = scriptableFromQObject(thisQObject);
|
---|
714 | QScriptEngine *oldEngine = 0;
|
---|
715 | if (scriptable) {
|
---|
716 | oldEngine = QScriptablePrivate::get(scriptable)->engine;
|
---|
717 | QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(engine);
|
---|
718 | }
|
---|
719 |
|
---|
720 | #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
|
---|
721 | engine->notifyFunctionEntry(context);
|
---|
722 | #endif
|
---|
723 |
|
---|
724 | if (callType == QMetaMethod::Constructor) {
|
---|
725 | Q_ASSERT(meta != 0);
|
---|
726 | meta->static_metacall(QMetaObject::CreateInstance, chosenIndex, params);
|
---|
727 | } else {
|
---|
728 | Q_ASSERT(thisQObject != 0);
|
---|
729 | thisQObject->qt_metacall(QMetaObject::InvokeMetaMethod, chosenIndex, params);
|
---|
730 | }
|
---|
731 |
|
---|
732 | if (scriptable)
|
---|
733 | QScriptablePrivate::get(scriptable)->engine = oldEngine;
|
---|
734 |
|
---|
735 | if (context->state() == QScriptContext::ExceptionState) {
|
---|
736 | result = context->returnValue(); // propagate
|
---|
737 | } else {
|
---|
738 | QScriptMetaType retType = chosenMethod.returnType();
|
---|
739 | if (retType.isVariant()) {
|
---|
740 | result = engine->valueFromVariant(*(QVariant *)params[0]);
|
---|
741 | } else if (retType.typeId() != 0) {
|
---|
742 | result = engine->create(retType.typeId(), params[0]);
|
---|
743 | if (!result.isValid())
|
---|
744 | engine->newVariant(&result, QVariant(retType.typeId(), params[0]));
|
---|
745 | } else {
|
---|
746 | result = engine->undefinedValue();
|
---|
747 | }
|
---|
748 | }
|
---|
749 | }
|
---|
750 | }
|
---|
751 |
|
---|
752 | context->m_result = result;
|
---|
753 | #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
|
---|
754 | engine->notifyFunctionExit(context);
|
---|
755 | #endif
|
---|
756 | }
|
---|
757 |
|
---|
758 |
|
---|
759 | class ExtQObjectDataIterator: public QScriptClassDataIterator
|
---|
760 | {
|
---|
761 | public:
|
---|
762 | ExtQObjectDataIterator(const QScriptValueImpl &object);
|
---|
763 | virtual ~ExtQObjectDataIterator();
|
---|
764 |
|
---|
765 | virtual bool hasNext() const;
|
---|
766 | virtual void next(QScript::Member *member);
|
---|
767 |
|
---|
768 | virtual bool hasPrevious() const;
|
---|
769 | virtual void previous(QScript::Member *member);
|
---|
770 |
|
---|
771 | virtual void toFront();
|
---|
772 | virtual void toBack();
|
---|
773 |
|
---|
774 | private:
|
---|
775 | enum State {
|
---|
776 | MetaProperties,
|
---|
777 | DynamicProperties,
|
---|
778 | MetaMethods
|
---|
779 | };
|
---|
780 |
|
---|
781 | QScriptValueImpl m_object;
|
---|
782 | int m_index;
|
---|
783 | State m_state;
|
---|
784 | };
|
---|
785 |
|
---|
786 | ExtQObjectDataIterator::ExtQObjectDataIterator(const QScriptValueImpl &object)
|
---|
787 | {
|
---|
788 | m_object = object;
|
---|
789 | toFront();
|
---|
790 | }
|
---|
791 |
|
---|
792 | ExtQObjectDataIterator::~ExtQObjectDataIterator()
|
---|
793 | {
|
---|
794 | }
|
---|
795 |
|
---|
796 | bool ExtQObjectDataIterator::hasNext() const
|
---|
797 | {
|
---|
798 | ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object);
|
---|
799 | if (!inst->value)
|
---|
800 | return false;
|
---|
801 | const QMetaObject *meta = inst->value->metaObject();
|
---|
802 | int i = m_index;
|
---|
803 |
|
---|
804 | switch (m_state) {
|
---|
805 | case MetaProperties: {
|
---|
806 | for ( ; i < meta->propertyCount(); ++i) {
|
---|
807 | QMetaProperty prop = meta->property(i);
|
---|
808 | if (isEnumerableMetaProperty(prop, meta, i)
|
---|
809 | && !isObjectProperty(m_object, prop.name())) {
|
---|
810 | return true;
|
---|
811 | }
|
---|
812 | }
|
---|
813 | i = 0;
|
---|
814 | // fall-through
|
---|
815 | }
|
---|
816 |
|
---|
817 | case DynamicProperties: {
|
---|
818 | QList<QByteArray> dpNames = inst->value->dynamicPropertyNames();
|
---|
819 | for ( ; i < dpNames.count(); ++i) {
|
---|
820 | if (!isObjectProperty(m_object, dpNames.at(i))) {
|
---|
821 | return true;
|
---|
822 | }
|
---|
823 | }
|
---|
824 | if (inst->options & QScriptEngine::SkipMethodsInEnumeration)
|
---|
825 | return false;
|
---|
826 | i = (inst->options & QScriptEngine::ExcludeSuperClassMethods)
|
---|
827 | ? meta->methodOffset() : 0;
|
---|
828 | // fall-through
|
---|
829 | }
|
---|
830 |
|
---|
831 | case MetaMethods: {
|
---|
832 | for ( ; i < meta->methodCount(); ++i) {
|
---|
833 | QMetaMethod method = meta->method(i);
|
---|
834 | if (hasMethodAccess(method, i, inst->options)
|
---|
835 | && !isObjectProperty(m_object, method.signature())) {
|
---|
836 | return true;
|
---|
837 | }
|
---|
838 | }
|
---|
839 | }
|
---|
840 |
|
---|
841 | } // switch
|
---|
842 |
|
---|
843 | return false;
|
---|
844 | }
|
---|
845 |
|
---|
846 | void ExtQObjectDataIterator::next(QScript::Member *member)
|
---|
847 | {
|
---|
848 | QScriptEnginePrivate *eng = m_object.engine();
|
---|
849 | ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object);
|
---|
850 | if (!inst->value)
|
---|
851 | return;
|
---|
852 | const QMetaObject *meta = inst->value->metaObject();
|
---|
853 | int i = m_index;
|
---|
854 |
|
---|
855 | switch (m_state) {
|
---|
856 | case MetaProperties: {
|
---|
857 | for ( ; i < meta->propertyCount(); ++i) {
|
---|
858 | QMetaProperty prop = meta->property(i);
|
---|
859 | if (isEnumerableMetaProperty(prop, meta, i)
|
---|
860 | && !isObjectProperty(m_object, prop.name())) {
|
---|
861 | QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(prop.name()));
|
---|
862 | member->native(nameId, i, flagsForMetaProperty(prop));
|
---|
863 | m_index = i + 1;
|
---|
864 | return;
|
---|
865 | }
|
---|
866 | }
|
---|
867 | m_state = DynamicProperties;
|
---|
868 | m_index = 0;
|
---|
869 | i = m_index;
|
---|
870 | // fall-through
|
---|
871 | }
|
---|
872 |
|
---|
873 | case DynamicProperties: {
|
---|
874 | QList<QByteArray> dpNames = inst->value->dynamicPropertyNames();
|
---|
875 | for ( ; i < dpNames.count(); ++i) {
|
---|
876 | if (!isObjectProperty(m_object, dpNames.at(i))) {
|
---|
877 | QByteArray name = dpNames.at(i);
|
---|
878 | QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name));
|
---|
879 | member->native(nameId, i,
|
---|
880 | QScriptValue::QObjectMember
|
---|
881 | | DYNAPROPERTY_ID);
|
---|
882 | m_index = i + 1;
|
---|
883 | return;
|
---|
884 | }
|
---|
885 | }
|
---|
886 | m_state = MetaMethods;
|
---|
887 | m_index = (inst->options & QScriptEngine::ExcludeSuperClassMethods)
|
---|
888 | ? meta->methodOffset() : 0;
|
---|
889 | i = m_index;
|
---|
890 | // fall-through
|
---|
891 | }
|
---|
892 |
|
---|
893 | case MetaMethods: {
|
---|
894 | for ( ; i < meta->methodCount(); ++i) {
|
---|
895 | QMetaMethod method = meta->method(i);
|
---|
896 | if (hasMethodAccess(method, i, inst->options)
|
---|
897 | && !isObjectProperty(m_object, method.signature())) {
|
---|
898 | QMetaMethod method = meta->method(i);
|
---|
899 | QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(method.signature()));
|
---|
900 | member->native(nameId, i,
|
---|
901 | QScriptValue::QObjectMember
|
---|
902 | | METHOD_ID);
|
---|
903 | m_index = i + 1;
|
---|
904 | return;
|
---|
905 | }
|
---|
906 | }
|
---|
907 | }
|
---|
908 |
|
---|
909 | } // switch
|
---|
910 |
|
---|
911 | member->invalidate();
|
---|
912 | }
|
---|
913 |
|
---|
914 | bool ExtQObjectDataIterator::hasPrevious() const
|
---|
915 | {
|
---|
916 | ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object);
|
---|
917 | if (!inst->value)
|
---|
918 | return false;
|
---|
919 | const QMetaObject *meta = inst->value->metaObject();
|
---|
920 | int i = m_index - 1;
|
---|
921 |
|
---|
922 | switch (m_state) {
|
---|
923 | case MetaMethods: {
|
---|
924 | int limit = (inst->options & QScriptEngine::ExcludeSuperClassMethods)
|
---|
925 | ? meta->methodOffset() : 0;
|
---|
926 | for ( ; i >= limit; --i) {
|
---|
927 | QMetaMethod method = meta->method(i);
|
---|
928 | if (hasMethodAccess(method, i, inst->options)
|
---|
929 | && !isObjectProperty(m_object, method.signature())) {
|
---|
930 | return true;
|
---|
931 | }
|
---|
932 | }
|
---|
933 | i = inst->value->dynamicPropertyNames().count() - 1;
|
---|
934 | // fall-through
|
---|
935 | }
|
---|
936 |
|
---|
937 | case DynamicProperties: {
|
---|
938 | QList<QByteArray> dpNames = inst->value->dynamicPropertyNames();
|
---|
939 | for ( ; i >= 0; --i) {
|
---|
940 | if (!isObjectProperty(m_object, dpNames.at(i))) {
|
---|
941 | return true;
|
---|
942 | }
|
---|
943 | }
|
---|
944 | i = meta->propertyCount() - 1;
|
---|
945 | // fall-through
|
---|
946 | }
|
---|
947 |
|
---|
948 | case MetaProperties: {
|
---|
949 | int limit = (inst->options & QScriptEngine::ExcludeSuperClassProperties)
|
---|
950 | ? meta->propertyOffset() : 0;
|
---|
951 | for ( ; i >= limit; --i) {
|
---|
952 | QMetaProperty prop = meta->property(i);
|
---|
953 | if (isEnumerableMetaProperty(prop, meta, i)
|
---|
954 | && !isObjectProperty(m_object, prop.name())) {
|
---|
955 | return true;
|
---|
956 | }
|
---|
957 | }
|
---|
958 | }
|
---|
959 |
|
---|
960 | } // switch
|
---|
961 |
|
---|
962 | return false;
|
---|
963 | }
|
---|
964 |
|
---|
965 | void ExtQObjectDataIterator::previous(QScript::Member *member)
|
---|
966 | {
|
---|
967 | QScriptEnginePrivate *eng = m_object.engine();
|
---|
968 | ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object);
|
---|
969 | if (!inst->value)
|
---|
970 | return;
|
---|
971 | const QMetaObject *meta = inst->value->metaObject();
|
---|
972 | int i = m_index - 1;
|
---|
973 |
|
---|
974 | switch (m_state) {
|
---|
975 | case MetaMethods: {
|
---|
976 | int limit = (inst->options & QScriptEngine::ExcludeSuperClassMethods)
|
---|
977 | ? meta->methodOffset() : 0;
|
---|
978 | for ( ; i >= limit; --i) {
|
---|
979 | QMetaMethod method = meta->method(i);
|
---|
980 | if (hasMethodAccess(method, i, inst->options)
|
---|
981 | && !isObjectProperty(m_object, method.signature())) {
|
---|
982 | QMetaMethod method = meta->method(i);
|
---|
983 | QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(method.signature()));
|
---|
984 | member->native(nameId, i,
|
---|
985 | QScriptValue::QObjectMember
|
---|
986 | | METHOD_ID);
|
---|
987 | m_index = i;
|
---|
988 | return;
|
---|
989 | }
|
---|
990 | }
|
---|
991 | m_state = DynamicProperties;
|
---|
992 | m_index = inst->value->dynamicPropertyNames().count() - 1;
|
---|
993 | i = m_index;
|
---|
994 | // fall-through
|
---|
995 | }
|
---|
996 |
|
---|
997 | case DynamicProperties: {
|
---|
998 | QList<QByteArray> dpNames = inst->value->dynamicPropertyNames();
|
---|
999 | for ( ; i >= 0; --i) {
|
---|
1000 | if (!isObjectProperty(m_object, dpNames.at(i))) {
|
---|
1001 | QByteArray name = dpNames.at(i);
|
---|
1002 | QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(name));
|
---|
1003 | member->native(nameId, i,
|
---|
1004 | QScriptValue::QObjectMember
|
---|
1005 | | DYNAPROPERTY_ID);
|
---|
1006 | m_index = i;
|
---|
1007 | return;
|
---|
1008 | }
|
---|
1009 | }
|
---|
1010 | m_state = MetaProperties;
|
---|
1011 | m_index = meta->propertyCount() - 1;
|
---|
1012 | i = m_index;
|
---|
1013 | // fall-through
|
---|
1014 | }
|
---|
1015 |
|
---|
1016 | case MetaProperties: {
|
---|
1017 | int limit = (inst->options & QScriptEngine::ExcludeSuperClassProperties)
|
---|
1018 | ? meta->propertyOffset() : 0;
|
---|
1019 | for ( ; i >= limit; --i) {
|
---|
1020 | QMetaProperty prop = meta->property(i);
|
---|
1021 | if (isEnumerableMetaProperty(prop, meta, i)
|
---|
1022 | && !isObjectProperty(m_object, prop.name())) {
|
---|
1023 | QScriptNameIdImpl *nameId = eng->nameId(QLatin1String(prop.name()));
|
---|
1024 | member->native(nameId, i, flagsForMetaProperty(prop));
|
---|
1025 | m_index = i;
|
---|
1026 | return;
|
---|
1027 | }
|
---|
1028 | }
|
---|
1029 | }
|
---|
1030 |
|
---|
1031 | } // switch
|
---|
1032 |
|
---|
1033 | member->invalidate();
|
---|
1034 | }
|
---|
1035 |
|
---|
1036 | void ExtQObjectDataIterator::toFront()
|
---|
1037 | {
|
---|
1038 | ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object);
|
---|
1039 | if (!inst->value)
|
---|
1040 | return;
|
---|
1041 | m_state = MetaProperties;
|
---|
1042 | const QMetaObject *meta = inst->value->metaObject();
|
---|
1043 | m_index = (inst->options & QScriptEngine::ExcludeSuperClassProperties)
|
---|
1044 | ? meta->propertyOffset() : 0;
|
---|
1045 | }
|
---|
1046 |
|
---|
1047 | void ExtQObjectDataIterator::toBack()
|
---|
1048 | {
|
---|
1049 | ExtQObject::Instance *inst = ExtQObject::Instance::get(m_object);
|
---|
1050 | if (!inst->value)
|
---|
1051 | return;
|
---|
1052 | if (inst->options & QScriptEngine::SkipMethodsInEnumeration) {
|
---|
1053 | m_state = DynamicProperties;
|
---|
1054 | m_index = inst->value->dynamicPropertyNames().count();
|
---|
1055 | } else {
|
---|
1056 | m_state = MetaMethods;
|
---|
1057 | const QMetaObject *meta = inst->value->metaObject();
|
---|
1058 | m_index = meta->methodCount();
|
---|
1059 | }
|
---|
1060 | }
|
---|
1061 |
|
---|
1062 | class ExtQObjectData: public QScriptClassData
|
---|
1063 | {
|
---|
1064 | public:
|
---|
1065 | ExtQObjectData(QScriptClassInfo *classInfo)
|
---|
1066 | : m_classInfo(classInfo)
|
---|
1067 | {
|
---|
1068 | }
|
---|
1069 |
|
---|
1070 | virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId,
|
---|
1071 | QScript::Member *member, QScriptValueImpl *,
|
---|
1072 | QScript::AccessMode access)
|
---|
1073 | {
|
---|
1074 | ExtQObject::Instance *inst = ExtQObject::Instance::get(object, m_classInfo);
|
---|
1075 | QObject *qobject = inst->value;
|
---|
1076 | if (! qobject) {
|
---|
1077 | // the object was deleted. We return true so we can
|
---|
1078 | // throw an error in get()/put()
|
---|
1079 | member->native(nameId, /*id=*/-1, /*flags=*/0);
|
---|
1080 | return true;
|
---|
1081 | }
|
---|
1082 |
|
---|
1083 | const QScriptEngine::QObjectWrapOptions &opt = inst->options;
|
---|
1084 | const QMetaObject *meta = qobject->metaObject();
|
---|
1085 |
|
---|
1086 | QScriptEnginePrivate *eng = object.engine();
|
---|
1087 |
|
---|
1088 | #ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
|
---|
1089 | QScriptMetaObject *metaCache = eng->cachedMetaObject(meta);
|
---|
1090 | if (metaCache->findMember(nameId, member)) {
|
---|
1091 | bool ignore = false;
|
---|
1092 | switch (member->flags() & ID_MASK) {
|
---|
1093 | case PROPERTY_ID:
|
---|
1094 | ignore = (opt & QScriptEngine::ExcludeSuperClassProperties)
|
---|
1095 | && (member->id() < meta->propertyOffset());
|
---|
1096 | break;
|
---|
1097 | case METHOD_ID:
|
---|
1098 | ignore = ((opt & QScriptEngine::ExcludeSuperClassMethods)
|
---|
1099 | && (member->id() < meta->methodOffset()))
|
---|
1100 | || ((opt & QScriptEngine::ExcludeDeleteLater)
|
---|
1101 | && (member->id() == 2));
|
---|
1102 | break;
|
---|
1103 | // we don't cache dynamic properties nor children,
|
---|
1104 | // so no need to handle DYNAPROPERTY_ID and CHILD_ID
|
---|
1105 | default:
|
---|
1106 | break;
|
---|
1107 | }
|
---|
1108 | if (!ignore)
|
---|
1109 | return true;
|
---|
1110 | }
|
---|
1111 | #endif
|
---|
1112 |
|
---|
1113 | QString memberName = eng->toString(nameId);
|
---|
1114 | QByteArray name = memberName.toLatin1();
|
---|
1115 |
|
---|
1116 | int index = -1;
|
---|
1117 |
|
---|
1118 | if (name.contains('(')) {
|
---|
1119 | QByteArray normalized = QMetaObject::normalizedSignature(name);
|
---|
1120 | if (-1 != (index = meta->indexOfMethod(normalized))) {
|
---|
1121 | QMetaMethod method = meta->method(index);
|
---|
1122 | if (hasMethodAccess(method, index, opt)) {
|
---|
1123 | member->native(nameId, index,
|
---|
1124 | QScriptValue::QObjectMember
|
---|
1125 | | METHOD_ID);
|
---|
1126 | #ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
|
---|
1127 | metaCache->registerMember(nameId, *member);
|
---|
1128 | #endif
|
---|
1129 | if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
|
---|
1130 | || (index >= meta->methodOffset())) {
|
---|
1131 | return true;
|
---|
1132 | }
|
---|
1133 | }
|
---|
1134 | }
|
---|
1135 | }
|
---|
1136 |
|
---|
1137 | index = meta->indexOfProperty(name);
|
---|
1138 | if (index != -1) {
|
---|
1139 | QMetaProperty prop = meta->property(index);
|
---|
1140 | if (prop.isScriptable()) {
|
---|
1141 | member->native(nameId, index, flagsForMetaProperty(prop));
|
---|
1142 | #ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
|
---|
1143 | metaCache->registerMember(nameId, *member);
|
---|
1144 | #endif
|
---|
1145 | if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
|
---|
1146 | || (index >= meta->propertyOffset())) {
|
---|
1147 | return true;
|
---|
1148 | }
|
---|
1149 | }
|
---|
1150 | }
|
---|
1151 |
|
---|
1152 | index = qobject->dynamicPropertyNames().indexOf(name);
|
---|
1153 | if (index != -1) {
|
---|
1154 | member->native(nameId, index,
|
---|
1155 | QScriptValue::QObjectMember
|
---|
1156 | | DYNAPROPERTY_ID);
|
---|
1157 | // not cached because it can be removed
|
---|
1158 | return true;
|
---|
1159 | }
|
---|
1160 |
|
---|
1161 | const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
|
---|
1162 | ? meta->methodOffset() : 0;
|
---|
1163 | for (index = meta->methodCount() - 1; index >= offset; --index) {
|
---|
1164 | QMetaMethod method = meta->method(index);
|
---|
1165 | if (hasMethodAccess(method, index, opt)
|
---|
1166 | && (methodName(method) == name)) {
|
---|
1167 | member->native(nameId, index,
|
---|
1168 | QScriptValue::QObjectMember
|
---|
1169 | | METHOD_ID
|
---|
1170 | | MAYBE_OVERLOADED);
|
---|
1171 | #ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
|
---|
1172 | metaCache->registerMember(nameId, *member);
|
---|
1173 | #endif
|
---|
1174 | return true;
|
---|
1175 | }
|
---|
1176 | }
|
---|
1177 |
|
---|
1178 | if (!(opt & QScriptEngine::ExcludeChildObjects)) {
|
---|
1179 | QList<QObject*> children = qobject->children();
|
---|
1180 | for (index = 0; index < children.count(); ++index) {
|
---|
1181 | QObject *child = children.at(index);
|
---|
1182 | if (child->objectName() == memberName) {
|
---|
1183 | member->native(nameId, index,
|
---|
1184 | QScriptValue::ReadOnly
|
---|
1185 | | QScriptValue::Undeletable
|
---|
1186 | | QScriptValue::SkipInEnumeration
|
---|
1187 | | CHILD_ID);
|
---|
1188 | // not cached because it can be removed or change name
|
---|
1189 | return true;
|
---|
1190 | }
|
---|
1191 | }
|
---|
1192 | }
|
---|
1193 |
|
---|
1194 | if ((access & QScript::Write) && (opt & QScriptEngine::AutoCreateDynamicProperties)) {
|
---|
1195 | member->native(nameId, -1, DYNAPROPERTY_ID);
|
---|
1196 | return true;
|
---|
1197 | }
|
---|
1198 |
|
---|
1199 | return false;
|
---|
1200 | }
|
---|
1201 |
|
---|
1202 | virtual bool get(const QScriptValueImpl &obj, const QScript::Member &member, QScriptValueImpl *result)
|
---|
1203 | {
|
---|
1204 | if (! member.isNativeProperty())
|
---|
1205 | return false;
|
---|
1206 |
|
---|
1207 | QScriptEnginePrivate *eng = obj.engine();
|
---|
1208 |
|
---|
1209 | ExtQObject::Instance *inst = ExtQObject::Instance::get(obj, m_classInfo);
|
---|
1210 | QObject *qobject = inst->value;
|
---|
1211 | if (!qobject) {
|
---|
1212 | QScriptContextPrivate *ctx = eng->currentContext();
|
---|
1213 | *result = ctx->throwError(
|
---|
1214 | QString::fromLatin1("cannot access member `%0' of deleted QObject")
|
---|
1215 | .arg(member.nameId()->s));
|
---|
1216 | return true;
|
---|
1217 | }
|
---|
1218 |
|
---|
1219 | switch (member.flags() & ID_MASK) {
|
---|
1220 | case PROPERTY_ID: {
|
---|
1221 | const QMetaObject *meta = qobject->metaObject();
|
---|
1222 | const int propertyIndex = member.id();
|
---|
1223 | QMetaProperty prop = meta->property(propertyIndex);
|
---|
1224 | Q_ASSERT(prop.isScriptable());
|
---|
1225 | if (GeneratePropertyFunctions) {
|
---|
1226 | QScriptValueImpl accessor;
|
---|
1227 | #ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
|
---|
1228 | QScriptMetaObject *metaCache = eng->cachedMetaObject(meta);
|
---|
1229 | accessor = metaCache->findPropertyAccessor(propertyIndex);
|
---|
1230 | if (!accessor.isValid()) {
|
---|
1231 | #endif
|
---|
1232 | accessor = eng->createFunction(new QtPropertyFunction(meta, propertyIndex));
|
---|
1233 | #ifndef Q_SCRIPT_NO_QMETAOBJECT_CACHE
|
---|
1234 | metaCache->registerPropertyAccessor(propertyIndex, accessor);
|
---|
1235 | }
|
---|
1236 | #endif
|
---|
1237 | *result = accessor;
|
---|
1238 | } else {
|
---|
1239 | QVariant v = prop.read(qobject);
|
---|
1240 | *result = eng->valueFromVariant(v);
|
---|
1241 | }
|
---|
1242 | } break;
|
---|
1243 |
|
---|
1244 | case DYNAPROPERTY_ID: {
|
---|
1245 | if (member.id() != -1) {
|
---|
1246 | QVariant v = qobject->property(member.nameId()->s.toLatin1());
|
---|
1247 | *result = eng->valueFromVariant(v);
|
---|
1248 | } else {
|
---|
1249 | *result = eng->undefinedValue();
|
---|
1250 | }
|
---|
1251 | } break;
|
---|
1252 |
|
---|
1253 | case METHOD_ID: {
|
---|
1254 | QScript::Member m;
|
---|
1255 | bool maybeOverloaded = (member.flags() & MAYBE_OVERLOADED) != 0;
|
---|
1256 | *result = eng->createFunction(new QtFunction(obj, member.id(),
|
---|
1257 | maybeOverloaded));
|
---|
1258 | // make it persist (otherwise Function.prototype.disconnect() would fail)
|
---|
1259 | uint flags = QScriptValue::QObjectMember;
|
---|
1260 | if (inst->options & QScriptEngine::SkipMethodsInEnumeration)
|
---|
1261 | flags |= QScriptValue::SkipInEnumeration;
|
---|
1262 | QScriptObject *instance = obj.objectValue();
|
---|
1263 | if (!instance->findMember(member.nameId(), &m))
|
---|
1264 | instance->createMember(member.nameId(), &m, flags);
|
---|
1265 | instance->put(m, *result);
|
---|
1266 | } break;
|
---|
1267 |
|
---|
1268 | case CHILD_ID: {
|
---|
1269 | QObject *child = qobject->children().at(member.id());
|
---|
1270 | result->invalidate();
|
---|
1271 | QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
|
---|
1272 | eng->newQObject(result, child, QScriptEngine::QtOwnership, opt);
|
---|
1273 | } break;
|
---|
1274 |
|
---|
1275 | } // switch
|
---|
1276 |
|
---|
1277 | return true;
|
---|
1278 | }
|
---|
1279 |
|
---|
1280 | virtual bool put(QScriptValueImpl *object, const QScript::Member &member, const QScriptValueImpl &value)
|
---|
1281 | {
|
---|
1282 | if (! member.isNativeProperty() || ! member.isWritable())
|
---|
1283 | return false;
|
---|
1284 |
|
---|
1285 | ExtQObject::Instance *inst = ExtQObject::Instance::get(*object, m_classInfo);
|
---|
1286 | QObject *qobject = inst->value;
|
---|
1287 | if (!qobject) {
|
---|
1288 | QScriptEnginePrivate *eng = object->engine();
|
---|
1289 | QScriptContextPrivate *ctx = eng->currentContext();
|
---|
1290 | ctx->throwError(QString::fromLatin1("cannot access member `%0' of deleted QObject")
|
---|
1291 | .arg(member.nameId()->s));
|
---|
1292 | return true;
|
---|
1293 | }
|
---|
1294 |
|
---|
1295 | switch (member.flags() & ID_MASK) {
|
---|
1296 | case CHILD_ID:
|
---|
1297 | return false;
|
---|
1298 |
|
---|
1299 | case METHOD_ID: {
|
---|
1300 | QScript::Member m;
|
---|
1301 | QScriptObject *instance = object->objectValue();
|
---|
1302 | if (!instance->findMember(member.nameId(), &m)) {
|
---|
1303 | instance->createMember(member.nameId(), &m,
|
---|
1304 | /*flags=*/0);
|
---|
1305 | }
|
---|
1306 | instance->put(m, value);
|
---|
1307 | return true;
|
---|
1308 | }
|
---|
1309 |
|
---|
1310 | case PROPERTY_ID:
|
---|
1311 | if (GeneratePropertyFunctions) {
|
---|
1312 | // we shouldn't get here, QScriptValueImpl::setProperty() messed up
|
---|
1313 | Q_ASSERT_X(0, "put", "Q_PROPERTY access cannot be overridden");
|
---|
1314 | return false;
|
---|
1315 | } else {
|
---|
1316 | const QMetaObject *meta = qobject->metaObject();
|
---|
1317 | QMetaProperty prop = meta->property(member.id());
|
---|
1318 | Q_ASSERT(prop.isScriptable());
|
---|
1319 | QVariant v = variantFromValue(object->engine(), prop.userType(), value);
|
---|
1320 | bool ok = prop.write(qobject, v);
|
---|
1321 | return ok;
|
---|
1322 | }
|
---|
1323 |
|
---|
1324 | case DYNAPROPERTY_ID: {
|
---|
1325 | QVariant v = value.toVariant();
|
---|
1326 | return ! qobject->setProperty(member.nameId()->s.toLatin1(), v);
|
---|
1327 | }
|
---|
1328 |
|
---|
1329 | } // switch
|
---|
1330 | return false;
|
---|
1331 | }
|
---|
1332 |
|
---|
1333 | virtual bool removeMember(const QScriptValueImpl &object,
|
---|
1334 | const QScript::Member &member)
|
---|
1335 | {
|
---|
1336 | QObject *qobject = object.toQObject();
|
---|
1337 | if (!qobject || !member.isNativeProperty() || !member.isDeletable())
|
---|
1338 | return false;
|
---|
1339 |
|
---|
1340 | if ((member.flags() & ID_MASK) == DYNAPROPERTY_ID) {
|
---|
1341 | qobject->setProperty(member.nameId()->s.toLatin1(), QVariant());
|
---|
1342 | return true;
|
---|
1343 | }
|
---|
1344 |
|
---|
1345 | return false;
|
---|
1346 | }
|
---|
1347 |
|
---|
1348 | virtual void mark(const QScriptValueImpl &, int)
|
---|
1349 | {
|
---|
1350 | }
|
---|
1351 |
|
---|
1352 | virtual QScriptClassDataIterator *newIterator(const QScriptValueImpl &object)
|
---|
1353 | {
|
---|
1354 | return new ExtQObjectDataIterator(object);
|
---|
1355 | }
|
---|
1356 |
|
---|
1357 | private:
|
---|
1358 | QScriptClassInfo *m_classInfo;
|
---|
1359 | };
|
---|
1360 |
|
---|
1361 | struct QObjectConnection
|
---|
1362 | {
|
---|
1363 | int slotIndex;
|
---|
1364 | QScriptValueImpl receiver;
|
---|
1365 | QScriptValueImpl slot;
|
---|
1366 | QScriptValueImpl senderWrapper;
|
---|
1367 |
|
---|
1368 | QObjectConnection(int i, const QScriptValueImpl &r, const QScriptValueImpl &s,
|
---|
1369 | const QScriptValueImpl &sw)
|
---|
1370 | : slotIndex(i), receiver(r), slot(s), senderWrapper(sw) {}
|
---|
1371 | QObjectConnection() : slotIndex(-1) {}
|
---|
1372 |
|
---|
1373 | bool hasTarget(const QScriptValueImpl &r, const QScriptValueImpl &s) const
|
---|
1374 | {
|
---|
1375 | if (r.isObject() != receiver.isObject())
|
---|
1376 | return false;
|
---|
1377 | if ((r.isObject() && receiver.isObject())
|
---|
1378 | && (r.objectValue() != receiver.objectValue())) {
|
---|
1379 | return false;
|
---|
1380 | }
|
---|
1381 | return (s.objectValue() == slot.objectValue());
|
---|
1382 | }
|
---|
1383 |
|
---|
1384 | void mark(int generation)
|
---|
1385 | {
|
---|
1386 | if (senderWrapper.isValid() && !senderWrapper.isMarked(generation)) {
|
---|
1387 | // see if the sender should be marked or not
|
---|
1388 | ExtQObject::Instance *inst = ExtQObject::Instance::get(senderWrapper);
|
---|
1389 | if ((inst->ownership == QScriptEngine::ScriptOwnership)
|
---|
1390 | || ((inst->ownership == QScriptEngine::AutoOwnership)
|
---|
1391 | && inst->value && !inst->value->parent())) {
|
---|
1392 | senderWrapper.invalidate();
|
---|
1393 | } else {
|
---|
1394 | senderWrapper.mark(generation);
|
---|
1395 | }
|
---|
1396 | }
|
---|
1397 | if (receiver.isValid())
|
---|
1398 | receiver.mark(generation);
|
---|
1399 | if (slot.isValid())
|
---|
1400 | slot.mark(generation);
|
---|
1401 | }
|
---|
1402 | };
|
---|
1403 |
|
---|
1404 | class QObjectConnectionManager: public QObject
|
---|
1405 | {
|
---|
1406 | public:
|
---|
1407 | QObjectConnectionManager();
|
---|
1408 | ~QObjectConnectionManager();
|
---|
1409 |
|
---|
1410 | bool addSignalHandler(QObject *sender, int signalIndex,
|
---|
1411 | const QScriptValueImpl &receiver,
|
---|
1412 | const QScriptValueImpl &slot,
|
---|
1413 | const QScriptValueImpl &senderWrapper = QScriptValueImpl());
|
---|
1414 | bool removeSignalHandler(
|
---|
1415 | QObject *sender, int signalIndex,
|
---|
1416 | const QScriptValueImpl &receiver,
|
---|
1417 | const QScriptValueImpl &slot);
|
---|
1418 |
|
---|
1419 | static const QMetaObject staticMetaObject;
|
---|
1420 | virtual const QMetaObject *metaObject() const;
|
---|
1421 | virtual void *qt_metacast(const char *);
|
---|
1422 | virtual int qt_metacall(QMetaObject::Call, int, void **argv);
|
---|
1423 |
|
---|
1424 | void execute(int slotIndex, void **argv);
|
---|
1425 |
|
---|
1426 | void mark(int generation);
|
---|
1427 |
|
---|
1428 | private:
|
---|
1429 | int m_slotCounter;
|
---|
1430 | QVector<QVector<QObjectConnection> > connections;
|
---|
1431 | };
|
---|
1432 |
|
---|
1433 | } // ::QScript
|
---|
1434 |
|
---|
1435 |
|
---|
1436 |
|
---|
1437 | QScript::ExtQObject::ExtQObject(QScriptEnginePrivate *eng):
|
---|
1438 | Ecma::Core(eng, QLatin1String("QObject"), QScriptClassInfo::QObjectType)
|
---|
1439 | {
|
---|
1440 | newQObject(&publicPrototype, new QScript::QObjectPrototype(),
|
---|
1441 | QScriptEngine::AutoOwnership,
|
---|
1442 | QScriptEngine::ExcludeSuperClassMethods
|
---|
1443 | | QScriptEngine::ExcludeSuperClassProperties
|
---|
1444 | | QScriptEngine::ExcludeChildObjects);
|
---|
1445 |
|
---|
1446 | eng->newConstructor(&ctor, this, publicPrototype);
|
---|
1447 | addPrototypeFunction(QLatin1String("toString"), method_toString, 0);
|
---|
1448 | addPrototypeFunction(QLatin1String("findChild"), method_findChild, 1);
|
---|
1449 | addPrototypeFunction(QLatin1String("findChildren"), method_findChildren, 1);
|
---|
1450 |
|
---|
1451 | classInfo()->setData(new QScript::ExtQObjectData(classInfo()));
|
---|
1452 | }
|
---|
1453 |
|
---|
1454 | QScript::ExtQObject::~ExtQObject()
|
---|
1455 | {
|
---|
1456 | }
|
---|
1457 |
|
---|
1458 | void QScript::ExtQObject::execute(QScriptContextPrivate *context)
|
---|
1459 | {
|
---|
1460 | QScriptValueImpl tmp;
|
---|
1461 | newQObject(&tmp, 0);
|
---|
1462 | context->setReturnValue(tmp);
|
---|
1463 | }
|
---|
1464 |
|
---|
1465 | void QScript::ExtQObject::newQObject(QScriptValueImpl *result, QObject *value,
|
---|
1466 | QScriptEngine::ValueOwnership ownership,
|
---|
1467 | const QScriptEngine::QObjectWrapOptions &options)
|
---|
1468 | {
|
---|
1469 | Instance *instance;
|
---|
1470 | if (!result->isValid()) {
|
---|
1471 | engine()->newObject(result, publicPrototype, classInfo());
|
---|
1472 | instance = new Instance();
|
---|
1473 | result->setObjectData(instance);
|
---|
1474 | } else {
|
---|
1475 | Q_ASSERT(result->isObject());
|
---|
1476 | if (result->classInfo() != classInfo()) {
|
---|
1477 | result->destroyObjectData();
|
---|
1478 | result->setClassInfo(classInfo());
|
---|
1479 | instance = new Instance();
|
---|
1480 | result->setObjectData(instance);
|
---|
1481 | } else {
|
---|
1482 | instance = Instance::get(*result);
|
---|
1483 | }
|
---|
1484 | }
|
---|
1485 | instance->value = value;
|
---|
1486 | instance->ownership = ownership;
|
---|
1487 | instance->options = options;
|
---|
1488 | }
|
---|
1489 |
|
---|
1490 | QScriptValueImpl QScript::ExtQObject::method_findChild(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo)
|
---|
1491 | {
|
---|
1492 | if (Instance *instance = Instance::get(context->thisObject(), classInfo)) {
|
---|
1493 | QObject *obj = instance->value;
|
---|
1494 | QString name = context->argument(0).toString();
|
---|
1495 | QObject *child = qFindChild<QObject*>(obj, name);
|
---|
1496 | QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
|
---|
1497 | QScriptValueImpl result;
|
---|
1498 | eng->newQObject(&result, child, QScriptEngine::QtOwnership, opt);
|
---|
1499 | return result;
|
---|
1500 | }
|
---|
1501 | return eng->undefinedValue();
|
---|
1502 | }
|
---|
1503 |
|
---|
1504 | QScriptValueImpl QScript::ExtQObject::method_findChildren(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo)
|
---|
1505 | {
|
---|
1506 | if (Instance *instance = Instance::get(context->thisObject(), classInfo)) {
|
---|
1507 | QObject *obj = instance->value;
|
---|
1508 | QList<QObject*> found;
|
---|
1509 | QScriptValueImpl arg = context->argument(0);
|
---|
1510 | #ifndef QT_NO_REGEXP
|
---|
1511 | if (arg.isRegExp()) {
|
---|
1512 | QRegExp re = arg.toRegExp();
|
---|
1513 | found = qFindChildren<QObject*>(obj, re);
|
---|
1514 | } else
|
---|
1515 | #endif
|
---|
1516 | {
|
---|
1517 | QString name = arg.isUndefined() ? QString() : arg.toString();
|
---|
1518 | found = qFindChildren<QObject*>(obj, name);
|
---|
1519 | }
|
---|
1520 | QScriptValueImpl result = eng->newArray(found.size());
|
---|
1521 | QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
|
---|
1522 | for (int i = 0; i < found.size(); ++i) {
|
---|
1523 | QScriptValueImpl value;
|
---|
1524 | eng->newQObject(&value, found.at(i), QScriptEngine::QtOwnership, opt);
|
---|
1525 | result.setProperty(i, value);
|
---|
1526 | }
|
---|
1527 | return result;
|
---|
1528 | }
|
---|
1529 | return eng->undefinedValue();
|
---|
1530 | }
|
---|
1531 |
|
---|
1532 | QScriptValueImpl QScript::ExtQObject::method_toString(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo)
|
---|
1533 | {
|
---|
1534 | if (Instance *instance = Instance::get(context->thisObject(), classInfo)) {
|
---|
1535 | QObject *obj = instance->value;
|
---|
1536 | const QMetaObject *meta = obj ? obj->metaObject() : &QObject::staticMetaObject;
|
---|
1537 | QString name = obj ? obj->objectName() : QString::fromUtf8("unnamed");
|
---|
1538 |
|
---|
1539 | QString str = QString::fromUtf8("%0(name = \"%1\")")
|
---|
1540 | .arg(QLatin1String(meta->className())).arg(name);
|
---|
1541 | return QScriptValueImpl(eng, str);
|
---|
1542 | }
|
---|
1543 | return eng->undefinedValue();
|
---|
1544 | }
|
---|
1545 |
|
---|
1546 |
|
---|
1547 |
|
---|
1548 | static const uint qt_meta_data_QObjectConnectionManager[] = {
|
---|
1549 |
|
---|
1550 | // content:
|
---|
1551 | 1, // revision
|
---|
1552 | 0, // classname
|
---|
1553 | 0, 0, // classinfo
|
---|
1554 | 1, 10, // methods
|
---|
1555 | 0, 0, // properties
|
---|
1556 | 0, 0, // enums/sets
|
---|
1557 |
|
---|
1558 | // slots: signature, parameters, type, tag, flags
|
---|
1559 | 35, 34, 34, 34, 0x0a,
|
---|
1560 |
|
---|
1561 | 0 // eod
|
---|
1562 | };
|
---|
1563 |
|
---|
1564 | static const char qt_meta_stringdata_QObjectConnectionManager[] = {
|
---|
1565 | "QScript::QObjectConnectionManager\0\0execute()\0"
|
---|
1566 | };
|
---|
1567 |
|
---|
1568 | const QMetaObject QScript::QObjectConnectionManager::staticMetaObject = {
|
---|
1569 | { &QObject::staticMetaObject, qt_meta_stringdata_QObjectConnectionManager,
|
---|
1570 | qt_meta_data_QObjectConnectionManager, 0 }
|
---|
1571 | };
|
---|
1572 |
|
---|
1573 | const QMetaObject *QScript::QObjectConnectionManager::metaObject() const
|
---|
1574 | {
|
---|
1575 | return &staticMetaObject;
|
---|
1576 | }
|
---|
1577 |
|
---|
1578 | void *QScript::QObjectConnectionManager::qt_metacast(const char *_clname)
|
---|
1579 | {
|
---|
1580 | if (!_clname) return 0;
|
---|
1581 | if (!strcmp(_clname, qt_meta_stringdata_QObjectConnectionManager))
|
---|
1582 | return static_cast<void*>(const_cast<QObjectConnectionManager*>(this));
|
---|
1583 | return QObject::qt_metacast(_clname);
|
---|
1584 | }
|
---|
1585 |
|
---|
1586 | int QScript::QObjectConnectionManager::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
|
---|
1587 | {
|
---|
1588 | _id = QObject::qt_metacall(_c, _id, _a);
|
---|
1589 | if (_id < 0)
|
---|
1590 | return _id;
|
---|
1591 | if (_c == QMetaObject::InvokeMetaMethod) {
|
---|
1592 | execute(_id, _a);
|
---|
1593 | _id -= m_slotCounter;
|
---|
1594 | }
|
---|
1595 | return _id;
|
---|
1596 | }
|
---|
1597 |
|
---|
1598 | void QScript::QObjectConnectionManager::execute(int slotIndex, void **argv)
|
---|
1599 | {
|
---|
1600 | QScriptValueImpl receiver;
|
---|
1601 | QScriptValueImpl slot;
|
---|
1602 | QScriptValueImpl senderWrapper;
|
---|
1603 | int signalIndex = -1;
|
---|
1604 | for (int i = 0; i < connections.size(); ++i) {
|
---|
1605 | const QVector<QObjectConnection> &cs = connections.at(i);
|
---|
1606 | for (int j = 0; j < cs.size(); ++j) {
|
---|
1607 | const QObjectConnection &c = cs.at(j);
|
---|
1608 | if (c.slotIndex == slotIndex) {
|
---|
1609 | receiver = c.receiver;
|
---|
1610 | slot = c.slot;
|
---|
1611 | senderWrapper = c.senderWrapper;
|
---|
1612 | signalIndex = i;
|
---|
1613 | break;
|
---|
1614 | }
|
---|
1615 | }
|
---|
1616 | }
|
---|
1617 | Q_ASSERT(slot.isValid());
|
---|
1618 |
|
---|
1619 | QScriptEnginePrivate *eng = slot.engine();
|
---|
1620 |
|
---|
1621 | if (eng->isCollecting()) {
|
---|
1622 | // we can't do a script function call during GC,
|
---|
1623 | // so we're forced to ignore this signal
|
---|
1624 | return;
|
---|
1625 | }
|
---|
1626 |
|
---|
1627 | QScriptFunction *fun = eng->convertToNativeFunction(slot);
|
---|
1628 | if (fun == 0) {
|
---|
1629 | // the signal handler has been GC'ed. This can only happen when
|
---|
1630 | // a QObject is owned by the engine, the engine is destroyed, and
|
---|
1631 | // there is a script function connected to the destroyed() signal
|
---|
1632 | Q_ASSERT(signalIndex <= 1); // destroyed(QObject*)
|
---|
1633 | return;
|
---|
1634 | }
|
---|
1635 |
|
---|
1636 | const QMetaObject *meta = sender()->metaObject();
|
---|
1637 | const QMetaMethod method = meta->method(signalIndex);
|
---|
1638 |
|
---|
1639 | QList<QByteArray> parameterTypes = method.parameterTypes();
|
---|
1640 | int argc = parameterTypes.count();
|
---|
1641 |
|
---|
1642 | QScriptValueImpl activation;
|
---|
1643 | eng->newActivation(&activation);
|
---|
1644 | QScriptObject *activation_data = activation.objectValue();
|
---|
1645 | activation_data->m_scope = slot.scope();
|
---|
1646 |
|
---|
1647 | int formalCount = fun->formals.count();
|
---|
1648 | int mx = qMax(formalCount, argc);
|
---|
1649 | activation_data->m_members.resize(mx + 1);
|
---|
1650 | activation_data->m_values.resize(mx + 1);
|
---|
1651 | for (int i = 0; i < mx; ++i) {
|
---|
1652 | QScriptNameIdImpl *nameId;
|
---|
1653 | if (i < formalCount)
|
---|
1654 | nameId = fun->formals.at(i);
|
---|
1655 | else
|
---|
1656 | nameId = 0;
|
---|
1657 | activation_data->m_members[i].object(nameId, i,
|
---|
1658 | QScriptValue::Undeletable
|
---|
1659 | | QScriptValue::SkipInEnumeration);
|
---|
1660 | if (i < argc) {
|
---|
1661 | int argType = QMetaType::type(parameterTypes.at(i));
|
---|
1662 | activation_data->m_values[i] = eng->create(argType, argv[i + 1]);
|
---|
1663 | } else {
|
---|
1664 | activation_data->m_values[i] = eng->undefinedValue();
|
---|
1665 | }
|
---|
1666 | }
|
---|
1667 |
|
---|
1668 | QScriptValueImpl senderObject;
|
---|
1669 | if (senderWrapper.isQObject()) {
|
---|
1670 | senderObject = senderWrapper;
|
---|
1671 | } else {
|
---|
1672 | QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
|
---|
1673 | eng->newQObject(&senderObject, sender(), QScriptEngine::QtOwnership, opt);
|
---|
1674 | }
|
---|
1675 | activation_data->m_members[mx].object(eng->idTable()->id___qt_sender__, mx,
|
---|
1676 | QScriptValue::SkipInEnumeration);
|
---|
1677 | activation_data->m_values[mx] = senderObject;
|
---|
1678 |
|
---|
1679 | QScriptValueImpl thisObject;
|
---|
1680 | if (receiver.isObject())
|
---|
1681 | thisObject = receiver;
|
---|
1682 | else
|
---|
1683 | thisObject = eng->globalObject();
|
---|
1684 |
|
---|
1685 | QScriptContextPrivate *context_data = eng->pushContext();
|
---|
1686 | context_data->m_activation = activation;
|
---|
1687 | context_data->m_callee = slot;
|
---|
1688 | context_data->m_thisObject = thisObject;
|
---|
1689 | context_data->argc = argc;
|
---|
1690 | context_data->args = const_cast<QScriptValueImpl*> (activation_data->m_values.constData());
|
---|
1691 |
|
---|
1692 | fun->execute(context_data);
|
---|
1693 |
|
---|
1694 | eng->popContext();
|
---|
1695 | if (eng->hasUncaughtException())
|
---|
1696 | eng->emitSignalHandlerException();
|
---|
1697 | }
|
---|
1698 |
|
---|
1699 | QScript::QObjectConnectionManager::QObjectConnectionManager()
|
---|
1700 | : m_slotCounter(0)
|
---|
1701 | {
|
---|
1702 | }
|
---|
1703 |
|
---|
1704 | QScript::QObjectConnectionManager::~QObjectConnectionManager()
|
---|
1705 | {
|
---|
1706 | }
|
---|
1707 |
|
---|
1708 | void QScript::QObjectConnectionManager::mark(int generation)
|
---|
1709 | {
|
---|
1710 | for (int i = 0; i < connections.size(); ++i) {
|
---|
1711 | QVector<QObjectConnection> &cs = connections[i];
|
---|
1712 | for (int j = 0; j < cs.size(); ++j)
|
---|
1713 | cs[j].mark(generation);
|
---|
1714 | }
|
---|
1715 | }
|
---|
1716 |
|
---|
1717 | bool QScript::QObjectConnectionManager::addSignalHandler(
|
---|
1718 | QObject *sender, int signalIndex, const QScriptValueImpl &receiver,
|
---|
1719 | const QScriptValueImpl &function, const QScriptValueImpl &senderWrapper)
|
---|
1720 | {
|
---|
1721 | if (connections.size() <= signalIndex)
|
---|
1722 | connections.resize(signalIndex+1);
|
---|
1723 | QVector<QObjectConnection> &cs = connections[signalIndex];
|
---|
1724 | int absSlotIndex = m_slotCounter + metaObject()->methodOffset();
|
---|
1725 | bool ok = QMetaObject::connect(sender, signalIndex, this, absSlotIndex);
|
---|
1726 | if (ok) {
|
---|
1727 | cs.append(QScript::QObjectConnection(m_slotCounter++, receiver, function, senderWrapper));
|
---|
1728 | QMetaMethod signal = sender->metaObject()->method(signalIndex);
|
---|
1729 | QByteArray signalString;
|
---|
1730 | signalString.append('2'); // signal code
|
---|
1731 | signalString.append(signal.signature());
|
---|
1732 | static_cast<QScript::QObjectNotifyCaller*>(sender)->callConnectNotify(signalString);
|
---|
1733 | }
|
---|
1734 | return ok;
|
---|
1735 | }
|
---|
1736 |
|
---|
1737 | bool QScript::QObjectConnectionManager::removeSignalHandler(
|
---|
1738 | QObject *sender, int signalIndex,
|
---|
1739 | const QScriptValueImpl &receiver,
|
---|
1740 | const QScriptValueImpl &slot)
|
---|
1741 | {
|
---|
1742 | if (connections.size() <= signalIndex)
|
---|
1743 | return false;
|
---|
1744 | QVector<QObjectConnection> &cs = connections[signalIndex];
|
---|
1745 | for (int i = 0; i < cs.size(); ++i) {
|
---|
1746 | const QObjectConnection &c = cs.at(i);
|
---|
1747 | if (c.hasTarget(receiver, slot)) {
|
---|
1748 | int absSlotIndex = c.slotIndex + metaObject()->methodOffset();
|
---|
1749 | bool ok = QMetaObject::disconnect(sender, signalIndex, this, absSlotIndex);
|
---|
1750 | if (ok) {
|
---|
1751 | cs.remove(i);
|
---|
1752 | QMetaMethod signal = sender->metaObject()->method(signalIndex);
|
---|
1753 | QByteArray signalString;
|
---|
1754 | signalString.append('2'); // signal code
|
---|
1755 | signalString.append(signal.signature());
|
---|
1756 | static_cast<QScript::QObjectNotifyCaller*>(sender)->callDisconnectNotify(signalString);
|
---|
1757 | }
|
---|
1758 | return ok;
|
---|
1759 | }
|
---|
1760 | }
|
---|
1761 | return false;
|
---|
1762 | }
|
---|
1763 |
|
---|
1764 |
|
---|
1765 |
|
---|
1766 | QString QScript::QtPropertyFunction::functionName() const
|
---|
1767 | {
|
---|
1768 | QMetaProperty prop = m_meta->property(m_index);
|
---|
1769 | return QLatin1String(prop.name());
|
---|
1770 | }
|
---|
1771 |
|
---|
1772 | void QScript::QtPropertyFunction::execute(QScriptContextPrivate *context)
|
---|
1773 | {
|
---|
1774 | context->calleeMetaIndex = m_index;
|
---|
1775 |
|
---|
1776 | QScriptEnginePrivate *eng_p = context->engine();
|
---|
1777 | #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
|
---|
1778 | eng_p->notifyFunctionEntry(context);
|
---|
1779 | #endif
|
---|
1780 | QScriptValueImpl result = eng_p->undefinedValue();
|
---|
1781 |
|
---|
1782 | QScriptValueImpl object = context->thisObject();
|
---|
1783 | QObject *qobject = object.toQObject();
|
---|
1784 | while ((!qobject || (qobject->metaObject() != m_meta))
|
---|
1785 | && object.prototype().isObject()) {
|
---|
1786 | object = object.prototype();
|
---|
1787 | qobject = object.toQObject();
|
---|
1788 | }
|
---|
1789 | Q_ASSERT(qobject);
|
---|
1790 |
|
---|
1791 | QMetaProperty prop = m_meta->property(m_index);
|
---|
1792 | Q_ASSERT(prop.isScriptable());
|
---|
1793 | if (context->argumentCount() == 0) {
|
---|
1794 | // get
|
---|
1795 | if (prop.isValid()) {
|
---|
1796 | QScriptable *scriptable = scriptableFromQObject(qobject);
|
---|
1797 | QScriptEngine *oldEngine = 0;
|
---|
1798 | if (scriptable) {
|
---|
1799 | oldEngine = QScriptablePrivate::get(scriptable)->engine;
|
---|
1800 | QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(eng_p);
|
---|
1801 | }
|
---|
1802 |
|
---|
1803 | QVariant v = prop.read(qobject);
|
---|
1804 |
|
---|
1805 | if (scriptable)
|
---|
1806 | QScriptablePrivate::get(scriptable)->engine = oldEngine;
|
---|
1807 |
|
---|
1808 | result = eng_p->valueFromVariant(v);
|
---|
1809 | }
|
---|
1810 | } else {
|
---|
1811 | // set
|
---|
1812 | QVariant v = variantFromValue(eng_p, prop.userType(), context->argument(0));
|
---|
1813 |
|
---|
1814 | QScriptable *scriptable = scriptableFromQObject(qobject);
|
---|
1815 | QScriptEngine *oldEngine = 0;
|
---|
1816 | if (scriptable) {
|
---|
1817 | oldEngine = QScriptablePrivate::get(scriptable)->engine;
|
---|
1818 | QScriptablePrivate::get(scriptable)->engine = QScriptEnginePrivate::get(eng_p);
|
---|
1819 | }
|
---|
1820 |
|
---|
1821 | prop.write(qobject, v);
|
---|
1822 |
|
---|
1823 | if (scriptable)
|
---|
1824 | QScriptablePrivate::get(scriptable)->engine = oldEngine;
|
---|
1825 |
|
---|
1826 | result = context->argument(0);
|
---|
1827 | }
|
---|
1828 | if (!eng_p->hasUncaughtException())
|
---|
1829 | context->m_result = result;
|
---|
1830 | #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
|
---|
1831 | eng_p->notifyFunctionExit(context);
|
---|
1832 | #endif
|
---|
1833 | }
|
---|
1834 |
|
---|
1835 | QString QScript::QtFunction::functionName() const
|
---|
1836 | {
|
---|
1837 | const QMetaObject *meta = metaObject();
|
---|
1838 | if (!meta)
|
---|
1839 | return QString();
|
---|
1840 | QMetaMethod method = meta->method(m_initialIndex);
|
---|
1841 | return QLatin1String(methodName(method));
|
---|
1842 | }
|
---|
1843 |
|
---|
1844 | void QScript::QtFunction::mark(QScriptEnginePrivate *engine, int generation)
|
---|
1845 | {
|
---|
1846 | if (m_object.isValid())
|
---|
1847 | engine->markObject(m_object, generation);
|
---|
1848 | QScriptFunction::mark(engine, generation);
|
---|
1849 | }
|
---|
1850 |
|
---|
1851 | void QScript::QtFunction::execute(QScriptContextPrivate *context)
|
---|
1852 | {
|
---|
1853 | QScriptEnginePrivate *eng_p = context->engine();
|
---|
1854 | QObject *qobj = qobject();
|
---|
1855 | if (!qobj) {
|
---|
1856 | context->calleeMetaIndex = m_initialIndex;
|
---|
1857 | #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
|
---|
1858 | eng_p->notifyFunctionEntry(context);
|
---|
1859 | #endif
|
---|
1860 | context->throwError(QLatin1String("cannot call function of deleted QObject"));
|
---|
1861 | #ifndef Q_SCRIPT_NO_EVENT_NOTIFY
|
---|
1862 | eng_p->notifyFunctionExit(context);
|
---|
1863 | #endif
|
---|
1864 | return;
|
---|
1865 | }
|
---|
1866 |
|
---|
1867 | QScriptValueImpl result = eng_p->undefinedValue();
|
---|
1868 |
|
---|
1869 | const QMetaObject *meta = qobj->metaObject();
|
---|
1870 |
|
---|
1871 | QObject *thisQObject = context->thisObject().toQObject();
|
---|
1872 | if (!thisQObject) // ### TypeError
|
---|
1873 | thisQObject = qobj;
|
---|
1874 |
|
---|
1875 | if (!meta->cast(thisQObject)) {
|
---|
1876 | #if 0
|
---|
1877 | // ### find common superclass, see if initialIndex is
|
---|
1878 | // in that class (or a superclass of that class),
|
---|
1879 | // then it's still safe to execute it
|
---|
1880 | funName = methodName(meta->method(m_initialIndex));
|
---|
1881 | context->throwError(
|
---|
1882 | QString::fromUtf8("cannot execute %0: %1 does not inherit %2")
|
---|
1883 | .arg(QLatin1String(funName))
|
---|
1884 | .arg(QLatin1String(thisQObject->metaObject()->className()))
|
---|
1885 | .arg(QLatin1String(meta->className())));
|
---|
1886 | return;
|
---|
1887 | #endif
|
---|
1888 | // invoking a function in the prototype
|
---|
1889 | thisQObject = qobj;
|
---|
1890 | }
|
---|
1891 |
|
---|
1892 | callQtMethod(context, QMetaMethod::Method, thisQObject,
|
---|
1893 | meta, m_initialIndex, m_maybeOverloaded);
|
---|
1894 | }
|
---|
1895 |
|
---|
1896 | int QScript::QtFunction::mostGeneralMethod(QMetaMethod *out) const
|
---|
1897 | {
|
---|
1898 | const QMetaObject *meta = metaObject();
|
---|
1899 | if (!meta)
|
---|
1900 | return -1;
|
---|
1901 | int index = m_initialIndex;
|
---|
1902 | QMetaMethod method = meta->method(index);
|
---|
1903 | if (maybeOverloaded() && (method.attributes() & QMetaMethod::Cloned)) {
|
---|
1904 | // find the most general method
|
---|
1905 | do {
|
---|
1906 | method = meta->method(--index);
|
---|
1907 | } while (method.attributes() & QMetaMethod::Cloned);
|
---|
1908 | }
|
---|
1909 | if (out)
|
---|
1910 | *out = method;
|
---|
1911 | return index;
|
---|
1912 | }
|
---|
1913 |
|
---|
1914 | QList<int> QScript::QtFunction::overloadedIndexes() const
|
---|
1915 | {
|
---|
1916 | if (!maybeOverloaded())
|
---|
1917 | return QList<int>();
|
---|
1918 | QList<int> result;
|
---|
1919 | QString name = functionName();
|
---|
1920 | const QMetaObject *meta = metaObject();
|
---|
1921 | for (int index = mostGeneralMethod() - 1; index >= 0; --index) {
|
---|
1922 | QString otherName = QString::fromLatin1(methodName(meta->method(index)));
|
---|
1923 | if (otherName == name)
|
---|
1924 | result.append(index);
|
---|
1925 | }
|
---|
1926 | return result;
|
---|
1927 | }
|
---|
1928 |
|
---|
1929 | /////////////////////////////////////////////////////////
|
---|
1930 |
|
---|
1931 | namespace QScript
|
---|
1932 | {
|
---|
1933 |
|
---|
1934 | ExtQMetaObject::Instance *ExtQMetaObject::Instance::get(const QScriptValueImpl &object,
|
---|
1935 | QScriptClassInfo *klass)
|
---|
1936 | {
|
---|
1937 | if (! klass || klass == object.classInfo())
|
---|
1938 | return static_cast<Instance*> (object.objectData());
|
---|
1939 |
|
---|
1940 | return 0;
|
---|
1941 | }
|
---|
1942 |
|
---|
1943 | void ExtQMetaObject::Instance::execute(QScriptContextPrivate *context)
|
---|
1944 | {
|
---|
1945 | if (ctor.isFunction()) {
|
---|
1946 | QScriptValueImplList args;
|
---|
1947 | for (int i = 0; i < context->argumentCount(); ++i)
|
---|
1948 | args << context->argument(i);
|
---|
1949 | QScriptEnginePrivate *eng = context->engine();
|
---|
1950 | context->m_result = eng->call(ctor, context->thisObject(), args,
|
---|
1951 | context->isCalledAsConstructor());
|
---|
1952 | } else {
|
---|
1953 | if (value->constructorCount() > 0) {
|
---|
1954 | callQtMethod(context, QMetaMethod::Constructor, /*thisQObject=*/0,
|
---|
1955 | value, value->constructorCount()-1, /*maybeOverloaded=*/true);
|
---|
1956 | if (context->state() == QScriptContext::NormalState) {
|
---|
1957 | ExtQObject::Instance *inst = ExtQObject::Instance::get(context->m_result);
|
---|
1958 | Q_ASSERT(inst != 0);
|
---|
1959 | inst->ownership = QScriptEngine::AutoOwnership;
|
---|
1960 | context->m_result.setPrototype(prototype);
|
---|
1961 | }
|
---|
1962 | } else {
|
---|
1963 | context->m_result = context->throwError(
|
---|
1964 | QScriptContext::TypeError,
|
---|
1965 | QString::fromUtf8("no constructor for %0")
|
---|
1966 | .arg(QLatin1String(value->className())));
|
---|
1967 | }
|
---|
1968 | }
|
---|
1969 | }
|
---|
1970 |
|
---|
1971 | struct StaticQtMetaObject : public QObject
|
---|
1972 | {
|
---|
1973 | static const QMetaObject *get()
|
---|
1974 | { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
|
---|
1975 | };
|
---|
1976 |
|
---|
1977 | class ExtQMetaObjectData: public QScriptClassData
|
---|
1978 | {
|
---|
1979 | public:
|
---|
1980 | ExtQMetaObjectData(QScriptEnginePrivate *, QScriptClassInfo *classInfo);
|
---|
1981 |
|
---|
1982 | virtual bool resolve(const QScriptValueImpl &object, QScriptNameIdImpl *nameId,
|
---|
1983 | QScript::Member *member, QScriptValueImpl *base,
|
---|
1984 | QScript::AccessMode access);
|
---|
1985 | virtual bool get(const QScriptValueImpl &object, const QScript::Member &member,
|
---|
1986 | QScriptValueImpl *result);
|
---|
1987 | virtual bool put(QScriptValueImpl *object, const QScript::Member &member,
|
---|
1988 | const QScriptValueImpl &value);
|
---|
1989 | virtual void mark(const QScriptValueImpl &object, int generation);
|
---|
1990 |
|
---|
1991 | private:
|
---|
1992 | QScriptClassInfo *m_classInfo;
|
---|
1993 | };
|
---|
1994 |
|
---|
1995 | ExtQMetaObjectData::ExtQMetaObjectData(QScriptEnginePrivate *,
|
---|
1996 | QScriptClassInfo *classInfo)
|
---|
1997 | : m_classInfo(classInfo)
|
---|
1998 | {
|
---|
1999 | }
|
---|
2000 |
|
---|
2001 | bool ExtQMetaObjectData::resolve(const QScriptValueImpl &object,
|
---|
2002 | QScriptNameIdImpl *nameId,
|
---|
2003 | QScript::Member *member,
|
---|
2004 | QScriptValueImpl *base,
|
---|
2005 | QScript::AccessMode /*access*/)
|
---|
2006 | {
|
---|
2007 | const QMetaObject *meta = object.toQMetaObject();
|
---|
2008 | if (!meta)
|
---|
2009 | return false;
|
---|
2010 |
|
---|
2011 | QScriptEnginePrivate *eng_p = object.engine();
|
---|
2012 | if (eng_p->idTable()->id_prototype == nameId) {
|
---|
2013 | // prototype property is a proxy to constructor's prototype property
|
---|
2014 | member->native(nameId, /*id=*/0, QScriptValue::Undeletable);
|
---|
2015 | return true;
|
---|
2016 | }
|
---|
2017 |
|
---|
2018 | QByteArray name = eng_p->toString(nameId).toLatin1();
|
---|
2019 |
|
---|
2020 | for (int i = 0; i < meta->enumeratorCount(); ++i) {
|
---|
2021 | QMetaEnum e = meta->enumerator(i);
|
---|
2022 |
|
---|
2023 | for (int j = 0; j < e.keyCount(); ++j) {
|
---|
2024 | const char *key = e.key(j);
|
---|
2025 |
|
---|
2026 | if (! qstrcmp (key, name.constData())) {
|
---|
2027 | member->native(nameId, e.value(j), QScriptValue::ReadOnly);
|
---|
2028 | *base = object;
|
---|
2029 | return true;
|
---|
2030 | }
|
---|
2031 | }
|
---|
2032 | }
|
---|
2033 |
|
---|
2034 | return false;
|
---|
2035 | }
|
---|
2036 |
|
---|
2037 | bool ExtQMetaObjectData::get(const QScriptValueImpl &object,
|
---|
2038 | const QScript::Member &member,
|
---|
2039 | QScriptValueImpl *result)
|
---|
2040 | {
|
---|
2041 | if (! member.isNativeProperty())
|
---|
2042 | return false;
|
---|
2043 |
|
---|
2044 | QScriptEnginePrivate *eng_p = object.engine();
|
---|
2045 | if (eng_p->idTable()->id_prototype == member.nameId()) {
|
---|
2046 | ExtQMetaObject::Instance *inst = ExtQMetaObject::Instance::get(object, m_classInfo);
|
---|
2047 | if (inst->ctor.isFunction())
|
---|
2048 | *result = inst->ctor.property(eng_p->idTable()->id_prototype);
|
---|
2049 | else
|
---|
2050 | *result = inst->prototype;
|
---|
2051 | } else {
|
---|
2052 | *result = QScriptValueImpl(member.id());
|
---|
2053 | }
|
---|
2054 | return true;
|
---|
2055 | }
|
---|
2056 |
|
---|
2057 | bool ExtQMetaObjectData::put(QScriptValueImpl *object, const Member &member,
|
---|
2058 | const QScriptValueImpl &value)
|
---|
2059 | {
|
---|
2060 | if (! member.isNativeProperty())
|
---|
2061 | return false;
|
---|
2062 |
|
---|
2063 | QScriptEnginePrivate *eng_p = object->engine();
|
---|
2064 | if (eng_p->idTable()->id_prototype == member.nameId()) {
|
---|
2065 | ExtQMetaObject::Instance *inst = ExtQMetaObject::Instance::get(*object, m_classInfo);
|
---|
2066 | if (inst->ctor.isFunction())
|
---|
2067 | inst->ctor.setProperty(eng_p->idTable()->id_prototype, value);
|
---|
2068 | else
|
---|
2069 | inst->prototype = value;
|
---|
2070 | }
|
---|
2071 |
|
---|
2072 | return true;
|
---|
2073 | }
|
---|
2074 |
|
---|
2075 | void ExtQMetaObjectData::mark(const QScriptValueImpl &object, int generation)
|
---|
2076 | {
|
---|
2077 | ExtQMetaObject::Instance *inst = ExtQMetaObject::Instance::get(object, m_classInfo);
|
---|
2078 | if (inst->ctor.isObject() || inst->ctor.isString())
|
---|
2079 | inst->ctor.mark(generation);
|
---|
2080 | }
|
---|
2081 |
|
---|
2082 | } // namespace QScript
|
---|
2083 |
|
---|
2084 | QScript::ExtQMetaObject::ExtQMetaObject(QScriptEnginePrivate *eng)
|
---|
2085 | : Ecma::Core(eng, QLatin1String("QMetaObject"), QScriptClassInfo::QMetaObjectType)
|
---|
2086 | {
|
---|
2087 | newQMetaObject(&publicPrototype, QScript::StaticQtMetaObject::get());
|
---|
2088 |
|
---|
2089 | eng->newConstructor(&ctor, this, publicPrototype);
|
---|
2090 | addPrototypeFunction(QLatin1String("className"), method_className, 0);
|
---|
2091 |
|
---|
2092 | classInfo()->setData(new QScript::ExtQMetaObjectData(eng, classInfo()));
|
---|
2093 | }
|
---|
2094 |
|
---|
2095 | QScript::ExtQMetaObject::~ExtQMetaObject()
|
---|
2096 | {
|
---|
2097 | }
|
---|
2098 |
|
---|
2099 | void QScript::ExtQMetaObject::execute(QScriptContextPrivate *context)
|
---|
2100 | {
|
---|
2101 | QScriptValueImpl tmp;
|
---|
2102 | newQMetaObject(&tmp, 0);
|
---|
2103 | context->setReturnValue(tmp);
|
---|
2104 | }
|
---|
2105 |
|
---|
2106 | void QScript::ExtQMetaObject::newQMetaObject(QScriptValueImpl *result, const QMetaObject *value,
|
---|
2107 | const QScriptValueImpl &ctor)
|
---|
2108 | {
|
---|
2109 | Instance *instance = new Instance();
|
---|
2110 | instance->value = value;
|
---|
2111 | if (ctor.isFunction()) {
|
---|
2112 | instance->ctor = ctor;
|
---|
2113 | } else {
|
---|
2114 | instance->prototype = engine()->newObject();
|
---|
2115 | instance->prototype.setPrototype(engine()->qobjectConstructor->publicPrototype);
|
---|
2116 | }
|
---|
2117 |
|
---|
2118 | engine()->newObject(result, publicPrototype, classInfo());
|
---|
2119 | result->setObjectData(instance);
|
---|
2120 | }
|
---|
2121 |
|
---|
2122 | QScriptValueImpl QScript::ExtQMetaObject::method_className(QScriptContextPrivate *context, QScriptEnginePrivate *eng, QScriptClassInfo *classInfo)
|
---|
2123 | {
|
---|
2124 | if (Instance *instance = Instance::get(context->thisObject(), classInfo)) {
|
---|
2125 | return QScriptValueImpl(eng, QString::fromLatin1(instance->value->className()));
|
---|
2126 | }
|
---|
2127 | return eng->undefinedValue();
|
---|
2128 | }
|
---|
2129 |
|
---|
2130 | QScriptQObjectData::QScriptQObjectData()
|
---|
2131 | : m_connectionManager(0)
|
---|
2132 | {
|
---|
2133 | }
|
---|
2134 |
|
---|
2135 | QScriptQObjectData::~QScriptQObjectData()
|
---|
2136 | {
|
---|
2137 | if (m_connectionManager) {
|
---|
2138 | delete m_connectionManager;
|
---|
2139 | m_connectionManager = 0;
|
---|
2140 | }
|
---|
2141 | }
|
---|
2142 |
|
---|
2143 | bool QScriptQObjectData::addSignalHandler(QObject *sender,
|
---|
2144 | int signalIndex,
|
---|
2145 | const QScriptValueImpl &receiver,
|
---|
2146 | const QScriptValueImpl &slot,
|
---|
2147 | const QScriptValueImpl &senderWrapper)
|
---|
2148 | {
|
---|
2149 | if (!m_connectionManager)
|
---|
2150 | m_connectionManager = new QScript::QObjectConnectionManager();
|
---|
2151 | return m_connectionManager->addSignalHandler(
|
---|
2152 | sender, signalIndex, receiver, slot, senderWrapper);
|
---|
2153 | }
|
---|
2154 |
|
---|
2155 | bool QScriptQObjectData::removeSignalHandler(QObject *sender,
|
---|
2156 | int signalIndex,
|
---|
2157 | const QScriptValueImpl &receiver,
|
---|
2158 | const QScriptValueImpl &slot)
|
---|
2159 | {
|
---|
2160 | if (!m_connectionManager)
|
---|
2161 | return false;
|
---|
2162 | return m_connectionManager->removeSignalHandler(
|
---|
2163 | sender, signalIndex, receiver, slot);
|
---|
2164 | }
|
---|
2165 |
|
---|
2166 | bool QScriptQObjectData::findWrapper(QScriptEngine::ValueOwnership ownership,
|
---|
2167 | const QScriptEngine::QObjectWrapOptions &options,
|
---|
2168 | QScriptValueImpl *out)
|
---|
2169 | {
|
---|
2170 | for (int i = 0; i < wrappers.size(); ++i) {
|
---|
2171 | const QScriptQObjectWrapperInfo &info = wrappers.at(i);
|
---|
2172 | if ((info.ownership == ownership) && (info.options == options)) {
|
---|
2173 | *out = info.object;
|
---|
2174 | return true;
|
---|
2175 | }
|
---|
2176 | }
|
---|
2177 | return false;
|
---|
2178 | }
|
---|
2179 |
|
---|
2180 | void QScriptQObjectData::registerWrapper(const QScriptValueImpl &wrapper,
|
---|
2181 | QScriptEngine::ValueOwnership ownership,
|
---|
2182 | const QScriptEngine::QObjectWrapOptions &options)
|
---|
2183 | {
|
---|
2184 | wrappers.append(QScriptQObjectWrapperInfo(wrapper, ownership, options));
|
---|
2185 | }
|
---|
2186 |
|
---|
2187 | void QScriptQObjectData::mark(int generation)
|
---|
2188 | {
|
---|
2189 | if (m_connectionManager)
|
---|
2190 | m_connectionManager->mark(generation);
|
---|
2191 |
|
---|
2192 | {
|
---|
2193 | QList<QScriptQObjectWrapperInfo>::iterator it;
|
---|
2194 | for (it = wrappers.begin(); it != wrappers.end(); ) {
|
---|
2195 | const QScriptQObjectWrapperInfo &info = *it;
|
---|
2196 | if (info.object.isMarked(generation)) {
|
---|
2197 | ++it;
|
---|
2198 | } else {
|
---|
2199 | it = wrappers.erase(it);
|
---|
2200 | }
|
---|
2201 | }
|
---|
2202 | }
|
---|
2203 | }
|
---|
2204 |
|
---|
2205 | QT_END_NAMESPACE
|
---|
2206 |
|
---|
2207 | #include "qscriptextqobject.moc"
|
---|
2208 |
|
---|
2209 | #endif // QT_NO_SCRIPT
|
---|