source: trunk/src/script/qscriptvalueiteratorimpl.cpp@ 98

Last change on this file since 98 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 11.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtScript module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qscriptvalueiteratorimpl_p.h"
43
44#ifndef QT_NO_SCRIPT
45
46#include "qscriptengine_p.h"
47#include "qscriptcontext_p.h"
48#include "qscriptvalueimpl_p.h"
49#include "qscriptmember_p.h"
50#include "qscriptobject_p.h"
51
52QT_BEGIN_NAMESPACE
53
54namespace QScript {
55
56extern QString numberToString(qsreal value);
57
58} // namespace
59
60QScriptValueIteratorImpl::QScriptValueIteratorImpl(const QScriptValueImpl &obj)
61{
62 Q_ASSERT(obj.isObject());
63 m_frontObject = obj;
64 m_member.invalidate();
65 m_foundMember.invalidate();
66 m_foundForward = false;
67 m_object = obj;
68 m_searchIndex = 0;
69 m_searchClassDataIterator = false;
70 m_classDataIterator = 0;
71 m_ignoresDontEnum = true;
72 m_enumerateProto = false;
73}
74
75QScriptValueIteratorImpl::~QScriptValueIteratorImpl()
76{
77 if (m_classDataIterator) {
78 delete m_classDataIterator;
79 m_classDataIterator = 0;
80 }
81}
82
83bool QScriptValueIteratorImpl::ignoresDontEnum() const
84{
85 return m_ignoresDontEnum;
86}
87
88void QScriptValueIteratorImpl::setIgnoresDontEnum(bool ignore)
89{
90 m_ignoresDontEnum = ignore;
91}
92
93bool QScriptValueIteratorImpl::enumeratePrototype() const
94{
95 return m_enumerateProto;
96}
97
98void QScriptValueIteratorImpl::setEnumeratePrototype(bool enable)
99{
100 m_enumerateProto = enable;
101}
102
103bool QScriptValueIteratorImpl::acceptsMember(const QScriptValueImpl &o,
104 const QScript::Member &m) const
105{
106 if (!m.isValid() || (!m_ignoresDontEnum && m.dontEnum())
107 || (m.isSetter() && !m.isGetter())) {
108 return false;
109 }
110
111 if (!m_enumerateProto || QScriptEnginePrivate::strictlyEquals(o, m_frontObject))
112 return true;
113
114 // make sure it's not a shadowed property
115 QScript::Member dummy;
116 QScriptValueImpl base;
117 QScriptNameIdImpl *id;
118 if (m.nameId()) {
119 id = m.nameId();
120 } else {
121 QScriptEnginePrivate *eng_p = m_frontObject.engine();
122 id = eng_p->nameId(QScript::numberToString(m.id()));
123 }
124 m_frontObject.resolve(id, &dummy, &base, QScriptValue::ResolvePrototype, QScript::Read);
125 return QScriptEnginePrivate::strictlyEquals(base, o);
126}
127
128bool QScriptValueIteratorImpl::hasNext()
129{
130 if (m_foundMember.isValid() && m_foundForward) {
131 // we have the information about the next element already
132 return true;
133 }
134
135 int idx, count;
136 QScriptValueImpl obj = m_object;
137
138 if (m_searchClassDataIterator) {
139 Q_ASSERT(m_classDataIterator != 0);
140 if (m_foundMember.isValid()) {
141 // undo effect of hasPrevious()
142 m_foundMember.invalidate();
143 QScript::Member dummy;
144 m_classDataIterator->next(&dummy);
145 }
146 goto LSearchClassData;
147 }
148
149 idx = m_searchIndex;
150 if (m_foundMember.isValid()) {
151 // undo effect of hasPrevious()
152 m_foundMember.invalidate();
153 ++idx;
154 }
155
156 LSearchObjectData:
157 count = obj.memberCount();
158 for (int i = idx; i < count; ++i) {
159 QScript::Member m;
160 obj.member(i, &m);
161 if (acceptsMember(obj, m)) {
162 m_foundObject = obj;
163 m_foundMember = m;
164 m_foundForward = true;
165 m_searchIndex = i + 1;
166 return true;
167 }
168 }
169
170 if (!m_classDataIterator) {
171 QScriptClassData *data = obj.classInfo()->data();
172 if (!data)
173 goto LNext;
174 m_classDataIterator = data->newIterator(obj);
175 if (!m_classDataIterator)
176 goto LNext;
177 }
178 m_searchClassDataIterator = true;
179
180 LSearchClassData:
181 Q_ASSERT(m_classDataIterator != 0);
182 while (m_classDataIterator->hasNext()) {
183 QScript::Member m;
184 m_classDataIterator->next(&m);
185 if (acceptsMember(obj, m)) {
186 m_foundObject = obj;
187 m_foundMember = m;
188 m_foundForward = true;
189 return true;
190 }
191 }
192
193 LNext:
194 if (!m_enumerateProto || !obj.prototype().isObject())
195 return false;
196
197 // look in prototype
198 obj = obj.prototype();
199 idx = 0;
200 if (m_classDataIterator) {
201 delete m_classDataIterator;
202 m_classDataIterator = 0;
203 m_searchClassDataIterator = false;
204 }
205 goto LSearchObjectData;
206}
207
208void QScriptValueIteratorImpl::next()
209{
210 (void)hasNext(); // sync the next-element info
211 m_object = m_foundObject;
212 m_member = m_foundMember;
213 m_foundObject = QScriptValueImpl();
214 m_foundMember.invalidate();
215}
216
217bool QScriptValueIteratorImpl::hasPrevious()
218{
219 if (m_foundMember.isValid() && !m_foundForward) {
220 // we have the information about the previous element already
221 return true;
222 }
223
224 QScriptValueImpl obj = m_object;
225
226 if (m_searchClassDataIterator) {
227 Q_ASSERT(m_classDataIterator != 0);
228 if (m_foundMember.isValid()) {
229 // undo effect of hasNext()
230 m_foundMember.invalidate();
231 QScript::Member dummy;
232 m_classDataIterator->previous(&dummy);
233 }
234 while (m_classDataIterator->hasPrevious()) {
235 QScript::Member m;
236 m_classDataIterator->previous(&m);
237 if (acceptsMember(obj, m)) {
238 m_foundObject = obj;
239 m_foundMember = m;
240 m_foundForward = false;
241 return true;
242 }
243 }
244 m_searchClassDataIterator = false;
245 m_searchIndex = obj.memberCount();
246 m_foundMember.invalidate();
247 }
248
249 // search object members
250 int i = m_searchIndex - 1;
251 if (m_foundMember.isValid()) {
252 // undo effect of hasPrevious()
253 m_foundMember.invalidate();
254 --i;
255 }
256 for ( ; i >= 0; --i) {
257 QScript::Member m;
258 obj.member(i, &m);
259 if (acceptsMember(obj, m)) {
260 m_foundObject = obj;
261 m_foundMember = m;
262 m_foundForward = false;
263 m_searchIndex = i;
264 return true;
265 }
266 }
267
268 return false;
269}
270
271void QScriptValueIteratorImpl::previous()
272{
273 (void)hasPrevious(); // sync the previous-element info
274 m_object = m_foundObject;
275 m_member = m_foundMember;
276 m_foundObject = QScriptValueImpl();
277 m_foundMember.invalidate();
278}
279
280QScript::Member *QScriptValueIteratorImpl::member()
281{
282 return &m_member;
283}
284
285QScriptNameIdImpl *QScriptValueIteratorImpl::nameId() const
286{
287 return m_member.nameId();
288}
289
290QString QScriptValueIteratorImpl::name() const
291{
292 if (!m_member.isValid())
293 return QString();
294 if (m_member.nameId())
295 return m_member.nameId()->s;
296 else
297 return QScript::numberToString(m_member.id());
298}
299
300QScriptValueImpl QScriptValueIteratorImpl::value() const
301{
302 if (!m_member.isValid())
303 return QScriptValueImpl();
304 QScriptValueImpl result;
305 m_object.get(m_member, &result);
306 if (m_member.isGetterOrSetter()) {
307 // find and call the getter
308 QScriptValueImpl getter;
309 if (m_member.isObjectProperty() && !m_member.isGetter()) {
310 QScript::Member mb;
311 QScriptObject *obj = m_object.m_object_value;
312 mb.object(m_member.nameId(), obj->memberCount(), 0);
313 if (!obj->findGetter(&mb))
314 return QScriptValueImpl();
315 m_object.get(mb, &getter);
316 } else {
317 getter = result;
318 }
319 result = getter.call(m_object);
320 }
321 return result;
322}
323
324void QScriptValueIteratorImpl::setValue(const QScriptValueImpl &value)
325{
326 if (!m_member.isValid())
327 return;
328 if (m_member.isGetterOrSetter()) {
329 // find and call the setter
330 QScriptValueImpl setter;
331 if (m_member.isObjectProperty() && !m_member.isSetter()) {
332 QScript::Member mb;
333 QScriptObject *obj = m_object.m_object_value;
334 mb.object(m_member.nameId(), obj->memberCount(), 0);
335 if (!obj->findSetter(&mb))
336 return;
337 m_object.get(mb, &setter);
338 } else {
339 m_object.get(m_member, &setter);
340 }
341 setter.call(m_object, QScriptValueImplList() << value);
342 } else {
343 m_object.put(m_member, value);
344 }
345}
346
347uint QScriptValueIteratorImpl::flags() const
348{
349 return m_member.flags();
350}
351
352QScriptValueImpl QScriptValueIteratorImpl::object() const
353{
354 return m_object;
355}
356
357void QScriptValueIteratorImpl::setObject(const QScriptValueImpl &obj)
358{
359 Q_ASSERT(obj.isObject());
360 m_object = obj;
361 if (m_classDataIterator) {
362 delete m_classDataIterator;
363 m_classDataIterator = 0;
364 }
365 toFront();
366}
367
368void QScriptValueIteratorImpl::remove()
369{
370 if (m_member.isValid())
371 m_object.removeMember(m_member);
372}
373
374void QScriptValueIteratorImpl::toFront()
375{
376 if (m_classDataIterator) {
377 if (!m_enumerateProto || QScriptEnginePrivate::strictlyEquals(m_object, m_frontObject)) {
378 m_classDataIterator->toFront();
379 } else {
380 delete m_classDataIterator;
381 m_classDataIterator = 0;
382 }
383 }
384
385 m_member.invalidate();
386 m_object = m_frontObject;
387
388 m_foundObject = QScriptValueImpl();
389 m_foundMember.invalidate();
390 m_searchIndex = 0;
391 m_searchClassDataIterator = false;
392}
393
394void QScriptValueIteratorImpl::toBack()
395{
396 m_member.invalidate();
397
398 m_foundObject = QScriptValueImpl();
399 m_foundMember.invalidate();
400
401 if (!m_classDataIterator) {
402 QScriptClassData *data = m_object.classInfo()->data();
403 if (data)
404 m_classDataIterator = data->newIterator(m_object);
405 }
406 if (m_classDataIterator)
407 m_classDataIterator->toBack();
408 else
409 m_searchIndex = m_object.memberCount();
410 m_searchClassDataIterator = (m_classDataIterator != 0);
411}
412
413QT_END_NAMESPACE
414
415#endif // QT_NO_SCRIPT
Note: See TracBrowser for help on using the repository browser.