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