Replace LGPL license tags with LGPL-ONLY
[qt-netbsd.git] / src / script / bridge / qscriptqobject.cpp
blob74ec999a1296fc68c809f89c8eefb80d051fe455
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-ONLY$
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.
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include "config.h"
43 #include "qscriptqobject_p.h"
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"
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"
64 namespace JSC
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);
74 QT_BEGIN_NAMESPACE
76 namespace QScript
79 struct QObjectConnection
81 int slotIndex;
82 JSC::JSValue receiver;
83 JSC::JSValue slot;
84 JSC::JSValue senderWrapper;
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) {}
91 bool hasTarget(JSC::JSValue r, JSC::JSValue s) const
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;
99 return (s == slot);
102 void mark(JSC::MarkStack& markStack)
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);
122 if (receiver)
123 markStack.append(receiver);
124 if (slot)
125 markStack.append(slot);
129 class QObjectNotifyCaller : public QObject
131 public:
132 void callConnectNotify(const char *signal)
133 { connectNotify(signal); }
134 void callDisconnectNotify(const char *signal)
135 { disconnectNotify(signal); }
138 class QObjectConnectionManager: public QObject
140 public:
141 QObjectConnectionManager(QScriptEnginePrivate *engine);
142 ~QObjectConnectionManager();
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);
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);
158 void execute(int slotIndex, void **argv);
160 void mark(JSC::MarkStack&);
162 private:
163 QScriptEnginePrivate *engine;
164 int slotCounter;
165 QVector<QVector<QObjectConnection> > connections;
168 static bool hasMethodAccess(const QMetaMethod &method, int index, const QScriptEngine::QObjectWrapOptions &opt)
170 return (method.access() != QMetaMethod::Private)
171 && ((index != 2) || !(opt & QScriptEngine::ExcludeDeleteLater));
174 static bool isEnumerableMetaProperty(const QMetaProperty &prop,
175 const QMetaObject *mo, int index)
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);
183 static inline QByteArray methodName(const QMetaMethod &method)
185 QByteArray signature = method.signature();
186 return signature.left(signature.indexOf('('));
189 static QVariant variantFromValue(QScriptEnginePrivate *eng,
190 int targetType, const QScriptValue &value)
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;
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()));
211 return QVariant();
214 static const bool GeneratePropertyFunctions = true;
216 static unsigned flagsForMetaProperty(const QMetaProperty &prop)
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);
226 static int indexOfMetaEnum(const QMetaObject *meta, const QByteArray &str)
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;
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;
242 return -1;
245 static inline QScriptable *scriptableFromQObject(QObject *qobj)
247 void *ptr = qobj->qt_metacast("QScriptable");
248 return reinterpret_cast<QScriptable*>(ptr);
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))
259 QtFunction::~QtFunction()
261 delete data;
264 JSC::CallType QtFunction::getCallData(JSC::CallData &callData)
266 callData.native.function = call;
267 return JSC::CallTypeHost;
270 void QtFunction::markChildren(JSC::MarkStack& markStack)
272 if (data->object)
273 markStack.append(data->object);
274 JSC::InternalFunction::markChildren(markStack);
277 QScriptObject *QtFunction::wrapperObject() const
279 Q_ASSERT(JSC::asObject(data->object)->inherits(&QScriptObject::info));
280 return static_cast<QScriptObject*>(JSC::asObject(data->object));
283 QObject *QtFunction::qobject() const
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();
291 const QMetaObject *QtFunction::metaObject() const
293 QObject *qobj = qobject();
294 if (!qobj)
295 return 0;
296 return qobj->metaObject();
299 int QtFunction::initialIndex() const
301 return data->initialIndex;
304 bool QtFunction::maybeOverloaded() const
306 return data->maybeOverloaded;
309 int QtFunction::mostGeneralMethod(QMetaMethod *out) const
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);
322 if (out)
323 *out = method;
324 return index;
327 QList<int> QScript::QtFunction::overloadedIndexes() const
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);
339 return result;
342 QString QtFunction::functionName() const
344 const QMetaObject *meta = metaObject();
345 if (!meta)
346 return QString();
347 QMetaMethod method = meta->method(initialIndex());
348 return QLatin1String(methodName(method));
351 class QScriptMetaType
353 public:
354 enum Kind {
355 Invalid,
356 Variant,
357 MetaType,
358 Unresolved,
359 MetaEnum
362 inline QScriptMetaType()
363 : m_kind(Invalid) { }
365 inline Kind kind() const
366 { return m_kind; }
368 int typeId() const;
370 inline bool isValid() const
371 { return (m_kind != Invalid); }
373 inline bool isVariant() const
374 { return (m_kind == Variant); }
376 inline bool isMetaType() const
377 { return (m_kind == MetaType); }
379 inline bool isUnresolved() const
380 { return (m_kind == Unresolved); }
382 inline bool isMetaEnum() const
383 { return (m_kind == MetaEnum); }
385 QByteArray name() const;
387 inline int enumeratorIndex() const
388 { Q_ASSERT(isMetaEnum()); return m_typeId; }
390 inline bool operator==(const QScriptMetaType &other) const
392 return (m_kind == other.m_kind) && (m_typeId == other.m_typeId);
395 static inline QScriptMetaType variant()
396 { return QScriptMetaType(Variant); }
398 static inline QScriptMetaType metaType(int typeId, const QByteArray &name)
399 { return QScriptMetaType(MetaType, typeId, name); }
401 static inline QScriptMetaType metaEnum(int enumIndex, const QByteArray &name)
402 { return QScriptMetaType(MetaEnum, enumIndex, name); }
404 static inline QScriptMetaType unresolved(const QByteArray &name)
405 { return QScriptMetaType(Unresolved, /*typeId=*/0, name); }
407 private:
408 inline QScriptMetaType(Kind kind, int typeId = 0, const QByteArray &name = QByteArray())
409 : m_kind(kind), m_typeId(typeId), m_name(name) { }
411 Kind m_kind;
412 int m_typeId;
413 QByteArray m_name;
416 int QScriptMetaType::typeId() const
418 if (isVariant())
419 return QMetaType::type("QVariant");
420 return isMetaEnum() ? 2/*int*/ : m_typeId;
423 QByteArray QScriptMetaType::name() const
425 if (!m_name.isEmpty())
426 return m_name;
427 else if (m_kind == Variant)
428 return "QVariant";
429 return QMetaType::typeName(typeId());
432 class QScriptMetaMethod
434 public:
435 inline QScriptMetaMethod()
437 inline QScriptMetaMethod(const QByteArray &name, const QVector<QScriptMetaType> &types)
438 : m_name(name), m_types(types), m_firstUnresolvedIndex(-1)
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;
448 inline bool isValid() const
449 { return !m_types.isEmpty(); }
451 QByteArray name() const
452 { return m_name; }
454 inline QScriptMetaType returnType() const
455 { return m_types.at(0); }
457 inline int argumentCount() const
458 { return m_types.count() - 1; }
460 inline QScriptMetaType argumentType(int arg) const
461 { return m_types.at(arg + 1); }
463 inline bool fullyResolved() const
464 { return m_firstUnresolvedIndex == -1; }
466 inline bool hasUnresolvedReturnType() const
467 { return (m_firstUnresolvedIndex == 0); }
469 inline int firstUnresolvedIndex() const
470 { return m_firstUnresolvedIndex; }
472 inline int count() const
473 { return m_types.count(); }
475 inline QScriptMetaType type(int index) const
476 { return m_types.at(index); }
478 inline QVector<QScriptMetaType> types() const
479 { return m_types; }
481 private:
482 QByteArray m_name;
483 QVector<QScriptMetaType> m_types;
484 int m_firstUnresolvedIndex;
487 struct QScriptMetaArguments
489 int matchDistance;
490 int index;
491 QScriptMetaMethod method;
492 QVarLengthArray<QVariant, 9> args;
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) { }
500 inline bool isValid() const
501 { return (index != -1); }
504 static QMetaMethod metaMethod(const QMetaObject *meta,
505 QMetaMethod::MethodType type,
506 int index)
508 if (type != QMetaMethod::Constructor)
509 return meta->method(index);
510 else
511 return meta->constructor(index);
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)
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);
533 if (index == initialIndex)
534 funName = methodName(method);
535 else {
536 if (methodName(method) != funName)
537 continue;
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));
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));
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));
578 } else {
579 if (argTypeName == "QVariant")
580 types.append(QScriptMetaType::variant());
581 else
582 types.append(QScriptMetaType::metaType(atype, argTypeName));
586 QScriptMetaMethod mtd = QScriptMetaMethod(methodName(method), types);
588 if (int(scriptArgs.size()) < mtd.argumentCount()) {
589 tooFewArgs.append(index);
590 continue;
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;
601 if (args.count() != mtd.count())
602 args.resize(mtd.count());
604 QScriptMetaType retType = mtd.returnType();
605 args[0] = QVariant(retType.typeId(), (void *)0); // the result
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();
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();
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;
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);
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;
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;
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;
720 } else if (actual.isString()) {
721 switch (tid) {
722 case QMetaType::QString:
723 // perfect
724 break;
725 default:
726 matchDistance += 10;
727 break;
729 } else if (actual.isBoolean()) {
730 switch (tid) {
731 case QMetaType::Bool:
732 // perfect
733 break;
734 default:
735 matchDistance += 10;
736 break;
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;
753 } else if (actual.isRegExp()) {
754 switch (tid) {
755 case QMetaType::QRegExp:
756 // perfect
757 break;
758 default:
759 matchDistance += 10;
760 break;
762 } else if (actual.isVariant()) {
763 if (argType.isVariant()
764 || (actual.toVariant().userType() == tid)) {
765 // perfect
766 } else {
767 matchDistance += 10;
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;
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;
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;
801 } else {
802 matchDistance += 10;
806 if (converted)
807 args[i+1] = v;
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;
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);
847 } else if (mtd.fullyResolved()) {
848 conversionFailed.append(index);
851 if (!maybeOverloaded)
852 break;
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()));
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));
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()));
897 result = JSC::throwError(exec, JSC::SyntaxError, message);
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()));
914 result = JSC::throwError(exec, JSC::TypeError, message);
915 } else {
916 chosenMethod = metaArgs.method;
917 chosenIndex = metaArgs.index;
918 args = metaArgs.args;
922 if (chosenIndex != -1) {
923 // call it
924 // context->calleeMetaIndex = chosenIndex;
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);
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);
953 // ### fixme
954 //#ifndef Q_SCRIPT_NO_EVENT_NOTIFY
955 // engine->notifyFunctionEntry(context);
956 //#endif
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);
965 if (scriptable)
966 QScriptablePrivate::get(scriptable)->engine = oldEngine;
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);
980 } else {
981 result = JSC::jsUndefined();
987 return result;
990 JSC::JSValue QtFunction::execute(JSC::ExecState *exec, JSC::JSValue thisValue,
991 const JSC::ArgList &scriptArgs)
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);
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();
1009 if (!thisQObject)
1010 thisQObject = qobj; // ### TypeError
1012 if (!meta->cast(thisQObject)) {
1013 // invoking a function in the prototype
1014 thisQObject = qobj;
1017 return callQtMethod(exec, QMetaMethod::Method, thisQObject, scriptArgs,
1018 meta, data->initialIndex, data->maybeOverloaded);
1021 const JSC::ClassInfo QtFunction::info = { "QtFunction", &InternalFunction::info, 0, 0 };
1023 JSC::JSValue JSC_HOST_CALL QtFunction::call(JSC::ExecState *exec, JSC::JSObject *callee,
1024 JSC::JSValue thisValue, const JSC::ArgList &args)
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;
1039 const JSC::ClassInfo QtPropertyFunction::info = { "QtPropertyFunction", &InternalFunction::info, 0, 0 };
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))
1050 QtPropertyFunction::~QtPropertyFunction()
1052 delete data;
1055 JSC::CallType QtPropertyFunction::getCallData(JSC::CallData &callData)
1057 callData.native.function = call;
1058 return JSC::CallTypeHost;
1061 JSC::JSValue JSC_HOST_CALL QtPropertyFunction::call(
1062 JSC::ExecState *exec, JSC::JSObject *callee,
1063 JSC::JSValue thisValue, const JSC::ArgList &args)
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;
1078 JSC::JSValue QtPropertyFunction::execute(JSC::ExecState *exec,
1079 JSC::JSValue thisValue,
1080 const JSC::ArgList &args)
1082 JSC::JSValue result = JSC::jsUndefined();
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();
1094 Q_ASSERT_X(qobject, Q_FUNC_INFO, "this-object must be a QObject");
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);
1108 QVariant v = prop.read(qobject);
1110 if (scriptable)
1111 QScriptablePrivate::get(scriptable)->engine = oldEngine;
1113 result = engine->jscValueFromVariant(v);
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);
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);
1137 prop.write(qobject, v);
1139 if (scriptable)
1140 QScriptablePrivate::get(scriptable)->engine = oldEngine;
1142 result = arg;
1144 return result;
1147 const QMetaObject *QtPropertyFunction::metaObject() const
1149 return data->meta;
1152 int QtPropertyFunction::propertyIndex() const
1154 return data->index;
1158 QObjectDelegate::QObjectDelegate(
1159 QObject *object, QScriptEngine::ValueOwnership ownership,
1160 const QScriptEngine::QObjectWrapOptions &options)
1161 : data(new Data(object, ownership, options))
1165 QObjectDelegate::~QObjectDelegate()
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;
1181 delete data;
1184 QScriptObjectDelegate::Type QObjectDelegate::type() const
1186 return QtObject;
1189 bool QObjectDelegate::getOwnPropertySlot(QScriptObject *object, JSC::ExecState *exec,
1190 const JSC::Identifier &propertyName,
1191 JSC::PropertySlot &slot)
1193 #ifndef QT_NO_PROPERTIES
1194 QByteArray name = QString(propertyName.ustring()).toLatin1();
1195 QObject *qobject = data->value;
1196 if (!qobject) {
1197 QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
1198 .arg(QString::fromLatin1(name));
1199 slot.setValue(JSC::throwError(exec, JSC::GeneralError, message));
1200 return true;
1203 const QMetaObject *meta = qobject->metaObject();
1205 QHash<QByteArray, JSC::JSValue>::const_iterator it = data->cachedMembers.constFind(name);
1206 if (it != data->cachedMembers.constEnd()) {
1207 if (GeneratePropertyFunctions && (meta->indexOfProperty(name) != -1))
1208 slot.setGetterSlot(JSC::asObject(it.value()));
1209 else
1210 slot.setValue(it.value());
1211 return true;
1215 const QScriptEngine::QObjectWrapOptions &opt = data->options;
1216 QScriptEnginePrivate *eng = scriptEngineFromExec(exec);
1217 int index = -1;
1218 if (name.contains('(')) {
1219 QByteArray normalized = QMetaObject::normalizedSignature(name);
1220 if (-1 != (index = meta->indexOfMethod(normalized))) {
1221 QMetaMethod method = meta->method(index);
1222 if (hasMethodAccess(method, index, opt)) {
1223 if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
1224 || (index >= meta->methodOffset())) {
1225 QtFunction *fun = new (exec)QtFunction(
1226 object, index, /*maybeOverloaded=*/false,
1227 &exec->globalData(), eng->originalGlobalObject()->functionStructure(),
1228 propertyName);
1229 slot.setValue(fun);
1230 data->cachedMembers.insert(name, fun);
1231 return true;
1237 index = meta->indexOfProperty(name);
1238 if (index != -1) {
1239 QMetaProperty prop = meta->property(index);
1240 if (prop.isScriptable()) {
1241 if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
1242 || (index >= meta->propertyOffset())) {
1243 if (GeneratePropertyFunctions) {
1244 QtPropertyFunction *fun = new (exec)QtPropertyFunction(
1245 meta, index, &exec->globalData(),
1246 eng->originalGlobalObject()->functionStructure(),
1247 propertyName);
1248 data->cachedMembers.insert(name, fun);
1249 slot.setGetterSlot(fun);
1250 } else {
1251 JSC::JSValue val;
1252 if (!prop.isValid())
1253 val = JSC::jsUndefined();
1254 else
1255 val = eng->jscValueFromVariant(prop.read(qobject));
1256 slot.setValue(val);
1258 return true;
1263 index = qobject->dynamicPropertyNames().indexOf(name);
1264 if (index != -1) {
1265 JSC::JSValue val = eng->jscValueFromVariant(qobject->property(name));
1266 slot.setValue(val);
1267 return true;
1270 const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
1271 ? meta->methodOffset() : 0;
1272 for (index = meta->methodCount() - 1; index >= offset; --index) {
1273 QMetaMethod method = meta->method(index);
1274 if (hasMethodAccess(method, index, opt)
1275 && (methodName(method) == name)) {
1276 QtFunction *fun = new (exec)QtFunction(
1277 object, index, /*maybeOverloaded=*/true,
1278 &exec->globalData(), eng->originalGlobalObject()->functionStructure(),
1279 propertyName);
1280 slot.setValue(fun);
1281 data->cachedMembers.insert(name, fun);
1282 return true;
1286 if (!(opt & QScriptEngine::ExcludeChildObjects)) {
1287 QList<QObject*> children = qobject->children();
1288 for (index = 0; index < children.count(); ++index) {
1289 QObject *child = children.at(index);
1290 if (child->objectName() == QString(propertyName.ustring())) {
1291 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
1292 QScriptValue tmp = QScriptEnginePrivate::get(eng)->newQObject(child, QScriptEngine::QtOwnership, opt);
1293 slot.setValue(eng->scriptValueToJSCValue(tmp));
1294 return true;
1299 return QScriptObjectDelegate::getOwnPropertySlot(object, exec, propertyName, slot);
1300 #else //QT_NO_PROPERTIES
1301 return false;
1302 #endif //QT_NO_PROPERTIES
1305 void QObjectDelegate::put(QScriptObject *object, JSC::ExecState* exec,
1306 const JSC::Identifier& propertyName,
1307 JSC::JSValue value, JSC::PutPropertySlot &slot)
1309 #ifndef QT_NO_PROPERTIES
1310 QByteArray name = ((QString)propertyName.ustring()).toLatin1();
1311 QObject *qobject = data->value;
1312 if (!qobject) {
1313 QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
1314 .arg(QString::fromLatin1(name));
1315 JSC::throwError(exec, JSC::GeneralError, message);
1316 return;
1319 const QScriptEngine::QObjectWrapOptions &opt = data->options;
1320 const QMetaObject *meta = qobject->metaObject();
1321 QScriptEnginePrivate *eng = scriptEngineFromExec(exec);
1322 int index = -1;
1323 if (name.contains('(')) {
1324 QByteArray normalized = QMetaObject::normalizedSignature(name);
1325 if (-1 != (index = meta->indexOfMethod(normalized))) {
1326 QMetaMethod method = meta->method(index);
1327 if (hasMethodAccess(method, index, opt)) {
1328 if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
1329 || (index >= meta->methodOffset())) {
1330 data->cachedMembers.insert(name, value);
1331 return;
1337 index = meta->indexOfProperty(name);
1338 if (index != -1) {
1339 QMetaProperty prop = meta->property(index);
1340 if (prop.isScriptable()) {
1341 if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
1342 || (index >= meta->propertyOffset())) {
1343 if (GeneratePropertyFunctions) {
1344 // ### ideally JSC would do this for us already, i.e. find out
1345 // that the property is a setter and call the setter.
1346 // Maybe QtPropertyFunction needs to inherit JSC::GetterSetter.
1347 JSC::JSValue fun;
1348 QHash<QByteArray, JSC::JSValue>::const_iterator it;
1349 it = data->cachedMembers.constFind(name);
1350 if (it != data->cachedMembers.constEnd()) {
1351 fun = it.value();
1352 } else {
1353 fun = new (exec)QtPropertyFunction(
1354 meta, index, &exec->globalData(),
1355 eng->originalGlobalObject()->functionStructure(),
1356 propertyName);
1357 data->cachedMembers.insert(name, fun);
1359 JSC::CallData callData;
1360 JSC::CallType callType = fun.getCallData(callData);
1361 JSC::JSValue argv[1] = { value };
1362 JSC::ArgList args(argv, 1);
1363 (void)JSC::call(exec, fun, callType, callData, object, args);
1364 } else {
1365 QVariant v;
1366 if (prop.isEnumType() && value.isString()
1367 && !eng->hasDemarshalFunction(prop.userType())) {
1368 // give QMetaProperty::write() a chance to convert from
1369 // string to enum value
1370 v = (QString)value.toString(exec);
1371 } else {
1372 v = eng->jscValueToVariant(value, prop.userType());
1374 (void)prop.write(qobject, v);
1376 return;
1381 const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
1382 ? meta->methodOffset() : 0;
1383 for (index = meta->methodCount() - 1; index >= offset; --index) {
1384 QMetaMethod method = meta->method(index);
1385 if (hasMethodAccess(method, index, opt)
1386 && (methodName(method) == name)) {
1387 data->cachedMembers.insert(name, value);
1388 return;
1392 index = qobject->dynamicPropertyNames().indexOf(name);
1393 if ((index != -1) || (opt & QScriptEngine::AutoCreateDynamicProperties)) {
1394 QVariant v = eng->scriptValueFromJSCValue(value).toVariant();
1395 (void)qobject->setProperty(name, v);
1396 return;
1399 QScriptObjectDelegate::put(object, exec, propertyName, value, slot);
1400 #endif //QT_NO_PROPERTIES
1403 bool QObjectDelegate::deleteProperty(QScriptObject *object, JSC::ExecState *exec,
1404 const JSC::Identifier& propertyName,
1405 bool checkDontDelete)
1407 #ifndef QT_NO_PROPERTIES
1408 QByteArray name = ((QString)propertyName.ustring()).toLatin1();
1409 QObject *qobject = data->value;
1410 if (!qobject) {
1411 QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
1412 .arg(QString::fromLatin1(name));
1413 JSC::throwError(exec, JSC::GeneralError, message);
1414 return false;
1417 const QMetaObject *meta = qobject->metaObject();
1419 QHash<QByteArray, JSC::JSValue>::iterator it = data->cachedMembers.find(name);
1420 if (it != data->cachedMembers.end()) {
1421 if (GeneratePropertyFunctions && (meta->indexOfProperty(name) != -1))
1422 return false;
1423 data->cachedMembers.erase(it);
1424 return true;
1428 const QScriptEngine::QObjectWrapOptions &opt = data->options;
1429 int index = meta->indexOfProperty(name);
1430 if (index != -1) {
1431 QMetaProperty prop = meta->property(index);
1432 if (prop.isScriptable() &&
1433 (!(opt & QScriptEngine::ExcludeSuperClassProperties)
1434 || (index >= meta->propertyOffset()))) {
1435 return false;
1439 index = qobject->dynamicPropertyNames().indexOf(name);
1440 if (index != -1) {
1441 (void)qobject->setProperty(name, QVariant());
1442 return true;
1445 return QScriptObjectDelegate::deleteProperty(object, exec, propertyName, checkDontDelete);
1446 #else //QT_NO_PROPERTIES
1447 return false;
1448 #endif //QT_NO_PROPERTIES
1451 bool QObjectDelegate::getPropertyAttributes(const QScriptObject *object,
1452 JSC::ExecState *exec,
1453 const JSC::Identifier &propertyName,
1454 unsigned &attributes) const
1456 #ifndef QT_NO_PROPERTIES
1457 // ### try to avoid duplicating logic from getOwnPropertySlot()
1458 QByteArray name = ((QString)propertyName.ustring()).toLatin1();
1459 QObject *qobject = data->value;
1460 if (!qobject)
1461 return false;
1463 const QScriptEngine::QObjectWrapOptions &opt = data->options;
1464 const QMetaObject *meta = qobject->metaObject();
1465 int index = -1;
1466 if (name.contains('(')) {
1467 QByteArray normalized = QMetaObject::normalizedSignature(name);
1468 if (-1 != (index = meta->indexOfMethod(normalized))) {
1469 QMetaMethod method = meta->method(index);
1470 if (hasMethodAccess(method, index, opt)) {
1471 if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
1472 || (index >= meta->methodOffset())) {
1473 attributes = QObjectMemberAttribute;
1474 if (opt & QScriptEngine::SkipMethodsInEnumeration)
1475 attributes |= JSC::DontEnum;
1476 return true;
1482 index = meta->indexOfProperty(name);
1483 if (index != -1) {
1484 QMetaProperty prop = meta->property(index);
1485 if (prop.isScriptable()) {
1486 if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
1487 || (index >= meta->propertyOffset())) {
1488 attributes = flagsForMetaProperty(prop);
1489 return true;
1494 index = qobject->dynamicPropertyNames().indexOf(name);
1495 if (index != -1) {
1496 attributes = QObjectMemberAttribute;
1497 return true;
1500 const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
1501 ? meta->methodOffset() : 0;
1502 for (index = meta->methodCount() - 1; index >= offset; --index) {
1503 QMetaMethod method = meta->method(index);
1504 if (hasMethodAccess(method, index, opt)
1505 && (methodName(method) == name)) {
1506 attributes = QObjectMemberAttribute;
1507 if (opt & QScriptEngine::SkipMethodsInEnumeration)
1508 attributes |= JSC::DontEnum;
1509 return true;
1513 if (!(opt & QScriptEngine::ExcludeChildObjects)) {
1514 QList<QObject*> children = qobject->children();
1515 for (index = 0; index < children.count(); ++index) {
1516 QObject *child = children.at(index);
1517 if (child->objectName() == (QString)(propertyName.ustring())) {
1518 attributes = JSC::ReadOnly | JSC::DontDelete | JSC::DontEnum;
1519 return true;
1524 return QScriptObjectDelegate::getPropertyAttributes(object, exec, propertyName, attributes);
1525 #else //QT_NO_PROPERTIES
1526 return false;
1527 #endif //QT_NO_PROPERTIES
1530 void QObjectDelegate::getOwnPropertyNames(QScriptObject *object, JSC::ExecState *exec,
1531 JSC::PropertyNameArray &propertyNames,
1532 bool includeNonEnumerable)
1534 #ifndef QT_NO_PROPERTIES
1535 QObject *qobject = data->value;
1536 if (!qobject) {
1537 QString message = QString::fromLatin1("cannot get property names of deleted QObject");
1538 JSC::throwError(exec, JSC::GeneralError, message);
1539 return;
1542 const QScriptEngine::QObjectWrapOptions &opt = data->options;
1543 const QMetaObject *meta = qobject->metaObject();
1545 int i = (opt & QScriptEngine::ExcludeSuperClassProperties)
1546 ? meta->propertyOffset() : 0;
1547 for ( ; i < meta->propertyCount(); ++i) {
1548 QMetaProperty prop = meta->property(i);
1549 if (isEnumerableMetaProperty(prop, meta, i)) {
1550 QString name = QString::fromLatin1(prop.name());
1551 propertyNames.add(JSC::Identifier(exec, name));
1557 QList<QByteArray> dpNames = qobject->dynamicPropertyNames();
1558 for (int i = 0; i < dpNames.size(); ++i) {
1559 QString name = QString::fromLatin1(dpNames.at(i));
1560 propertyNames.add(JSC::Identifier(exec, name));
1564 if (!(opt & QScriptEngine::SkipMethodsInEnumeration)) {
1565 int i = (opt & QScriptEngine::ExcludeSuperClassMethods)
1566 ? meta->methodOffset() : 0;
1567 for ( ; i < meta->methodCount(); ++i) {
1568 QMetaMethod method = meta->method(i);
1569 if (hasMethodAccess(method, i, opt)) {
1570 QMetaMethod method = meta->method(i);
1571 QString sig = QString::fromLatin1(method.signature());
1572 propertyNames.add(JSC::Identifier(exec, sig));
1577 QScriptObjectDelegate::getOwnPropertyNames(object, exec, propertyNames, includeNonEnumerable);
1578 #endif //QT_NO_PROPERTIES
1581 void QObjectDelegate::markChildren(QScriptObject *object, JSC::MarkStack& markStack)
1583 QHash<QByteArray, JSC::JSValue>::const_iterator it;
1584 for (it = data->cachedMembers.constBegin(); it != data->cachedMembers.constEnd(); ++it) {
1585 JSC::JSValue val = it.value();
1586 if (val)
1587 markStack.append(val);
1590 QScriptObjectDelegate::markChildren(object, markStack);
1593 bool QObjectDelegate::compareToObject(QScriptObject *, JSC::ExecState *exec, JSC::JSObject *o2)
1595 if (!o2->inherits(&QScriptObject::info))
1596 return false;
1597 QScriptObject *object = static_cast<QScriptObject*>(o2);
1598 QScriptObjectDelegate *delegate = object->delegate();
1599 if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject))
1600 return false;
1601 return value() == static_cast<QObjectDelegate *>(delegate)->value();
1604 static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChild(JSC::ExecState *exec, JSC::JSObject*,
1605 JSC::JSValue thisValue, const JSC::ArgList &args)
1607 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
1608 thisValue = engine->toUsableValue(thisValue);
1609 if (!thisValue.inherits(&QScriptObject::info))
1610 return throwError(exec, JSC::TypeError, "this object is not a QObject");
1611 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(thisValue));
1612 QScriptObjectDelegate *delegate = scriptObject->delegate();
1613 if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject))
1614 return throwError(exec, JSC::TypeError, "this object is not a QObject");
1615 QObject *obj = static_cast<QObjectDelegate*>(delegate)->value();
1616 QString name;
1617 if (args.size() != 0)
1618 name = args.at(0).toString(exec);
1619 QObject *child = qFindChild<QObject*>(obj, name);
1620 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
1621 return engine->newQObject(child, QScriptEngine::QtOwnership, opt);
1624 static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncFindChildren(JSC::ExecState *exec, JSC::JSObject*,
1625 JSC::JSValue thisValue, const JSC::ArgList &args)
1627 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
1628 thisValue = engine->toUsableValue(thisValue);
1629 // extract the QObject
1630 if (!thisValue.inherits(&QScriptObject::info))
1631 return throwError(exec, JSC::TypeError, "this object is not a QObject");
1632 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(thisValue));
1633 QScriptObjectDelegate *delegate = scriptObject->delegate();
1634 if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject))
1635 return throwError(exec, JSC::TypeError, "this object is not a QObject");
1636 const QObject *const obj = static_cast<QObjectDelegate*>(delegate)->value();
1638 // find the children
1639 QList<QObject *> children;
1640 if (args.size() != 0) {
1641 const JSC::JSValue arg = args.at(0);
1642 if (arg.inherits(&JSC::RegExpObject::info)) {
1643 const QObjectList allChildren= obj->children();
1645 JSC::RegExpObject *const regexp = JSC::asRegExpObject(arg);
1647 const int allChildrenCount = allChildren.size();
1648 for (int i = 0; i < allChildrenCount; ++i) {
1649 QObject *const child = allChildren.at(i);
1650 const JSC::UString childName = child->objectName();
1651 JSC::RegExpConstructor* regExpConstructor = engine->originalGlobalObject()->regExpConstructor();
1652 int position;
1653 int length;
1654 regExpConstructor->performMatch(regexp->regExp(), childName, 0, position, length);
1655 if (position >= 0)
1656 children.append(child);
1658 } else {
1659 const QString name(args.at(0).toString(exec));
1660 children = qFindChildren<QObject*>(obj, name);
1662 } else {
1663 children = qFindChildren<QObject*>(obj, QString());
1665 // create the result array with the children
1666 const int length = children.size();
1667 JSC::JSArray *const result = JSC::constructEmptyArray(exec, length);
1669 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
1670 for (int i = 0; i < length; ++i) {
1671 QObject *const child = children.at(i);
1672 result->put(exec, i, engine->newQObject(child, QScriptEngine::QtOwnership, opt));
1674 return JSC::JSValue(result);
1677 static JSC::JSValue JSC_HOST_CALL qobjectProtoFuncToString(JSC::ExecState *exec, JSC::JSObject*,
1678 JSC::JSValue thisValue, const JSC::ArgList&)
1680 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
1681 thisValue = engine->toUsableValue(thisValue);
1682 if (!thisValue.inherits(&QScriptObject::info))
1683 return JSC::jsUndefined();
1684 QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(thisValue));
1685 QScriptObjectDelegate *delegate = scriptObject->delegate();
1686 if (!delegate || (delegate->type() != QScriptObjectDelegate::QtObject))
1687 return JSC::jsUndefined();
1688 QObject *obj = static_cast<QObjectDelegate*>(delegate)->value();
1689 const QMetaObject *meta = obj ? obj->metaObject() : &QObject::staticMetaObject;
1690 QString name = obj ? obj->objectName() : QString::fromUtf8("unnamed");
1691 QString str = QString::fromUtf8("%0(name = \"%1\")")
1692 .arg(QLatin1String(meta->className())).arg(name);
1693 return JSC::jsString(exec, str);
1696 QObjectPrototype::QObjectPrototype(JSC::ExecState* exec, WTF::PassRefPtr<JSC::Structure> structure,
1697 JSC::Structure* prototypeFunctionStructure)
1698 : QScriptObject(structure)
1700 setDelegate(new QObjectDelegate(new QObjectPrototypeObject(), QScriptEngine::AutoOwnership,
1701 QScriptEngine::ExcludeSuperClassMethods
1702 | QScriptEngine::ExcludeSuperClassProperties
1703 | QScriptEngine::ExcludeChildObjects));
1705 putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/0, exec->propertyNames().toString, qobjectProtoFuncToString), JSC::DontEnum);
1706 putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChild"), qobjectProtoFuncFindChild), JSC::DontEnum);
1707 putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChildren"), qobjectProtoFuncFindChildren), JSC::DontEnum);
1710 const JSC::ClassInfo QMetaObjectWrapperObject::info = { "QMetaObject", 0, 0, 0 };
1712 QMetaObjectWrapperObject::QMetaObjectWrapperObject(
1713 JSC::ExecState *exec, const QMetaObject *metaObject, JSC::JSValue ctor,
1714 WTF::PassRefPtr<JSC::Structure> sid)
1715 : JSC::JSObject(sid),
1716 data(new Data(metaObject, ctor))
1718 if (!ctor)
1719 data->prototype = new (exec)JSC::JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
1722 QMetaObjectWrapperObject::~QMetaObjectWrapperObject()
1724 delete data;
1727 bool QMetaObjectWrapperObject::getOwnPropertySlot(
1728 JSC::ExecState *exec, const JSC::Identifier& propertyName,
1729 JSC::PropertySlot &slot)
1731 const QMetaObject *meta = data->value;
1732 if (!meta)
1733 return false;
1735 if (propertyName == exec->propertyNames().prototype) {
1736 if (data->ctor)
1737 slot.setValue(data->ctor.get(exec, propertyName));
1738 else
1739 slot.setValue(data->prototype);
1740 return true;
1743 QByteArray name = QString(propertyName.ustring()).toLatin1();
1745 for (int i = 0; i < meta->enumeratorCount(); ++i) {
1746 QMetaEnum e = meta->enumerator(i);
1747 for (int j = 0; j < e.keyCount(); ++j) {
1748 const char *key = e.key(j);
1749 if (!qstrcmp(key, name.constData())) {
1750 slot.setValue(JSC::JSValue(exec, e.value(j)));
1751 return true;
1756 return JSC::JSObject::getOwnPropertySlot(exec, propertyName, slot);
1759 void QMetaObjectWrapperObject::put(JSC::ExecState* exec, const JSC::Identifier& propertyName,
1760 JSC::JSValue value, JSC::PutPropertySlot &slot)
1762 if (propertyName == exec->propertyNames().prototype) {
1763 if (data->ctor)
1764 data->ctor.put(exec, propertyName, value, slot);
1765 else
1766 data->prototype = value;
1767 return;
1769 const QMetaObject *meta = data->value;
1770 if (meta) {
1771 QByteArray name = QString(propertyName.ustring()).toLatin1();
1772 for (int i = 0; i < meta->enumeratorCount(); ++i) {
1773 QMetaEnum e = meta->enumerator(i);
1774 for (int j = 0; j < e.keyCount(); ++j) {
1775 if (!qstrcmp(e.key(j), name.constData()))
1776 return;
1780 JSC::JSObject::put(exec, propertyName, value, slot);
1783 bool QMetaObjectWrapperObject::deleteProperty(
1784 JSC::ExecState *exec, const JSC::Identifier& propertyName,
1785 bool checkDontDelete)
1787 if (propertyName == exec->propertyNames().prototype)
1788 return false;
1789 const QMetaObject *meta = data->value;
1790 if (meta) {
1791 QByteArray name = QString(propertyName.ustring()).toLatin1();
1792 for (int i = 0; i < meta->enumeratorCount(); ++i) {
1793 QMetaEnum e = meta->enumerator(i);
1794 for (int j = 0; j < e.keyCount(); ++j) {
1795 if (!qstrcmp(e.key(j), name.constData()))
1796 return false;
1800 return JSC::JSObject::deleteProperty(exec, propertyName, checkDontDelete);
1803 bool QMetaObjectWrapperObject::getPropertyAttributes(JSC::ExecState *exec,
1804 const JSC::Identifier &propertyName,
1805 unsigned &attributes) const
1807 if (propertyName == exec->propertyNames().prototype) {
1808 attributes = JSC::DontDelete;
1809 return true;
1811 const QMetaObject *meta = data->value;
1812 if (meta) {
1813 QByteArray name = QString(propertyName.ustring()).toLatin1();
1814 for (int i = 0; i < meta->enumeratorCount(); ++i) {
1815 QMetaEnum e = meta->enumerator(i);
1816 for (int j = 0; j < e.keyCount(); ++j) {
1817 if (!qstrcmp(e.key(j), name.constData())) {
1818 attributes = JSC::ReadOnly | JSC::DontDelete;
1819 return true;
1824 return JSC::JSObject::getPropertyAttributes(exec, propertyName, attributes);
1827 void QMetaObjectWrapperObject::getOwnPropertyNames(JSC::ExecState *exec,
1828 JSC::PropertyNameArray &propertyNames,
1829 bool includeNonEnumerable)
1831 const QMetaObject *meta = data->value;
1832 if (!meta)
1833 return;
1834 for (int i = 0; i < meta->enumeratorCount(); ++i) {
1835 QMetaEnum e = meta->enumerator(i);
1836 for (int j = 0; j < e.keyCount(); ++j)
1837 propertyNames.add(JSC::Identifier(exec, e.key(j)));
1839 JSC::JSObject::getOwnPropertyNames(exec, propertyNames, includeNonEnumerable);
1842 void QMetaObjectWrapperObject::markChildren(JSC::MarkStack& markStack)
1844 if (data->ctor)
1845 markStack.append(data->ctor);
1846 if (data->prototype)
1847 markStack.append(data->prototype);
1848 JSC::JSObject::markChildren(markStack);
1851 JSC::CallType QMetaObjectWrapperObject::getCallData(JSC::CallData& callData)
1853 callData.native.function = call;
1854 return JSC::CallTypeHost;
1857 JSC::ConstructType QMetaObjectWrapperObject::getConstructData(JSC::ConstructData& constructData)
1859 constructData.native.function = construct;
1860 return JSC::ConstructTypeHost;
1863 JSC::JSValue JSC_HOST_CALL QMetaObjectWrapperObject::call(
1864 JSC::ExecState *exec, JSC::JSObject *callee,
1865 JSC::JSValue thisValue, const JSC::ArgList &args)
1867 QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
1868 thisValue = eng_p->toUsableValue(thisValue);
1869 if (!callee->inherits(&QMetaObjectWrapperObject::info))
1870 return throwError(exec, JSC::TypeError, "callee is not a QMetaObject");
1871 QMetaObjectWrapperObject *self = static_cast<QMetaObjectWrapperObject*>(callee);
1872 JSC::ExecState *previousFrame = eng_p->currentFrame;
1873 eng_p->pushContext(exec, thisValue, args, callee);
1874 JSC::JSValue result = self->execute(eng_p->currentFrame, args);
1875 eng_p->popContext();
1876 eng_p->currentFrame = previousFrame;
1877 return result;
1880 JSC::JSObject* QMetaObjectWrapperObject::construct(JSC::ExecState *exec, JSC::JSObject *callee, const JSC::ArgList &args)
1882 QMetaObjectWrapperObject *self = static_cast<QMetaObjectWrapperObject*>(callee);
1883 QScriptEnginePrivate *eng_p = scriptEngineFromExec(exec);
1884 JSC::ExecState *previousFrame = eng_p->currentFrame;
1885 eng_p->pushContext(exec, JSC::JSValue(), args, callee, true);
1886 JSC::JSValue result = self->execute(eng_p->currentFrame, args);
1887 eng_p->popContext();
1888 eng_p->currentFrame = previousFrame;
1889 if (!result || !result.isObject())
1890 return 0;
1891 return JSC::asObject(result);
1894 JSC::JSValue QMetaObjectWrapperObject::execute(JSC::ExecState *exec,
1895 const JSC::ArgList &args)
1897 if (data->ctor) {
1898 QScriptEnginePrivate *eng_p = QScript::scriptEngineFromExec(exec);
1899 QScriptContext *ctx = eng_p->contextForFrame(exec);
1900 JSC::CallData callData;
1901 JSC::CallType callType = data->ctor.getCallData(callData);
1902 Q_UNUSED(callType);
1903 Q_ASSERT_X(callType == JSC::CallTypeHost, Q_FUNC_INFO, "script constructors not supported");
1904 if (data->ctor.inherits(&FunctionWithArgWrapper::info)) {
1905 FunctionWithArgWrapper *wrapper = static_cast<FunctionWithArgWrapper*>(JSC::asObject(data->ctor));
1906 QScriptValue result = wrapper->function()(ctx, QScriptEnginePrivate::get(eng_p), wrapper->arg());
1907 return eng_p->scriptValueToJSCValue(result);
1908 } else {
1909 Q_ASSERT(data->ctor.inherits(&FunctionWrapper::info));
1910 FunctionWrapper *wrapper = static_cast<FunctionWrapper*>(JSC::asObject(data->ctor));
1911 QScriptValue result = wrapper->function()(ctx, QScriptEnginePrivate::get(eng_p));
1912 return eng_p->scriptValueToJSCValue(result);
1914 } else {
1915 const QMetaObject *meta = data->value;
1916 if (meta->constructorCount() > 0) {
1917 JSC::JSValue result = callQtMethod(exec, QMetaMethod::Constructor, /*thisQObject=*/0,
1918 args, meta, meta->constructorCount()-1, /*maybeOverloaded=*/true);
1919 if (!exec->hadException()) {
1920 Q_ASSERT(result && result.inherits(&QScriptObject::info));
1921 QScriptObject *object = static_cast<QScriptObject*>(JSC::asObject(result));
1922 QScript::QObjectDelegate *delegate = static_cast<QScript::QObjectDelegate*>(object->delegate());
1923 delegate->setOwnership(QScriptEngine::AutoOwnership);
1924 if (data->prototype)
1925 object->setPrototype(data->prototype);
1927 return result;
1928 } else {
1929 QString message = QString::fromLatin1("no constructor for %0")
1930 .arg(QLatin1String(meta->className()));
1931 return JSC::throwError(exec, JSC::TypeError, message);
1936 struct StaticQtMetaObject : public QObject
1938 static const QMetaObject *get()
1939 { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; }
1942 static JSC::JSValue JSC_HOST_CALL qmetaobjectProtoFuncClassName(
1943 JSC::ExecState *exec, JSC::JSObject*, JSC::JSValue thisValue, const JSC::ArgList&)
1945 QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
1946 thisValue = engine->toUsableValue(thisValue);
1947 if (!thisValue.inherits(&QMetaObjectWrapperObject::info))
1948 return throwError(exec, JSC::TypeError, "this object is not a QMetaObject");
1949 const QMetaObject *meta = static_cast<QMetaObjectWrapperObject*>(JSC::asObject(thisValue))->value();
1950 return JSC::jsString(exec, meta->className());
1953 QMetaObjectPrototype::QMetaObjectPrototype(
1954 JSC::ExecState *exec, WTF::PassRefPtr<JSC::Structure> structure,
1955 JSC::Structure* prototypeFunctionStructure)
1956 : QMetaObjectWrapperObject(exec, StaticQtMetaObject::get(), /*ctor=*/JSC::JSValue(), structure)
1958 putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/0, JSC::Identifier(exec, "className"), qmetaobjectProtoFuncClassName), JSC::DontEnum);
1961 static const uint qt_meta_data_QObjectConnectionManager[] = {
1963 // content:
1964 1, // revision
1965 0, // classname
1966 0, 0, // classinfo
1967 1, 10, // methods
1968 0, 0, // properties
1969 0, 0, // enums/sets
1971 // slots: signature, parameters, type, tag, flags
1972 35, 34, 34, 34, 0x0a,
1974 0 // eod
1977 static const char qt_meta_stringdata_QObjectConnectionManager[] = {
1978 "QScript::QObjectConnectionManager\0\0execute()\0"
1981 const QMetaObject QObjectConnectionManager::staticMetaObject = {
1982 { &QObject::staticMetaObject, qt_meta_stringdata_QObjectConnectionManager,
1983 qt_meta_data_QObjectConnectionManager, 0 }
1986 const QMetaObject *QObjectConnectionManager::metaObject() const
1988 return &staticMetaObject;
1991 void *QObjectConnectionManager::qt_metacast(const char *_clname)
1993 if (!_clname) return 0;
1994 if (!strcmp(_clname, qt_meta_stringdata_QObjectConnectionManager))
1995 return static_cast<void*>(const_cast<QObjectConnectionManager*>(this));
1996 return QObject::qt_metacast(_clname);
1999 int QObjectConnectionManager::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
2001 _id = QObject::qt_metacall(_c, _id, _a);
2002 if (_id < 0)
2003 return _id;
2004 if (_c == QMetaObject::InvokeMetaMethod) {
2005 execute(_id, _a);
2006 _id -= slotCounter;
2008 return _id;
2011 void QObjectConnectionManager::execute(int slotIndex, void **argv)
2013 JSC::JSValue receiver;
2014 JSC::JSValue slot;
2015 JSC::JSValue senderWrapper;
2016 int signalIndex = -1;
2017 for (int i = 0; i < connections.size(); ++i) {
2018 const QVector<QObjectConnection> &cs = connections.at(i);
2019 for (int j = 0; j < cs.size(); ++j) {
2020 const QObjectConnection &c = cs.at(j);
2021 if (c.slotIndex == slotIndex) {
2022 receiver = c.receiver;
2023 slot = c.slot;
2024 senderWrapper = c.senderWrapper;
2025 signalIndex = i;
2026 break;
2030 Q_ASSERT(slot && slot.isObject());
2032 if (engine->isCollecting()) {
2033 qWarning("QtScript: can't execute signal handler during GC");
2034 // we can't do a script function call during GC,
2035 // so we're forced to ignore this signal
2036 return;
2039 #if 0
2040 QScriptFunction *fun = engine->convertToNativeFunction(slot);
2041 if (fun == 0) {
2042 // the signal handler has been GC'ed. This can only happen when
2043 // a QObject is owned by the engine, the engine is destroyed, and
2044 // there is a script function connected to the destroyed() signal
2045 Q_ASSERT(signalIndex <= 1); // destroyed(QObject*)
2046 return;
2048 #endif
2050 const QMetaObject *meta = sender()->metaObject();
2051 const QMetaMethod method = meta->method(signalIndex);
2053 QList<QByteArray> parameterTypes = method.parameterTypes();
2054 int argc = parameterTypes.count();
2056 JSC::ExecState *exec = engine->currentFrame;
2057 QVarLengthArray<JSC::JSValue, 8> argsVector(argc);
2058 for (int i = 0; i < argc; ++i) {
2059 // ### optimize -- no need to convert via QScriptValue
2060 QScriptValue actual;
2061 void *arg = argv[i + 1];
2062 QByteArray typeName = parameterTypes.at(i);
2063 int argType = QMetaType::type(parameterTypes.at(i));
2064 if (!argType) {
2065 if (typeName == "QVariant") {
2066 actual = engine->scriptValueFromVariant(*reinterpret_cast<QVariant*>(arg));
2067 } else {
2068 qWarning("QScriptEngine: Unable to handle unregistered datatype '%s' "
2069 "when invoking handler of signal %s::%s",
2070 typeName.constData(), meta->className(), method.signature());
2071 actual = QScriptValue(QScriptValue::UndefinedValue);
2073 } else {
2074 actual = engine->create(argType, arg);
2076 argsVector[i] = engine->scriptValueToJSCValue(actual);
2078 JSC::ArgList jscArgs(argsVector.data(), argsVector.size());
2080 JSC::JSValue senderObject;
2081 if (senderWrapper && senderWrapper.inherits(&QScriptObject::info)) // ### check if it's actually a QObject wrapper
2082 senderObject = senderWrapper;
2083 else {
2084 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
2085 senderObject = engine->newQObject(sender(), QScriptEngine::QtOwnership, opt);
2088 JSC::JSValue thisObject;
2089 if (receiver && receiver.isObject())
2090 thisObject = receiver;
2091 else
2092 thisObject = engine->globalObject();
2094 JSC::CallData callData;
2095 JSC::CallType callType = slot.getCallData(callData);
2096 if (exec->hadException())
2097 exec->clearException(); // ### otherwise JSC asserts
2098 JSC::call(exec, slot, callType, callData, thisObject, jscArgs);
2100 if (exec->hadException()) {
2101 engine->emitSignalHandlerException();
2105 QObjectConnectionManager::QObjectConnectionManager(QScriptEnginePrivate *eng)
2106 : engine(eng), slotCounter(0)
2110 QObjectConnectionManager::~QObjectConnectionManager()
2114 void QObjectConnectionManager::mark(JSC::MarkStack& markStack)
2116 for (int i = 0; i < connections.size(); ++i) {
2117 QVector<QObjectConnection> &cs = connections[i];
2118 for (int j = 0; j < cs.size(); ++j)
2119 cs[j].mark(markStack);
2123 bool QObjectConnectionManager::addSignalHandler(
2124 QObject *sender, int signalIndex, JSC::JSValue receiver,
2125 JSC::JSValue function, JSC::JSValue senderWrapper,
2126 Qt::ConnectionType type)
2128 if (connections.size() <= signalIndex)
2129 connections.resize(signalIndex+1);
2130 QVector<QObjectConnection> &cs = connections[signalIndex];
2131 int absSlotIndex = slotCounter + metaObject()->methodOffset();
2132 bool ok = QMetaObject::connect(sender, signalIndex, this, absSlotIndex, type);
2133 if (ok) {
2134 cs.append(QObjectConnection(slotCounter++, receiver, function, senderWrapper));
2135 QMetaMethod signal = sender->metaObject()->method(signalIndex);
2136 QByteArray signalString;
2137 signalString.append('2'); // signal code
2138 signalString.append(signal.signature());
2139 static_cast<QObjectNotifyCaller*>(sender)->callConnectNotify(signalString);
2141 return ok;
2144 bool QObjectConnectionManager::removeSignalHandler(
2145 QObject *sender, int signalIndex,
2146 JSC::JSValue receiver, JSC::JSValue slot)
2148 if (connections.size() <= signalIndex)
2149 return false;
2150 QVector<QObjectConnection> &cs = connections[signalIndex];
2151 for (int i = 0; i < cs.size(); ++i) {
2152 const QObjectConnection &c = cs.at(i);
2153 if (c.hasTarget(receiver, slot)) {
2154 int absSlotIndex = c.slotIndex + metaObject()->methodOffset();
2155 bool ok = QMetaObject::disconnect(sender, signalIndex, this, absSlotIndex);
2156 if (ok) {
2157 cs.remove(i);
2158 QMetaMethod signal = sender->metaObject()->method(signalIndex);
2159 QByteArray signalString;
2160 signalString.append('2'); // signal code
2161 signalString.append(signal.signature());
2162 static_cast<QScript::QObjectNotifyCaller*>(sender)->callDisconnectNotify(signalString);
2164 return ok;
2167 return false;
2170 QObjectData::QObjectData(QScriptEnginePrivate *eng)
2171 : engine(eng), connectionManager(0)
2175 QObjectData::~QObjectData()
2177 if (connectionManager) {
2178 delete connectionManager;
2179 connectionManager = 0;
2183 void QObjectData::mark(JSC::MarkStack& markStack)
2185 if (connectionManager)
2186 connectionManager->mark(markStack);
2188 QList<QScript::QObjectWrapperInfo>::iterator it;
2189 for (it = wrappers.begin(); it != wrappers.end(); ) {
2190 const QScript::QObjectWrapperInfo &info = *it;
2191 // ### don't mark if there are no other references.
2192 // we need something like isMarked()
2193 markStack.append(info.object);
2194 ++it;
2199 bool QObjectData::addSignalHandler(QObject *sender,
2200 int signalIndex,
2201 JSC::JSValue receiver,
2202 JSC::JSValue slot,
2203 JSC::JSValue senderWrapper,
2204 Qt::ConnectionType type)
2206 if (!connectionManager)
2207 connectionManager = new QObjectConnectionManager(engine);
2208 return connectionManager->addSignalHandler(
2209 sender, signalIndex, receiver, slot, senderWrapper, type);
2212 bool QObjectData::removeSignalHandler(QObject *sender,
2213 int signalIndex,
2214 JSC::JSValue receiver,
2215 JSC::JSValue slot)
2217 if (!connectionManager)
2218 return false;
2219 return connectionManager->removeSignalHandler(
2220 sender, signalIndex, receiver, slot);
2223 QScriptObject *QObjectData::findWrapper(QScriptEngine::ValueOwnership ownership,
2224 const QScriptEngine::QObjectWrapOptions &options) const
2226 for (int i = 0; i < wrappers.size(); ++i) {
2227 const QObjectWrapperInfo &info = wrappers.at(i);
2228 if ((info.ownership == ownership) && (info.options == options))
2229 return info.object;
2231 return 0;
2234 void QObjectData::registerWrapper(QScriptObject *wrapper,
2235 QScriptEngine::ValueOwnership ownership,
2236 const QScriptEngine::QObjectWrapOptions &options)
2238 wrappers.append(QObjectWrapperInfo(wrapper, ownership, options));
2241 } // namespace QScript
2243 QT_END_NAMESPACE
2245 namespace JSC
2247 ASSERT_CLASS_FITS_IN_CELL(QScript::QtFunction);
2250 #include "moc_qscriptqobject_p.cpp"