1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtQml module of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
9
** Commercial License Usage
10
** Licensees holding valid commercial Qt licenses may use this file in
11
** accordance with the commercial license agreement provided with the
12
** Software or, alternatively, in accordance with the terms contained in
13
** a written agreement between you and Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
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());