source: branches/4.5.1/src/script/qscriptextqobject.cpp@ 1168

Last change on this file since 1168 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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