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