Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / v8 / qv8sequencewrapper_p_p.h
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #ifndef QV8SEQUENCEWRAPPER_P_P_H
43 #define QV8SEQUENCEWRAPPER_P_P_H
44
45 //
46 //  W A R N I N G
47 //  -------------
48 //
49 // This file is not part of the Qt API.  It exists purely as an
50 // implementation detail.  This header file may change from version to
51 // version without notice, or even be removed.
52 //
53 // We mean it.
54 //
55
56 #include <private/qdeclarativeengine_p.h>
57 #include <private/qdeclarativemetatype_p.h>
58
59 QT_BEGIN_NAMESPACE
60
61 /*!
62   \internal
63   \class QV8SequenceResource
64   \brief The abstract base class of the external resource used in sequence type objects
65
66   Every sequence type object returned by QV8SequenceWrapper::fromVariant() or
67   QV8SequenceWrapper::newSequence() has a type-specific QV8SequenceResource which
68   contains the type name, the meta type ids of the sequence and sequence element
69   types, as well as either the sequence data (copy) or object pointer and property
70   index (reference) data associated with the sequence.
71  */
72 class QV8SequenceResource : public QV8ObjectResource
73 {
74     V8_RESOURCE_TYPE(SequenceType);
75
76 public:
77     virtual ~QV8SequenceResource() {}
78
79     enum ObjectType { Reference, Copy };
80
81     virtual QVariant toVariant() = 0;
82     virtual bool isEqual(const QV8SequenceResource *v) = 0;
83
84     virtual quint32 lengthGetter() = 0;
85     virtual void lengthSetter(v8::Handle<v8::Value> value) = 0;
86     virtual v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) = 0;
87     virtual v8::Handle<v8::Value> indexedGetter(quint32 index) = 0;
88     virtual v8::Handle<v8::Boolean> indexedDeleter(quint32 index) = 0;
89     virtual v8::Handle<v8::Array> indexedEnumerator() = 0;
90     virtual v8::Handle<v8::Value> toString() = 0;
91
92     ObjectType objectType;
93     QByteArray typeName;
94     int sequenceMetaTypeId;
95     int elementMetaTypeId;
96
97 protected:
98     QV8SequenceResource(QV8Engine *engine, ObjectType type, const QByteArray &name, int sequenceId, int elementId)
99         : QV8ObjectResource(engine), objectType(type), typeName(name), sequenceMetaTypeId(sequenceId), elementMetaTypeId(elementId)
100     {
101     }
102 };
103
104 static int convertV8ValueToInt(QV8Engine *, v8::Handle<v8::Value> v)
105 {
106     return v->Int32Value();
107 }
108
109 static v8::Handle<v8::Value> convertIntToV8Value(QV8Engine *, int v)
110 {
111     return v8::Integer::New(v);
112 }
113
114 static QString convertIntToString(QV8Engine *, int v)
115 {
116     return QString::number(v);
117 }
118
119 static qreal convertV8ValueToReal(QV8Engine *, v8::Handle<v8::Value> v)
120 {
121     return v->NumberValue();
122 }
123
124 static v8::Handle<v8::Value> convertRealToV8Value(QV8Engine *, qreal v)
125 {
126     return v8::Number::New(v);
127 }
128
129 static QString convertRealToString(QV8Engine *, qreal v)
130 {
131     return QString::number(v);
132 }
133
134 static bool convertV8ValueToBool(QV8Engine *, v8::Handle<v8::Value> v)
135 {
136     return v->BooleanValue();
137 }
138
139 static v8::Handle<v8::Value> convertBoolToV8Value(QV8Engine *, bool v)
140 {
141     return v8::Boolean::New(v);
142 }
143
144 static QString convertBoolToString(QV8Engine *, bool v)
145 {
146     if (v)
147         return QLatin1String("true");
148     return QLatin1String("false");
149 }
150
151 static QString convertV8ValueToString(QV8Engine *e, v8::Handle<v8::Value> v)
152 {
153     return e->toString(v->ToString());
154 }
155
156 static v8::Handle<v8::Value> convertStringToV8Value(QV8Engine *e, const QString &v)
157 {
158     return e->toString(v);
159 }
160
161 static QString convertStringToString(QV8Engine *, const QString &v)
162 {
163     return v;
164 }
165
166 static QString convertV8ValueToQString(QV8Engine *e, v8::Handle<v8::Value> v)
167 {
168     return e->toString(v->ToString());
169 }
170
171 static v8::Handle<v8::Value> convertQStringToV8Value(QV8Engine *e, const QString &v)
172 {
173     return e->toString(v);
174 }
175
176 static QString convertQStringToString(QV8Engine *, const QString &v)
177 {
178     return v;
179 }
180
181 static QUrl convertV8ValueToUrl(QV8Engine *e, v8::Handle<v8::Value> v)
182 {
183     QUrl u;
184     u.setEncodedUrl(e->toString(v->ToString()).toUtf8(), QUrl::TolerantMode);
185     return u;
186 }
187
188 static v8::Handle<v8::Value> convertUrlToV8Value(QV8Engine *e, const QUrl &v)
189 {
190     return e->toString(v.toEncoded());
191 }
192
193 static QString convertUrlToString(QV8Engine *, const QUrl &v)
194 {
195     return v.toString();
196 }
197
198
199 /*
200   \internal
201   \class QV8<Type>SequenceResource
202   \brief The external resource used in sequence type objects
203
204   Every sequence type object returned by QV8SequenceWrapper::newSequence() has
205   a QV8<Type>SequenceResource which contains a property index and a pointer
206   to the object which contains the property.
207
208   Every sequence type object returned by QV8SequenceWrapper::fromVariant() has
209   a QV8<Type>SequenceResource which contains a copy of the sequence value.
210   Operations on the sequence are implemented directly in terms of that sequence data.
211
212   There exists one QV8<Type>SequenceResource instance for every JavaScript Object
213   (sequence) instance returned from QV8SequenceWrapper::newSequence() or
214   QV8SequenceWrapper::fromVariant().
215  */
216
217 //  F(elementType, elementTypeName, sequenceType, defaultValue)
218 #define FOREACH_QML_SEQUENCE_TYPE(F) \
219     F(int, Int, QList<int>, 0) \
220     F(qreal, Real, QList<qreal>, 0.0) \
221     F(bool, Bool, QList<bool>, false) \
222     F(QString, String, QList<QString>, QString()) \
223     F(QString, QString, QStringList, QString()) \
224     F(QUrl, Url, QList<QUrl>, QUrl())
225
226 #define QML_SEQUENCE_TYPE_RESOURCE(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue, ConversionToV8fn, ConversionFromV8fn, ToStringfn) \
227     QT_END_NAMESPACE \
228     Q_DECLARE_METATYPE(SequenceType) \
229     QT_BEGIN_NAMESPACE \
230     class QV8##SequenceElementTypeName##SequenceResource : public QV8SequenceResource { \
231         public:\
232             QV8##SequenceElementTypeName##SequenceResource(QV8Engine *engine, QObject *obj, int propIdx) \
233                 : QV8SequenceResource(engine, QV8SequenceResource::Reference, #SequenceType, qMetaTypeId<SequenceType>(), qMetaTypeId<SequenceElementType>()) \
234                 , object(obj), propertyIndex(propIdx) \
235             { \
236             } \
237             QV8##SequenceElementTypeName##SequenceResource(QV8Engine *engine, const SequenceType &value) \
238                 : QV8SequenceResource(engine, QV8SequenceResource::Copy, #SequenceType, qMetaTypeId<SequenceType>(), qMetaTypeId<SequenceElementType>()) \
239                 , object(0), propertyIndex(-1), c(value) \
240             { \
241             } \
242             ~QV8##SequenceElementTypeName##SequenceResource() \
243             { \
244             } \
245             static QVariant toVariant(QV8Engine *e, v8::Handle<v8::Array> array, uint32_t length, bool *succeeded) \
246             { \
247                 SequenceType list; \
248                 for (uint32_t ii = 0; ii < length; ++ii) { \
249                     list.append(ConversionFromV8fn(e, array->Get(ii))); \
250                 } \
251                 *succeeded = true; \
252                 return QVariant::fromValue<SequenceType>(list); \
253             } \
254             QVariant toVariant() \
255             { \
256                 if (objectType == QV8SequenceResource::Reference) { \
257                     if (!object) \
258                         return QVariant(); \
259                     loadReference(); \
260                 } \
261                 return QVariant::fromValue<SequenceType>(c); \
262             } \
263             bool isEqual(const QV8SequenceResource *v) \
264             { \
265                 /* Note: two different sequences can never be equal (even if they  */ \
266                 /* contain the same elements in the same order) in order to        */ \
267                 /* maintain JavaScript semantics.  However, if they both reference */ \
268                 /* the same QObject+propertyIndex, they are equal.                 */ \
269                 if (objectType == QV8SequenceResource::Reference && v->objectType == QV8SequenceResource::Reference) { \
270                     if (sequenceMetaTypeId == v->sequenceMetaTypeId) { \
271                         const QV8##SequenceElementTypeName##SequenceResource *rhs = static_cast<const QV8##SequenceElementTypeName##SequenceResource *>(v); \
272                         return (object != 0 && object == rhs->object && propertyIndex == rhs->propertyIndex); \
273                     } \
274                 } else if (objectType == QV8SequenceResource::Copy && v->objectType == QV8SequenceResource::Copy) { \
275                     if (sequenceMetaTypeId == v->sequenceMetaTypeId) { \
276                         const QV8##SequenceElementTypeName##SequenceResource *rhs = static_cast<const QV8##SequenceElementTypeName##SequenceResource *>(v); \
277                         return (this == rhs); \
278                     } \
279                 } \
280                 return false; \
281             } \
282             quint32 lengthGetter() \
283             { \
284                 if (objectType == QV8SequenceResource::Reference) { \
285                     if (!object) \
286                         return 0; \
287                     loadReference(); \
288                 } \
289                 return c.count(); \
290             } \
291             void lengthSetter(v8::Handle<v8::Value> value) \
292             { \
293                 /* Get the new required length */ \
294                 if (value.IsEmpty() || !value->IsUint32()) \
295                     return; \
296                 quint32 newLength = value->Uint32Value(); \
297                 /* Read the sequence from the QObject property if we're a reference */ \
298                 if (objectType == QV8SequenceResource::Reference) { \
299                     if (!object) \
300                         return; \
301                     void *a[] = { &c, 0 }; \
302                     QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
303                 } \
304                 /* Determine whether we need to modify the sequence */ \
305                 quint32 count = c.count(); \
306                 if (newLength == count) { \
307                     return; \
308                 } else if (newLength > count) { \
309                     /* according to ECMA262r3 we need to insert */ \
310                     /* undefined values increasing length to newLength. */ \
311                     /* We cannot, so we insert default-values instead. */ \
312                     while (newLength > count++) { \
313                         c.append(DefaultValue); \
314                     } \
315                 } else { \
316                     /* according to ECMA262r3 we need to remove */ \
317                     /* elements until the sequence is the required length. */ \
318                     while (newLength < count) { \
319                         count--; \
320                         c.removeAt(count); \
321                     } \
322                 } \
323                 /* write back if required. */ \
324                 if (objectType == QV8SequenceResource::Reference) { \
325                     /* write back.  already checked that object is non-null, so skip that check here. */ \
326                     int status = -1; \
327                     QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::DontRemoveBinding; \
328                     void *a[] = { &c, 0, &status, &flags }; \
329                     QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
330                 } \
331                 return; \
332             } \
333             v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) \
334             { \
335                 if (objectType == QV8SequenceResource::Reference) { \
336                     if (!object) \
337                         return v8::Undefined(); \
338                     loadReference(); \
339                 } \
340                 /* modify the sequence */ \
341                 SequenceElementType elementValue = ConversionFromV8fn(engine, value); \
342                 quint32 count = c.count(); \
343                 if (index == count) { \
344                     c.append(elementValue); \
345                 } else if (index < count) { \
346                     c[index] = elementValue; \
347                 } else { \
348                     /* according to ECMA262r3 we need to insert */ \
349                     /* the value at the given index, increasing length to index+1. */ \
350                     while (index > count++) { \
351                         c.append(DefaultValue); \
352                     } \
353                     c.append(elementValue); \
354                 } \
355                 /* write back.  already checked that object is non-null, so skip that check here. */ \
356                 if (objectType == QV8SequenceResource::Reference) \
357                     storeReference(); \
358                 return value; \
359             } \
360             v8::Handle<v8::Value> indexedGetter(quint32 index) \
361             { \
362                 if (objectType == QV8SequenceResource::Reference) { \
363                     if (!object) \
364                         return v8::Undefined(); \
365                     loadReference(); \
366                 } \
367                 quint32 count = c.count(); \
368                 if (index < count) \
369                     return ConversionToV8fn(engine, c.at(index)); \
370                 return v8::Undefined(); \
371             } \
372             v8::Handle<v8::Boolean> indexedDeleter(quint32 index) \
373             { \
374                 if (objectType == QV8SequenceResource::Reference) { \
375                     if (!object) \
376                         return v8::Boolean::New(false); \
377                     void *a[] = { &c, 0 }; \
378                     QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
379                 } \
380                 if (index < c.count()) { \
381                     /* according to ECMA262r3 it should be Undefined, */ \
382                     /* but we cannot, so we insert a default-value instead. */ \
383                     c.replace(index, DefaultValue); \
384                     if (objectType == QV8SequenceResource::Reference) { \
385                         /* write back.  already checked that object is non-null, so skip that check here. */ \
386                         int status = -1; \
387                         QDeclarativePropertyPrivate::WriteFlags flags = QDeclarativePropertyPrivate::DontRemoveBinding; \
388                         void *a[] = { &c, 0, &status, &flags }; \
389                         QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
390                     } \
391                     return v8::Boolean::New(true); \
392                 } \
393                 return v8::Boolean::New(false); \
394             } \
395             v8::Handle<v8::Array> indexedEnumerator() \
396             { \
397                 if (objectType == QV8SequenceResource::Reference) { \
398                     if (!object) \
399                         return v8::Handle<v8::Array>(); \
400                     loadReference(); \
401                 } \
402                 quint32 count = c.count(); \
403                 v8::Local<v8::Array> retn = v8::Array::New(count); \
404                 for (quint32 i = 0; i < count; ++i) { \
405                     retn->Set(i, v8::Integer::NewFromUnsigned(i)); \
406                 } \
407                 return retn; \
408             } \
409             v8::Handle<v8::Value> toString() \
410             { \
411                 if (objectType == QV8SequenceResource::Reference) { \
412                     if (!object) \
413                         return v8::Undefined(); \
414                     loadReference(); \
415                 } \
416                 QString str; \
417                 quint32 count = c.count(); \
418                 for (quint32 i = 0; i < count; ++i) { \
419                     str += QString(QLatin1String("%1,")).arg(ToStringfn(engine, c[i])); \
420                 } \
421                 str.chop(1); \
422                 return engine->toString(str); \
423             } \
424             void loadReference() \
425             { \
426                 Q_ASSERT(object); \
427                 Q_ASSERT(objectType == QV8SequenceResource::Reference); \
428                 void *a[] = { &c, 0 }; \
429                 QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
430             } \
431             void storeReference() \
432             { \
433                 Q_ASSERT(object); \
434                 Q_ASSERT(objectType == QV8SequenceResource::Reference); \
435                 int status = -1; \
436                 QDeclarativePropertyPrivate::WriteFlags flags = \
437                     QDeclarativePropertyPrivate::DontRemoveBinding; \
438                 void *a[] = { &c, 0, &status, &flags }; \
439                 QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
440             } \
441         private: \
442             QDeclarativeGuard<QObject> object; \
443             int propertyIndex; \
444             SequenceType c; \
445     };
446
447 #define GENERATE_QML_SEQUENCE_TYPE_RESOURCE(ElementType, ElementTypeName, SequenceType, DefaultValue) \
448     QML_SEQUENCE_TYPE_RESOURCE(ElementType, ElementTypeName, SequenceType, DefaultValue, convert##ElementTypeName##ToV8Value, convertV8ValueTo##ElementTypeName, convert##ElementTypeName##ToString)
449
450 FOREACH_QML_SEQUENCE_TYPE(GENERATE_QML_SEQUENCE_TYPE_RESOURCE)
451 #undef GENERATE_QML_SEQUENCE_TYPE_RESOURCE
452 #undef QML_SEQUENCE_TYPE_RESOURCE
453
454 QT_END_NAMESPACE
455
456 #endif // QV8SEQUENCEWRAPPER_P_P_H