1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qv8contextwrapper_p.h"
43 #include "qv8engine_p.h"
45 #include <private/qqmlengine_p.h>
46 #include <private/qqmlcontext_p.h>
48 #include <private/qjsvalue_p.h>
49 #include <private/qscript_impl_p.h>
53 class QV8TypeResource : public QV8ObjectResource
55 V8_RESOURCE_TYPE(TypeType);
58 QV8TypeResource(QV8Engine *engine);
59 virtual ~QV8TypeResource();
61 QV8TypeWrapper::TypeNameMode mode;
63 QQmlGuard<QObject> object;
66 QQmlTypeNameCache *typeNamespace;
67 const void *importNamespace;
70 QV8TypeResource::QV8TypeResource(QV8Engine *engine)
71 : QV8ObjectResource(engine), mode(QV8TypeWrapper::IncludeEnums), type(0), typeNamespace(0), importNamespace(0)
75 QV8TypeResource::~QV8TypeResource()
77 if (typeNamespace) typeNamespace->release();
80 QV8TypeWrapper::QV8TypeWrapper()
85 QV8TypeWrapper::~QV8TypeWrapper()
89 void QV8TypeWrapper::destroy()
91 qPersistentDispose(m_constructor);
94 void QV8TypeWrapper::init(QV8Engine *engine)
97 v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
98 ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
99 ft->InstanceTemplate()->SetHasExternalResource(true);
100 m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
103 // Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
104 v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QQmlType *t, TypeNameMode mode)
107 // XXX NewInstance() should be optimized
108 v8::Local<v8::Object> rv = m_constructor->NewInstance();
109 QV8TypeResource *r = new QV8TypeResource(m_engine);
110 r->mode = mode; r->object = o; r->type = t;
111 rv->SetExternalResource(r);
115 // Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
117 v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QQmlTypeNameCache *t,
118 const void *importNamespace, TypeNameMode mode)
121 Q_ASSERT(importNamespace);
122 // XXX NewInstance() should be optimized
123 v8::Local<v8::Object> rv = m_constructor->NewInstance();
124 QV8TypeResource *r = new QV8TypeResource(m_engine);
126 r->mode = mode; r->object = o; r->typeNamespace = t; r->importNamespace = importNamespace;
127 rv->SetExternalResource(r);
131 QVariant QV8TypeWrapper::toVariant(QV8ObjectResource *r)
133 Q_ASSERT(r->resourceType() == QV8ObjectResource::TypeType);
134 QV8TypeResource *resource = static_cast<QV8TypeResource *>(r);
135 QV8Engine *v8engine = resource->engine;
137 if (resource->type && resource->type->isSingleton()) {
138 QQmlEngine *e = v8engine->engine();
139 QQmlType::SingletonInstanceInfo *siinfo = resource->type->singletonInstanceInfo();
140 siinfo->init(e); // note: this will also create QJSValue singleton which isn't strictly required.
141 QObject *qobjectSingleton = siinfo->qobjectApi(e);
142 if (qobjectSingleton) {
143 return QVariant::fromValue<QObject*>(qobjectSingleton);
147 // only QObject Singleton Type can be converted to a variant.
151 v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
152 const v8::AccessorInfo &info)
154 QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
157 return v8::Undefined();
159 QV8Engine *v8engine = resource->engine;
160 QQmlContextData *context = v8engine->callingContext();
162 QObject *object = resource->object;
164 QHashedV8String propertystring(property);
166 if (resource->type) {
167 QQmlType *type = resource->type;
169 // singleton types are handled differently to other types.
170 if (type->isSingleton()) {
171 QQmlEngine *e = v8engine->engine();
172 QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
175 QObject *qobjectSingleton = siinfo->qobjectApi(e);
176 if (qobjectSingleton) {
177 // check for enum value
178 if (QV8Engine::startsWithUpper(property)) {
179 if (resource->mode == IncludeEnums) {
180 QString name = v8engine->toString(property);
183 QByteArray enumName = name.toUtf8();
184 const QMetaObject *metaObject = qobjectSingleton->metaObject();
185 for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
186 QMetaEnum e = metaObject->enumerator(ii);
188 int value = e.keyToValue(enumName.constData(), &ok);
190 return v8::Integer::New(value);
195 // check for property.
196 v8::Handle<v8::Value> rv = v8engine->qobjectWrapper()->getProperty(qobjectSingleton, propertystring, context, QV8QObjectWrapper::IgnoreRevision);
198 } else if (!siinfo->scriptApi(e).isUndefined()) {
199 // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
200 QJSValuePrivate *apiprivate = QJSValuePrivate::get(siinfo->scriptApi(e));
201 QScopedPointer<QJSValuePrivate> propertyValue(apiprivate->property(property).give());
202 return propertyValue->asV8Value(v8engine);
205 // Fall through to return empty handle
209 if (QV8Engine::startsWithUpper(property)) {
211 int value = type->enumValue(propertystring, &ok);
213 return v8::Integer::New(value);
215 // Fall through to return empty handle
217 } else if (resource->object) {
218 QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
220 return v8engine->qobjectWrapper()->getProperty(ao, propertystring, context,
221 QV8QObjectWrapper::IgnoreRevision);
223 // Fall through to return empty handle
226 // Fall through to return empty handle
229 // Fall through to return empty handle
231 } else if (resource->typeNamespace) {
232 Q_ASSERT(resource->importNamespace);
233 QQmlTypeNameCache::Result r = resource->typeNamespace->query(propertystring,
234 resource->importNamespace);
237 QQmlContextData *context = v8engine->callingContext();
239 return v8engine->typeWrapper()->newObject(object, r.type, resource->mode);
240 } else if (r.scriptIndex != -1) {
241 int index = r.scriptIndex;
242 if (index < context->importedScripts.count())
243 return context->importedScripts.at(index);
244 } else if (r.importNamespace) {
245 return v8engine->typeWrapper()->newObject(object, context->imports, r.importNamespace);
248 return v8::Undefined();
252 // Fall through to return empty handle
255 Q_ASSERT(!"Unreachable");
258 return v8::Handle<v8::Value>();
261 v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
262 v8::Local<v8::Value> value,
263 const v8::AccessorInfo &info)
265 QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
270 QV8Engine *v8engine = resource->engine;
271 QQmlContextData *context = v8engine->callingContext();
273 QHashedV8String propertystring(property);
275 QQmlType *type = resource->type;
276 if (type && !type->isSingleton() && resource->object) {
277 QObject *object = resource->object;
278 QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
280 v8engine->qobjectWrapper()->setProperty(ao, propertystring, context, value,
281 QV8QObjectWrapper::IgnoreRevision);
282 } else if (type && type->isSingleton()) {
283 QQmlEngine *e = v8engine->engine();
284 QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
287 QObject *qobjectSingleton = siinfo->qobjectApi(e);
288 if (qobjectSingleton) {
289 v8engine->qobjectWrapper()->setProperty(qobjectSingleton, propertystring, context, value,
290 QV8QObjectWrapper::IgnoreRevision);
291 } else if (!siinfo->scriptApi(e).isUndefined()) {
292 QScopedPointer<QJSValuePrivate> setvalp(new QJSValuePrivate(v8engine, value));
293 QJSValuePrivate *apiprivate = QJSValuePrivate::get(siinfo->scriptApi(e));
294 if (apiprivate->propertyFlags(property) & QJSValuePrivate::ReadOnly) {
295 QString error = QLatin1String("Cannot assign to read-only property \"") +
296 v8engine->toString(property) + QLatin1Char('\"');
297 v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
299 apiprivate->setProperty(property, setvalp.data());