1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmllistwrapper_p.h"
41#include <private/qqmllist_p.h>
42#include <private/qv4objectproto_p.h>
43#include <qv4objectiterator_p.h>
44
45#include <private/qv4functionobject_p.h>
46#include <private/qv4qobjectwrapper_p.h>
47
48QT_BEGIN_NAMESPACE
49
50using namespace QV4;
51
52DEFINE_OBJECT_VTABLE(QmlListWrapper);
53
54void Heap::QmlListWrapper::init()
55{
56 Object::init();
57 object.init();
58 QV4::Scope scope(internalClass->engine);
59 QV4::ScopedObject o(scope, this);
60 o->setArrayType(Heap::ArrayData::Custom);
61}
62
63void Heap::QmlListWrapper::destroy()
64{
65 object.destroy();
66 Object::destroy();
67}
68
69ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, QObject *object, int propId, int propType)
70{
71 if (!object || propId == -1)
72 return Encode::null();
73
74 Scope scope(engine);
75
76 Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocate<QmlListWrapper>());
77 r->d()->object = object;
78 r->d()->propertyType = propType;
79 void *args[] = { &r->d()->property(), nullptr };
80 QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
81 return r.asReturnedValue();
82}
83
84ReturnedValue QmlListWrapper::create(ExecutionEngine *engine, const QQmlListProperty<QObject> &prop, int propType)
85{
86 Scope scope(engine);
87
88 Scoped<QmlListWrapper> r(scope, engine->memoryManager->allocate<QmlListWrapper>());
89 r->d()->object = prop.object;
90 r->d()->property() = prop;
91 r->d()->propertyType = propType;
92 return r.asReturnedValue();
93}
94
95QVariant QmlListWrapper::toVariant() const
96{
97 if (!d()->object)
98 return QVariant();
99
100 return QVariant::fromValue(QQmlListReferencePrivate::init(d()->property(), d()->propertyType, engine()->qmlEngine()));
101}
102
103
104ReturnedValue QmlListWrapper::virtualGet(const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty)
105{
106 Q_ASSERT(m->as<QmlListWrapper>());
107 const QmlListWrapper *w = static_cast<const QmlListWrapper *>(m);
108 QV4::ExecutionEngine *v4 = w->engine();
109
110 if (id.isArrayIndex()) {
111 uint index = id.asArrayIndex();
112 quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
113 if (index < count && w->d()->property().at) {
114 if (hasProperty)
115 *hasProperty = true;
116 return QV4::QObjectWrapper::wrap(v4, w->d()->property().at(&w->d()->property(), index));
117 }
118
119 if (hasProperty)
120 *hasProperty = false;
121 return Value::undefinedValue().asReturnedValue();
122 } else if (id.isString()) {
123 if (id == v4->id_length()->propertyKey() && !w->d()->object.isNull()) {
124 quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
125 return Value::fromUInt32(count).asReturnedValue();
126 }
127 }
128
129 return Object::virtualGet(m, id, receiver, hasProperty);
130}
131
132bool QmlListWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver)
133{
134 // doesn't do anything. Should we throw?
135 Q_UNUSED(m);
136 Q_UNUSED(id);
137 Q_UNUSED(value);
138 Q_UNUSED(receiver);
139 return false;
140}
141
142struct QmlListWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
143{
144 ~QmlListWrapperOwnPropertyKeyIterator() override = default;
145 PropertyKey next(const Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override;
146
147};
148
149PropertyKey QmlListWrapperOwnPropertyKeyIterator::next(const Object *o, Property *pd, PropertyAttributes *attrs)
150{
151 const QmlListWrapper *w = static_cast<const QmlListWrapper *>(o);
152
153 quint32 count = w->d()->property().count ? w->d()->property().count(&w->d()->property()) : 0;
154 if (arrayIndex < count) {
155 uint index = arrayIndex;
156 ++arrayIndex;
157 if (attrs)
158 *attrs = QV4::Attr_Data;
159 if (pd)
160 pd->value = QV4::QObjectWrapper::wrap(w->engine(), w->d()->property().at(&w->d()->property(), index));
161 return PropertyKey::fromArrayIndex(index);
162 }
163
164 return ObjectOwnPropertyKeyIterator::next(o, pd, attrs);
165}
166
167OwnPropertyKeyIterator *QmlListWrapper::virtualOwnPropertyKeys(const Object *m, Value *target)
168{
169 *target = *m;
170 return new QmlListWrapperOwnPropertyKeyIterator;
171}
172
173void PropertyListPrototype::init(ExecutionEngine *)
174{
175 defineDefaultProperty(QStringLiteral("push"), method_push, 1);
176}
177
178ReturnedValue PropertyListPrototype::method_push(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc)
179{
180 Scope scope(b);
181 ScopedObject instance(scope, thisObject->toObject(scope.engine));
182 if (!instance)
183 RETURN_UNDEFINED();
184 QmlListWrapper *w = instance->as<QmlListWrapper>();
185 if (!w)
186 RETURN_UNDEFINED();
187 if (!w->d()->property().append)
188 THROW_GENERIC_ERROR("List doesn't define an Append function");
189
190 QV4::ScopedObject so(scope);
191 for (int i = 0, ei = argc; i < ei; ++i)
192 {
193 so = argv[i].toObject(scope.engine);
194 if (QV4::QObjectWrapper *wrapper = so->as<QV4::QObjectWrapper>())
195 w->d()->property().append(&w->d()->property(), wrapper->object() );
196 }
197 return Encode::undefined();
198}
199
200QT_END_NAMESPACE
201