~ubuntu-branches/ubuntu/saucy/qtdeclarative-opensource-src/saucy

« back to all changes in this revision

Viewing changes to src/qml/qml/v8/qv8typewrapper.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 14:17:19 UTC
  • Revision ID: package-import@ubuntu.com-20130205141719-qqeyml8wslpyez52
Tags: upstream-5.0.1
ImportĀ upstreamĀ versionĀ 5.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the QtQml module of the Qt Toolkit.
 
7
**
 
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.
 
16
**
 
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.
 
24
**
 
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.
 
28
**
 
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.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include "qv8contextwrapper_p.h"
 
43
#include "qv8engine_p.h"
 
44
 
 
45
#include <private/qqmlengine_p.h>
 
46
#include <private/qqmlcontext_p.h>
 
47
 
 
48
#include <private/qjsvalue_p.h>
 
49
#include <private/qscript_impl_p.h>
 
50
 
 
51
QT_BEGIN_NAMESPACE
 
52
 
 
53
class QV8TypeResource : public QV8ObjectResource
 
54
{
 
55
    V8_RESOURCE_TYPE(TypeType);
 
56
 
 
57
public:
 
58
    QV8TypeResource(QV8Engine *engine);
 
59
    virtual ~QV8TypeResource();
 
60
 
 
61
    QV8TypeWrapper::TypeNameMode mode;
 
62
 
 
63
    QQmlGuard<QObject> object;
 
64
 
 
65
    QQmlType *type;
 
66
    QQmlTypeNameCache *typeNamespace;
 
67
    const void *importNamespace;
 
68
};
 
69
 
 
70
QV8TypeResource::QV8TypeResource(QV8Engine *engine)
 
71
: QV8ObjectResource(engine), mode(QV8TypeWrapper::IncludeEnums), type(0), typeNamespace(0), importNamespace(0)
 
72
{
 
73
}
 
74
 
 
75
QV8TypeResource::~QV8TypeResource()
 
76
{
 
77
    if (typeNamespace) typeNamespace->release();
 
78
}
 
79
 
 
80
QV8TypeWrapper::QV8TypeWrapper()
 
81
: m_engine(0)
 
82
{
 
83
}
 
84
 
 
85
QV8TypeWrapper::~QV8TypeWrapper()
 
86
{
 
87
}
 
88
 
 
89
void QV8TypeWrapper::destroy()
 
90
{
 
91
    qPersistentDispose(m_constructor);
 
92
}
 
93
 
 
94
void QV8TypeWrapper::init(QV8Engine *engine)
 
95
{
 
96
    m_engine = 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());
 
101
}
 
102
 
 
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)
 
105
{
 
106
    Q_ASSERT(t);
 
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);
 
112
    return rv;
 
113
}
 
114
 
 
115
// Returns a type wrapper for importNamespace (of t) on o.  This allows nested resolution of a type in a 
 
116
// namespace.
 
117
v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QQmlTypeNameCache *t, 
 
118
                                                const void *importNamespace, TypeNameMode mode)
 
119
{
 
120
    Q_ASSERT(t);
 
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);
 
125
    t->addref();
 
126
    r->mode = mode; r->object = o; r->typeNamespace = t; r->importNamespace = importNamespace;
 
127
    rv->SetExternalResource(r);
 
128
    return rv;
 
129
}
 
130
 
 
131
QVariant QV8TypeWrapper::toVariant(QV8ObjectResource *r)
 
132
{
 
133
    Q_ASSERT(r->resourceType() == QV8ObjectResource::TypeType);
 
134
    QV8TypeResource *resource = static_cast<QV8TypeResource *>(r);
 
135
    QV8Engine *v8engine = resource->engine;
 
136
 
 
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);
 
144
        }
 
145
    }
 
146
 
 
147
    // only QObject Singleton Type can be converted to a variant.
 
148
    return QVariant();
 
149
}
 
150
 
 
151
v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property, 
 
152
                                             const v8::AccessorInfo &info)
 
153
{
 
154
    QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
 
155
 
 
156
    if (!resource) 
 
157
        return v8::Undefined();
 
158
 
 
159
    QV8Engine *v8engine = resource->engine;
 
160
    QQmlContextData *context = v8engine->callingContext();
 
161
 
 
162
    QObject *object = resource->object;
 
163
 
 
164
    QHashedV8String propertystring(property);
 
165
 
 
166
    if (resource->type) {
 
167
        QQmlType *type = resource->type;
 
168
 
 
169
        // singleton types are handled differently to other types.
 
170
        if (type->isSingleton()) {
 
171
            QQmlEngine *e = v8engine->engine();
 
172
            QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
 
173
            siinfo->init(e);
 
174
 
 
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);
 
181
 
 
182
                        // ### Optimize
 
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);
 
187
                            bool ok;
 
188
                            int value = e.keyToValue(enumName.constData(), &ok);
 
189
                            if (ok)
 
190
                                return v8::Integer::New(value);
 
191
                        }
 
192
                    }
 
193
                }
 
194
 
 
195
                // check for property.
 
196
                v8::Handle<v8::Value> rv = v8engine->qobjectWrapper()->getProperty(qobjectSingleton, propertystring, context, QV8QObjectWrapper::IgnoreRevision);
 
197
                return rv;
 
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);
 
203
            }
 
204
 
 
205
            // Fall through to return empty handle
 
206
 
 
207
        } else {
 
208
 
 
209
            if (QV8Engine::startsWithUpper(property)) {
 
210
                bool ok = false;
 
211
                int value = type->enumValue(propertystring, &ok);
 
212
                if (ok)
 
213
                    return v8::Integer::New(value);
 
214
 
 
215
                // Fall through to return empty handle
 
216
 
 
217
            } else if (resource->object) {
 
218
                QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
 
219
                if (ao)
 
220
                    return v8engine->qobjectWrapper()->getProperty(ao, propertystring, context,
 
221
                                                                   QV8QObjectWrapper::IgnoreRevision);
 
222
 
 
223
                // Fall through to return empty handle
 
224
            }
 
225
 
 
226
            // Fall through to return empty handle
 
227
        }
 
228
 
 
229
        // Fall through to return empty handle
 
230
 
 
231
    } else if (resource->typeNamespace) {
 
232
        Q_ASSERT(resource->importNamespace);
 
233
        QQmlTypeNameCache::Result r = resource->typeNamespace->query(propertystring,
 
234
                                                                             resource->importNamespace);
 
235
 
 
236
        if (r.isValid()) {
 
237
            QQmlContextData *context = v8engine->callingContext();
 
238
            if (r.type) {
 
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);
 
246
            }
 
247
 
 
248
            return v8::Undefined();
 
249
 
 
250
        }
 
251
 
 
252
        // Fall through to return empty handle
 
253
 
 
254
    } else {
 
255
        Q_ASSERT(!"Unreachable");
 
256
    }
 
257
 
 
258
    return v8::Handle<v8::Value>();
 
259
}
 
260
 
 
261
v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property, 
 
262
                                             v8::Local<v8::Value> value,
 
263
                                             const v8::AccessorInfo &info)
 
264
{
 
265
    QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
 
266
 
 
267
    if (!resource) 
 
268
        return value;
 
269
 
 
270
    QV8Engine *v8engine = resource->engine;
 
271
    QQmlContextData *context = v8engine->callingContext();
 
272
 
 
273
    QHashedV8String propertystring(property);
 
274
 
 
275
    QQmlType *type = resource->type;
 
276
    if (type && !type->isSingleton() && resource->object) {
 
277
        QObject *object = resource->object;
 
278
        QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
 
279
        if (ao) 
 
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();
 
285
        siinfo->init(e);
 
286
 
 
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)));
 
298
            } else {
 
299
                apiprivate->setProperty(property, setvalp.data());
 
300
            }
 
301
        }
 
302
    }
 
303
 
 
304
    return value;
 
305
}
 
306
 
 
307
QT_END_NAMESPACE