/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the QtScript module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL-ONLY$ | |
** GNU Lesser General Public License Usage | |
** This file may be used under the terms of the GNU Lesser | |
** General Public License version 2.1 as published by the Free Software | |
** Foundation and appearing in the file LICENSE.LGPL included in the | |
** packaging of this file. Please review the following information to | |
** ensure the GNU Lesser General Public License version 2.1 requirements | |
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | |
** | |
** If you have questions regarding the use of this file, please contact | |
** Nokia at qt-info@nokia.com. | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "config.h" | |
#include "qscriptvalueiterator.h" | |
#include "qscriptstring.h" | |
#include "qscriptengine.h" | |
#include "qscriptengine_p.h" | |
#include "qscriptvalue_p.h" | |
#include "qlinkedlist.h" | |
#include "JSObject.h" | |
#include "PropertyNameArray.h" | |
#include "JSArray.h" | |
#include "JSFunction.h" | |
QT_BEGIN_NAMESPACE | |
/*! | |
\since 4.3 | |
\class QScriptValueIterator | |
\brief The QScriptValueIterator class provides a Java-style iterator for QScriptValue. | |
\ingroup script | |
The QScriptValueIterator constructor takes a QScriptValue as | |
argument. After construction, the iterator is located at the very | |
beginning of the sequence of properties. Here's how to iterate over | |
all the properties of a QScriptValue: | |
\snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 0 | |
The next() advances the iterator. The name(), value() and flags() | |
functions return the name, value and flags of the last item that was | |
jumped over. | |
If you want to remove properties as you iterate over the | |
QScriptValue, use remove(). If you want to modify the value of a | |
property, use setValue(). | |
Note that QScriptValueIterator only iterates over the QScriptValue's | |
own properties; i.e. it does not follow the prototype chain. You can | |
use a loop like this to follow the prototype chain: | |
\snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 1 | |
Note that QScriptValueIterator will not automatically skip over | |
properties that have the QScriptValue::SkipInEnumeration flag set; | |
that flag only affects iteration in script code. If you want, you | |
can skip over such properties with code like the following: | |
\snippet doc/src/snippets/code/src_script_qscriptvalueiterator.cpp 2 | |
\sa QScriptValue::property() | |
*/ | |
class QScriptValueIteratorPrivate | |
{ | |
public: | |
QScriptValueIteratorPrivate() | |
: initialized(false) | |
{} | |
~QScriptValueIteratorPrivate() | |
{ | |
if (!initialized) | |
return; | |
QScriptEnginePrivate *eng_p = engine(); | |
if (!eng_p) | |
return; | |
QScript::APIShim shim(eng_p); | |
propertyNames.clear(); //destroying the identifiers need to be done under the APIShim guard | |
} | |
QScriptValuePrivate *object() const | |
{ | |
return QScriptValuePrivate::get(objectValue); | |
} | |
QScriptEnginePrivate *engine() const | |
{ | |
return QScriptEnginePrivate::get(objectValue.engine()); | |
} | |
void ensureInitialized() | |
{ | |
if (initialized) | |
return; | |
QScriptEnginePrivate *eng_p = engine(); | |
QScript::APIShim shim(eng_p); | |
JSC::ExecState *exec = eng_p->globalExec(); | |
JSC::PropertyNameArray propertyNamesArray(exec); | |
JSC::asObject(object()->jscValue)->getOwnPropertyNames(exec, propertyNamesArray, JSC::IncludeDontEnumProperties); | |
JSC::PropertyNameArray::const_iterator propertyNamesIt = propertyNamesArray.begin(); | |
for(; propertyNamesIt != propertyNamesArray.end(); ++propertyNamesIt) { | |
propertyNames.append(*propertyNamesIt); | |
} | |
it = propertyNames.begin(); | |
initialized = true; | |
} | |
QScriptValue objectValue; | |
QLinkedList<JSC::Identifier> propertyNames; | |
QLinkedList<JSC::Identifier>::iterator it; | |
QLinkedList<JSC::Identifier>::iterator current; | |
bool initialized; | |
}; | |
/*! | |
Constructs an iterator for traversing \a object. The iterator is | |
set to be at the front of the sequence of properties (before the | |
first property). | |
*/ | |
QScriptValueIterator::QScriptValueIterator(const QScriptValue &object) | |
: d_ptr(0) | |
{ | |
if (object.isObject()) { | |
d_ptr.reset(new QScriptValueIteratorPrivate()); | |
d_ptr->objectValue = object; | |
} | |
} | |
/*! | |
Destroys the iterator. | |
*/ | |
QScriptValueIterator::~QScriptValueIterator() | |
{ | |
} | |
/*! | |
Returns true if there is at least one item ahead of the iterator | |
(i.e. the iterator is \e not at the back of the property sequence); | |
otherwise returns false. | |
\sa next(), hasPrevious() | |
*/ | |
bool QScriptValueIterator::hasNext() const | |
{ | |
Q_D(const QScriptValueIterator); | |
if (!d) | |
return false; | |
const_cast<QScriptValueIteratorPrivate*>(d)->ensureInitialized(); | |
return d->it != d->propertyNames.end(); | |
} | |
/*! | |
Advances the iterator by one position. | |
Calling this function on an iterator located at the back of the | |
container leads to undefined results. | |
\sa hasNext(), previous(), name() | |
*/ | |
void QScriptValueIterator::next() | |
{ | |
Q_D(QScriptValueIterator); | |
if (!d) | |
return; | |
d->ensureInitialized(); | |
d->current = d->it; | |
++(d->it); | |
} | |
/*! | |
Returns true if there is at least one item behind the iterator | |
(i.e. the iterator is \e not at the front of the property sequence); | |
otherwise returns false. | |
\sa previous(), hasNext() | |
*/ | |
bool QScriptValueIterator::hasPrevious() const | |
{ | |
Q_D(const QScriptValueIterator); | |
if (!d) | |
return false; | |
const_cast<QScriptValueIteratorPrivate*>(d)->ensureInitialized(); | |
return d->it != d->propertyNames.begin(); | |
} | |
/*! | |
Moves the iterator back by one position. | |
Calling this function on an iterator located at the front of the | |
container leads to undefined results. | |
\sa hasPrevious(), next(), name() | |
*/ | |
void QScriptValueIterator::previous() | |
{ | |
Q_D(QScriptValueIterator); | |
if (!d) | |
return; | |
d->ensureInitialized(); | |
--(d->it); | |
d->current = d->it; | |
} | |
/*! | |
Moves the iterator to the front of the QScriptValue (before the | |
first property). | |
\sa toBack(), next() | |
*/ | |
void QScriptValueIterator::toFront() | |
{ | |
Q_D(QScriptValueIterator); | |
if (!d) | |
return; | |
d->ensureInitialized(); | |
d->it = d->propertyNames.begin(); | |
} | |
/*! | |
Moves the iterator to the back of the QScriptValue (after the | |
last property). | |
\sa toFront(), previous() | |
*/ | |
void QScriptValueIterator::toBack() | |
{ | |
Q_D(QScriptValueIterator); | |
if (!d) | |
return; | |
d->ensureInitialized(); | |
d->it = d->propertyNames.end(); | |
} | |
/*! | |
Returns the name of the last property that was jumped over using | |
next() or previous(). | |
\sa value(), flags() | |
*/ | |
QString QScriptValueIterator::name() const | |
{ | |
Q_D(const QScriptValueIterator); | |
if (!d || !d->initialized || !d->engine()) | |
return QString(); | |
return d->current->ustring(); | |
} | |
/*! | |
\since 4.4 | |
Returns the name of the last property that was jumped over using | |
next() or previous(). | |
*/ | |
QScriptString QScriptValueIterator::scriptName() const | |
{ | |
Q_D(const QScriptValueIterator); | |
if (!d || !d->initialized || !d->engine()) | |
return QScriptString(); | |
return d->engine()->toStringHandle(*d->current); | |
} | |
/*! | |
Returns the value of the last property that was jumped over using | |
next() or previous(). | |
\sa setValue(), name() | |
*/ | |
QScriptValue QScriptValueIterator::value() const | |
{ | |
Q_D(const QScriptValueIterator); | |
if (!d || !d->initialized || !d->engine()) | |
return QScriptValue(); | |
QScript::APIShim shim(d->engine()); | |
JSC::JSValue jsValue = d->object()->property(*d->current); | |
return d->engine()->scriptValueFromJSCValue(jsValue); | |
} | |
/*! | |
Sets the \a value of the last property that was jumped over using | |
next() or previous(). | |
\sa value(), name() | |
*/ | |
void QScriptValueIterator::setValue(const QScriptValue &value) | |
{ | |
Q_D(QScriptValueIterator); | |
if (!d || !d->initialized || !d->engine()) | |
return; | |
QScript::APIShim shim(d->engine()); | |
JSC::JSValue jsValue = d->engine()->scriptValueToJSCValue(value); | |
d->object()->setProperty(*d->current, jsValue); | |
} | |
/*! | |
Returns the flags of the last property that was jumped over using | |
next() or previous(). | |
\sa value() | |
*/ | |
QScriptValue::PropertyFlags QScriptValueIterator::flags() const | |
{ | |
Q_D(const QScriptValueIterator); | |
if (!d || !d->initialized || !d->engine()) | |
return 0; | |
QScript::APIShim shim(d->engine()); | |
return d->object()->propertyFlags(*d->current); | |
} | |
/*! | |
Removes the last property that was jumped over using next() | |
or previous(). | |
\sa setValue() | |
*/ | |
void QScriptValueIterator::remove() | |
{ | |
Q_D(QScriptValueIterator); | |
if (!d || !d->initialized || !d->engine()) | |
return; | |
QScript::APIShim shim(d->engine()); | |
d->object()->setProperty(*d->current, JSC::JSValue()); | |
d->propertyNames.erase(d->current); | |
} | |
/*! | |
Makes the iterator operate on \a object. The iterator is set to be | |
at the front of the sequence of properties (before the first | |
property). | |
*/ | |
QScriptValueIterator& QScriptValueIterator::operator=(QScriptValue &object) | |
{ | |
d_ptr.reset(); | |
if (object.isObject()) { | |
d_ptr.reset(new QScriptValueIteratorPrivate()); | |
d_ptr->objectValue = object; | |
} | |
return *this; | |
} | |
QT_END_NAMESPACE |