Merge branch 'qtquick2' of scm.dev.nokia.troll.no:qt/qtdeclarative-staging into v8
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v8 / qv8valuetypewrapper.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
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.
15 **
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.
23 **
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.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qv8valuetypewrapper_p.h"
43 #include "qv8engine_p.h"
44
45 #include <private/qdeclarativevaluetype_p.h>
46 #include <private/qdeclarativebinding_p.h>
47
48 QT_BEGIN_NAMESPACE
49
50 class QV8ValueTypeResource : public QV8ObjectResource
51 {
52     V8_RESOURCE_TYPE(ValueTypeType);
53
54 public:
55     enum ObjectType { Reference, Copy };
56
57     QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType);
58
59     ObjectType objectType;
60     QDeclarativeValueType *type;
61 };
62
63 class QV8ValueTypeReferenceResource : public QV8ValueTypeResource
64 {
65 public:
66     QV8ValueTypeReferenceResource(QV8Engine *engine);
67
68     QDeclarativeGuard<QObject> object;
69     int property;
70 };
71
72 class QV8ValueTypeCopyResource : public QV8ValueTypeResource
73 {
74 public:
75     QV8ValueTypeCopyResource(QV8Engine *engine);
76
77     QVariant value;
78 };
79
80 QV8ValueTypeResource::QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType)
81 : QV8ObjectResource(engine), objectType(objectType)
82 {
83 }
84
85 QV8ValueTypeReferenceResource::QV8ValueTypeReferenceResource(QV8Engine *engine)
86 : QV8ValueTypeResource(engine, Reference)
87 {
88 }
89
90 QV8ValueTypeCopyResource::QV8ValueTypeCopyResource(QV8Engine *engine)
91 : QV8ValueTypeResource(engine, Copy)
92 {
93 }
94
95 QV8ValueTypeWrapper::QV8ValueTypeWrapper()
96 : m_engine(0)
97 {
98 }
99
100 QV8ValueTypeWrapper::~QV8ValueTypeWrapper()
101 {
102 }
103
104 void QV8ValueTypeWrapper::destroy()
105 {
106     qPersistentDispose(m_constructor);
107 }
108
109 void QV8ValueTypeWrapper::init(QV8Engine *engine)
110 {
111     m_engine = engine;
112     v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
113     ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
114     ft->InstanceTemplate()->SetHasExternalResource(true);
115     m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
116 }
117
118 v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(QObject *object, int property, QDeclarativeValueType *type)
119 {
120     // XXX NewInstance() should be optimized
121     v8::Local<v8::Object> rv = m_constructor->NewInstance(); 
122     QV8ValueTypeReferenceResource *r = new QV8ValueTypeReferenceResource(m_engine);
123     r->type = type; r->object = object; r->property = property;
124     rv->SetExternalResource(r);
125     return rv;
126 }
127
128 v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(const QVariant &value, QDeclarativeValueType *type)
129 {
130     // XXX NewInstance() should be optimized
131     v8::Local<v8::Object> rv = m_constructor->NewInstance(); 
132     QV8ValueTypeCopyResource *r = new QV8ValueTypeCopyResource(m_engine);
133     r->type = type; r->value = value;
134     rv->SetExternalResource(r);
135     return rv;
136 }
137
138 QVariant QV8ValueTypeWrapper::toVariant(v8::Handle<v8::Object> obj)
139 {
140     QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(obj);
141     if (r) return toVariant(r);
142     else return QVariant();
143 }
144
145 QVariant QV8ValueTypeWrapper::toVariant(QV8ObjectResource *r)
146 {
147     Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType);
148     QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r);
149     
150     if (resource->objectType == QV8ValueTypeResource::Reference) {
151         QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
152
153         if (reference->object) {
154             reference->type->read(reference->object, reference->property);
155             return reference->type->value();
156         } else {
157             return QVariant();
158         }
159
160     } else {
161         Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
162
163         QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
164
165         return copy->value;
166     }
167 }
168
169 v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property, 
170                                                   const v8::AccessorInfo &info)
171 {
172     QV8ValueTypeResource *r =  v8_resource_cast<QV8ValueTypeResource>(info.This());
173     if (!r) return v8::Undefined();
174
175     // XXX This is horribly inefficient.  Sadly people seem to have taken a liking to 
176     // value type properties, so we should probably try and optimize it a little.
177     // We should probably just replace all value properties with dedicated accessors.
178
179     QByteArray propName = r->engine->toString(property).toUtf8();
180     int index = r->type->metaObject()->indexOfProperty(propName.constData());
181     if (index == -1)
182         return v8::Undefined();
183
184     if (r->objectType == QV8ValueTypeResource::Reference) {
185         QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
186
187         if (!reference->object)
188             return v8::Undefined();
189
190         r->type->read(reference->object, reference->property);
191     } else {
192         Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
193
194         QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
195
196         r->type->setValue(copy->value);
197     }
198
199     QMetaProperty prop = r->type->metaObject()->property(index);
200     QVariant result = prop.read(r->type);
201
202     return r->engine->fromVariant(result);
203 }
204
205 v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property, 
206                                                   v8::Local<v8::Value> value,
207                                                   const v8::AccessorInfo &info)
208 {
209     QV8ValueTypeResource *r =  v8_resource_cast<QV8ValueTypeResource>(info.This());
210     if (!r) return value;
211
212     QByteArray propName = r->engine->toString(property).toUtf8();
213     int index = r->type->metaObject()->indexOfProperty(propName.constData());
214     if (index == -1)
215         return value;
216
217     if (r->objectType == QV8ValueTypeResource::Reference) {
218         QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
219
220         if (!reference->object || 
221             !reference->object->metaObject()->property(reference->property).isWritable())
222             return value;
223
224         r->type->read(reference->object, reference->property);
225         QMetaProperty p = r->type->metaObject()->property(index);
226
227         QDeclarativeBinding *newBinding = 0;
228
229         if (value->IsFunction()) {
230             QDeclarativeContextData *context = r->engine->callingContext();
231             v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
232
233             QDeclarativePropertyCache::Data cacheData;
234             cacheData.flags = QDeclarativePropertyCache::Data::IsWritable;
235             cacheData.propType = reference->object->metaObject()->property(reference->property).userType();
236             cacheData.coreIndex = reference->property;
237
238             QDeclarativePropertyCache::ValueTypeData valueTypeData;
239             valueTypeData.valueTypeCoreIdx = index;
240             valueTypeData.valueTypePropType = p.userType();
241
242             v8::Local<v8::StackTrace> trace = 
243                 v8::StackTrace::CurrentStackTrace(1, 
244                         (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber | 
245                                                             v8::StackTrace::kScriptName));
246             v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
247             int lineNumber = frame->GetLineNumber();
248             QString url = r->engine->toString(frame->GetScriptName());
249
250             newBinding = new QDeclarativeBinding(&function, reference->object, context);
251             newBinding->setSourceLocation(url, lineNumber);
252             newBinding->setTarget(QDeclarativePropertyPrivate::restore(cacheData, valueTypeData, 
253                                                                        reference->object, context));
254             newBinding->setEvaluateFlags(newBinding->evaluateFlags() | QDeclarativeBinding::RequiresThisObject);
255         }
256
257         QDeclarativeAbstractBinding *oldBinding = 
258             QDeclarativePropertyPrivate::setBinding(reference->object, reference->property, index, newBinding);
259         if (oldBinding)
260             oldBinding->destroy();
261
262         if (!value->IsFunction()) {
263             QVariant v = r->engine->toVariant(value, -1);
264
265             if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
266                 v = v.toInt();
267
268             p.write(reference->type, v);
269
270             reference->type->write(reference->object, reference->property, 0);
271         }
272
273     } else {
274         Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
275
276         QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
277
278         QVariant v = r->engine->toVariant(value, -1);
279
280         r->type->setValue(copy->value);
281         QMetaProperty p = r->type->metaObject()->property(index);
282         p.write(r->type, v);
283         copy->value = r->type->value();
284     }
285
286     return value;
287 }
288
289 QT_END_NAMESPACE