src/script/bridge/qscriptqobject.cpp
branchRCL_3
changeset 4 3b1da2848fc7
parent 3 41300fa6a67c
child 30 5dc02b23752f
equal deleted inserted replaced
3:41300fa6a67c 4:3b1da2848fc7
     1 /****************************************************************************
     1 /****************************************************************************
     2 **
     2 **
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     4 ** All rights reserved.
     4 ** All rights reserved.
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
     6 **
     6 **
     7 ** This file is part of the QtScript module of the Qt Toolkit.
     7 ** This file is part of the QtScript module of the Qt Toolkit.
     8 **
     8 **
   976     Q_ASSERT(data->object.inherits(&QScriptObject::info));
   976     Q_ASSERT(data->object.inherits(&QScriptObject::info));
   977     QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(data->object));
   977     QScriptObject *scriptObject = static_cast<QScriptObject*>(JSC::asObject(data->object));
   978     QScriptObjectDelegate *delegate = scriptObject->delegate();
   978     QScriptObjectDelegate *delegate = scriptObject->delegate();
   979     Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::QtObject));
   979     Q_ASSERT(delegate && (delegate->type() == QScriptObjectDelegate::QtObject));
   980     QObject *qobj = static_cast<QScript::QObjectDelegate*>(delegate)->value();
   980     QObject *qobj = static_cast<QScript::QObjectDelegate*>(delegate)->value();
   981     Q_ASSERT_X(qobj != 0, "QtFunction::call", "handle the case when QObject has been deleted");
   981     if (!qobj)
       
   982         return JSC::throwError(exec, JSC::GeneralError, QString::fromLatin1("cannot call function of deleted QObject"));
   982     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
   983     QScriptEnginePrivate *engine = scriptEngineFromExec(exec);
   983 
   984 
   984     const QMetaObject *meta = qobj->metaObject();
   985     const QMetaObject *meta = qobj->metaObject();
   985     QObject *thisQObject = 0;
   986     QObject *thisQObject = 0;
   986     thisValue = engine->toUsableValue(thisValue);
   987     thisValue = engine->toUsableValue(thisValue);
  1171 
  1172 
  1172 bool QObjectDelegate::getOwnPropertySlot(QScriptObject *object, JSC::ExecState *exec,
  1173 bool QObjectDelegate::getOwnPropertySlot(QScriptObject *object, JSC::ExecState *exec,
  1173                                          const JSC::Identifier &propertyName,
  1174                                          const JSC::Identifier &propertyName,
  1174                                          JSC::PropertySlot &slot)
  1175                                          JSC::PropertySlot &slot)
  1175 {
  1176 {
       
  1177     //Note: this has to be kept in sync with getOwnPropertyDescriptor
  1176 #ifndef QT_NO_PROPERTIES
  1178 #ifndef QT_NO_PROPERTIES
  1177     QByteArray name = QString(propertyName.ustring()).toLatin1();
  1179     QByteArray name = QString(propertyName.ustring()).toLatin1();
  1178     QObject *qobject = data->value;
  1180     QObject *qobject = data->value;
  1179     if (!qobject) {
  1181     if (!qobject) {
  1180         QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
  1182         QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
  1278             }
  1280             }
  1279         }
  1281         }
  1280     }
  1282     }
  1281 
  1283 
  1282     return QScriptObjectDelegate::getOwnPropertySlot(object, exec, propertyName, slot);
  1284     return QScriptObjectDelegate::getOwnPropertySlot(object, exec, propertyName, slot);
       
  1285 #else //QT_NO_PROPERTIES
       
  1286     return false;
       
  1287 #endif //QT_NO_PROPERTIES
       
  1288 }
       
  1289 
       
  1290 
       
  1291 bool QObjectDelegate::getOwnPropertyDescriptor(QScriptObject *object, JSC::ExecState *exec,
       
  1292                                          const JSC::Identifier &propertyName,
       
  1293                                          JSC::PropertyDescriptor &descriptor)
       
  1294 {
       
  1295     //Note: this has to be kept in sync with getOwnPropertySlot abd getPropertyAttributes
       
  1296 #ifndef QT_NO_PROPERTIES
       
  1297     QByteArray name = QString(propertyName.ustring()).toLatin1();
       
  1298     QObject *qobject = data->value;
       
  1299     if (!qobject) {
       
  1300         QString message = QString::fromLatin1("cannot access member `%0' of deleted QObject")
       
  1301                           .arg(QString::fromLatin1(name));
       
  1302         descriptor.setValue(JSC::throwError(exec, JSC::GeneralError, message));
       
  1303         return true;
       
  1304     }
       
  1305 
       
  1306     const QScriptEngine::QObjectWrapOptions &opt = data->options;
       
  1307 
       
  1308     const QMetaObject *meta = qobject->metaObject();
       
  1309     {
       
  1310         QHash<QByteArray, JSC::JSValue>::const_iterator it = data->cachedMembers.constFind(name);
       
  1311         if (it != data->cachedMembers.constEnd()) {
       
  1312             int index;
       
  1313             if (GeneratePropertyFunctions && ((index = meta->indexOfProperty(name)) != -1)) {
       
  1314                 QMetaProperty prop = meta->property(index);
       
  1315                 descriptor.setAccessorDescriptor(it.value(), it.value(), flagsForMetaProperty(prop));
       
  1316                 if (!prop.isWritable())
       
  1317                     descriptor.setWritable(false);
       
  1318             } else {
       
  1319                 unsigned attributes = QObjectMemberAttribute;
       
  1320                 if (opt & QScriptEngine::SkipMethodsInEnumeration)
       
  1321                     attributes |= JSC::DontEnum;
       
  1322                 descriptor.setDescriptor(it.value(), attributes);
       
  1323             }
       
  1324             return true;
       
  1325         }
       
  1326     }
       
  1327 
       
  1328     QScriptEnginePrivate *eng = scriptEngineFromExec(exec);
       
  1329     int index = -1;
       
  1330     if (name.contains('(')) {
       
  1331         QByteArray normalized = QMetaObject::normalizedSignature(name);
       
  1332         if (-1 != (index = meta->indexOfMethod(normalized))) {
       
  1333             QMetaMethod method = meta->method(index);
       
  1334             if (hasMethodAccess(method, index, opt)) {
       
  1335                 if (!(opt & QScriptEngine::ExcludeSuperClassMethods)
       
  1336                     || (index >= meta->methodOffset())) {
       
  1337                     QtFunction *fun = new (exec)QtFunction(
       
  1338                         object, index, /*maybeOverloaded=*/false,
       
  1339                         &exec->globalData(), eng->originalGlobalObject()->functionStructure(),
       
  1340                         propertyName);
       
  1341                     data->cachedMembers.insert(name, fun);
       
  1342                     unsigned attributes = QObjectMemberAttribute;
       
  1343                     if (opt & QScriptEngine::SkipMethodsInEnumeration)
       
  1344                         attributes |= JSC::DontEnum;
       
  1345                     descriptor.setDescriptor(fun, attributes);
       
  1346                     return true;
       
  1347                 }
       
  1348             }
       
  1349         }
       
  1350     }
       
  1351 
       
  1352     index = meta->indexOfProperty(name);
       
  1353     if (index != -1) {
       
  1354         QMetaProperty prop = meta->property(index);
       
  1355         if (prop.isScriptable()) {
       
  1356             if (!(opt & QScriptEngine::ExcludeSuperClassProperties)
       
  1357                 || (index >= meta->propertyOffset())) {
       
  1358                 unsigned attributes = flagsForMetaProperty(prop);
       
  1359                 if (GeneratePropertyFunctions) {
       
  1360                     QtPropertyFunction *fun = new (exec)QtPropertyFunction(
       
  1361                         meta, index, &exec->globalData(),
       
  1362                         eng->originalGlobalObject()->functionStructure(),
       
  1363                         propertyName);
       
  1364                     data->cachedMembers.insert(name, fun);
       
  1365                     descriptor.setAccessorDescriptor(fun, fun, attributes);
       
  1366                     if (attributes & JSC::ReadOnly)
       
  1367                         descriptor.setWritable(false);
       
  1368                 } else {
       
  1369                     JSC::JSValue val;
       
  1370                     if (!prop.isValid())
       
  1371                         val = JSC::jsUndefined();
       
  1372                     else
       
  1373                         val = eng->jscValueFromVariant(prop.read(qobject));
       
  1374                     descriptor.setDescriptor(val, attributes);
       
  1375                 }
       
  1376                 return true;
       
  1377             }
       
  1378         }
       
  1379     }
       
  1380 
       
  1381     index = qobject->dynamicPropertyNames().indexOf(name);
       
  1382     if (index != -1) {
       
  1383         JSC::JSValue val = eng->jscValueFromVariant(qobject->property(name));
       
  1384         descriptor.setDescriptor(val, QObjectMemberAttribute);
       
  1385         return true;
       
  1386     }
       
  1387 
       
  1388     const int offset = (opt & QScriptEngine::ExcludeSuperClassMethods)
       
  1389                        ? meta->methodOffset() : 0;
       
  1390     for (index = meta->methodCount() - 1; index >= offset; --index) {
       
  1391         QMetaMethod method = meta->method(index);
       
  1392         if (hasMethodAccess(method, index, opt)
       
  1393             && (methodName(method) == name)) {
       
  1394             QtFunction *fun = new (exec)QtFunction(
       
  1395                 object, index, /*maybeOverloaded=*/true,
       
  1396                 &exec->globalData(), eng->originalGlobalObject()->functionStructure(),
       
  1397                 propertyName);
       
  1398             unsigned attributes = QObjectMemberAttribute;
       
  1399             if (opt & QScriptEngine::SkipMethodsInEnumeration)
       
  1400                 attributes |= JSC::DontEnum;
       
  1401             descriptor.setDescriptor(fun, attributes);
       
  1402             data->cachedMembers.insert(name, fun);
       
  1403             return true;
       
  1404         }
       
  1405     }
       
  1406 
       
  1407     if (!(opt & QScriptEngine::ExcludeChildObjects)) {
       
  1408         QList<QObject*> children = qobject->children();
       
  1409         for (index = 0; index < children.count(); ++index) {
       
  1410             QObject *child = children.at(index);
       
  1411             if (child->objectName() == QString(propertyName.ustring())) {
       
  1412                 QScriptEngine::QObjectWrapOptions opt = QScriptEngine::PreferExistingWrapperObject;
       
  1413                 QScriptValue tmp = QScriptEnginePrivate::get(eng)->newQObject(child, QScriptEngine::QtOwnership, opt);
       
  1414                 descriptor.setDescriptor(eng->scriptValueToJSCValue(tmp), JSC::ReadOnly | JSC::DontDelete | JSC::DontEnum);
       
  1415                 return true;
       
  1416             }
       
  1417         }
       
  1418     }
       
  1419 
       
  1420     return QScriptObjectDelegate::getOwnPropertyDescriptor(object, exec, propertyName, descriptor);
  1283 #else //QT_NO_PROPERTIES
  1421 #else //QT_NO_PROPERTIES
  1284     return false;
  1422     return false;
  1285 #endif //QT_NO_PROPERTIES
  1423 #endif //QT_NO_PROPERTIES
  1286 }
  1424 }
  1287 
  1425 
  1435                                             JSC::ExecState *exec,
  1573                                             JSC::ExecState *exec,
  1436                                             const JSC::Identifier &propertyName,
  1574                                             const JSC::Identifier &propertyName,
  1437                                             unsigned &attributes) const
  1575                                             unsigned &attributes) const
  1438 {
  1576 {
  1439 #ifndef QT_NO_PROPERTIES
  1577 #ifndef QT_NO_PROPERTIES
  1440     // ### try to avoid duplicating logic from getOwnPropertySlot()
  1578     //Note: this has to be kept in sync with getOwnPropertyDescriptor and getOwnPropertySlot
  1441     QByteArray name = ((QString)propertyName.ustring()).toLatin1();
  1579     QByteArray name = ((QString)propertyName.ustring()).toLatin1();
  1442     QObject *qobject = data->value;
  1580     QObject *qobject = data->value;
  1443     if (!qobject)
  1581     if (!qobject)
  1444         return false;
  1582         return false;
  1445 
  1583 
  1686                                     | QScriptEngine::ExcludeChildObjects));
  1824                                     | QScriptEngine::ExcludeChildObjects));
  1687 
  1825 
  1688     putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/0, exec->propertyNames().toString, qobjectProtoFuncToString), JSC::DontEnum);
  1826     putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/0, exec->propertyNames().toString, qobjectProtoFuncToString), JSC::DontEnum);
  1689     putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChild"), qobjectProtoFuncFindChild), JSC::DontEnum);
  1827     putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChild"), qobjectProtoFuncFindChild), JSC::DontEnum);
  1690     putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChildren"), qobjectProtoFuncFindChildren), JSC::DontEnum);
  1828     putDirectFunction(exec, new (exec) JSC::PrototypeFunction(exec, prototypeFunctionStructure, /*length=*/1, JSC::Identifier(exec, "findChildren"), qobjectProtoFuncFindChildren), JSC::DontEnum);
       
  1829     this->structure()->setHasGetterSetterProperties(true);
  1691 }
  1830 }
  1692 
  1831 
  1693 const JSC::ClassInfo QMetaObjectWrapperObject::info = { "QMetaObject", 0, 0, 0 };
  1832 const JSC::ClassInfo QMetaObjectWrapperObject::info = { "QMetaObject", 0, 0, 0 };
  1694 
  1833 
  1695 QMetaObjectWrapperObject::QMetaObjectWrapperObject(
  1834 QMetaObjectWrapperObject::QMetaObjectWrapperObject(
  2079     if (exec->hadException())
  2218     if (exec->hadException())
  2080         exec->clearException(); // ### otherwise JSC asserts
  2219         exec->clearException(); // ### otherwise JSC asserts
  2081     JSC::call(exec, slot, callType, callData, thisObject, jscArgs);
  2220     JSC::call(exec, slot, callType, callData, thisObject, jscArgs);
  2082 
  2221 
  2083     if (exec->hadException()) {
  2222     if (exec->hadException()) {
  2084         engine->emitSignalHandlerException();
  2223         if (slot.inherits(&QtFunction::info) && !static_cast<QtFunction*>(JSC::asObject(slot))->qobject()) {
       
  2224             // The function threw an error because the target QObject has been deleted.
       
  2225             // The connections list is stale; remove the signal handler and ignore the exception.
       
  2226             removeSignalHandler(sender(), signalIndex, receiver, slot);
       
  2227             exec->clearException();
       
  2228         } else {
       
  2229             engine->emitSignalHandlerException();
       
  2230         }
  2085     }
  2231     }
  2086 }
  2232 }
  2087 
  2233 
  2088 QObjectConnectionManager::QObjectConnectionManager(QScriptEnginePrivate *eng)
  2234 QObjectConnectionManager::QObjectConnectionManager(QScriptEnginePrivate *eng)
  2089     : engine(eng), slotCounter(0)
  2235     : engine(eng), slotCounter(0)