diff options
Diffstat (limited to 'src/qml/jsapi')
-rw-r--r-- | src/qml/jsapi/jsapi.pri | 12 | ||||
-rw-r--r-- | src/qml/jsapi/qjsengine.cpp | 430 | ||||
-rw-r--r-- | src/qml/jsapi/qjsengine.h | 138 | ||||
-rw-r--r-- | src/qml/jsapi/qjsengine_p.h | 75 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalue.cpp | 1047 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalue.h | 149 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalue_p.h | 99 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalueiterator.cpp | 206 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalueiterator.h | 78 | ||||
-rw-r--r-- | src/qml/jsapi/qjsvalueiterator_p.h | 70 |
10 files changed, 2304 insertions, 0 deletions
diff --git a/src/qml/jsapi/jsapi.pri b/src/qml/jsapi/jsapi.pri new file mode 100644 index 0000000000..f70588ec7b --- /dev/null +++ b/src/qml/jsapi/jsapi.pri @@ -0,0 +1,12 @@ +SOURCES += \ + $$PWD/qjsengine.cpp \ + $$PWD/qjsvalue.cpp \ + $$PWD/qjsvalueiterator.cpp \ + +HEADERS += \ + $$PWD/qjsengine.h \ + $$PWD/qjsengine_p.h \ + $$PWD/qjsvalue.h \ + $$PWD/qjsvalue_p.h \ + $$PWD/qjsvalueiterator.h \ + $$PWD/qjsvalueiterator_p.h diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp new file mode 100644 index 0000000000..d3c2c75ca7 --- /dev/null +++ b/src/qml/jsapi/qjsengine.cpp @@ -0,0 +1,430 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qjsengine.h" +#include "qjsengine_p.h" +#include "qjsvalue.h" +#include "qjsvalue_p.h" +#include "private/qv8engine_p.h" + +#include "private/qv4engine_p.h" +#include "private/qv4mm_p.h" +#include "private/qv4globalobject_p.h" +#include "private/qv4script_p.h" +#include "private/qv4exception_p.h" + +#include <QtCore/qdatetime.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qvariant.h> +#include <QtCore/qdatetime.h> + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdir.h> +#include <QtCore/qfile.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/qpluginloader.h> +#include <qthread.h> +#include <qmutex.h> +#include <qwaitcondition.h> +#include <private/qqmlglobal_p.h> +#include <qqmlengine.h> + +#undef Q_D +#undef Q_Q +#define Q_D(blah) +#define Q_Q(blah) + +Q_DECLARE_METATYPE(QList<int>) + +/*! + \since 5.0 + \class QJSEngine + + \brief The QJSEngine class provides an environment for evaluating JavaScript code. + + \ingroup qtjavascript + \inmodule QtQml + \mainclass + + \section1 Evaluating Scripts + + Use evaluate() to evaluate script code. + + \snippet code/src_script_qjsengine.cpp 0 + + evaluate() returns a QJSValue that holds the result of the + evaluation. The QJSValue class provides functions for converting + the result to various C++ types (e.g. QJSValue::toString() + and QJSValue::toNumber()). + + The following code snippet shows how a script function can be + defined and then invoked from C++ using QJSValue::call(): + + \snippet code/src_script_qjsengine.cpp 1 + + As can be seen from the above snippets, a script is provided to the + engine in the form of a string. One common way of loading scripts is + by reading the contents of a file and passing it to evaluate(): + + \snippet code/src_script_qjsengine.cpp 2 + + Here we pass the name of the file as the second argument to + evaluate(). This does not affect evaluation in any way; the second + argument is a general-purpose string that is used to identify the + script for debugging purposes. + + \section1 Engine Configuration + + The globalObject() function returns the \b {Global Object} + associated with the script engine. Properties of the Global Object + are accessible from any script code (i.e. they are global + variables). Typically, before evaluating "user" scripts, you will + want to configure a script engine by adding one or more properties + to the Global Object: + + \snippet code/src_script_qjsengine.cpp 3 + + Adding custom properties to the scripting environment is one of the + standard means of providing a scripting API that is specific to your + application. Usually these custom properties are objects created by + the newQObject() or newObject() functions. + + \section1 Script Exceptions + + evaluate() can throw a script exception (e.g. due to a syntax + error); in that case, the return value is the value that was thrown + (typically an \c{Error} object). You can check whether the + evaluation caused an exception by calling isError() on the return + value. If isError() returns true, you can call toString() on the + error object to obtain an error message. + + \snippet code/src_script_qjsengine.cpp 4 + + \section1 Script Object Creation + + Use newObject() to create a JavaScript object; this is the + C++ equivalent of the script statement \c{new Object()}. You can use + the object-specific functionality in QJSValue to manipulate the + script object (e.g. QJSValue::setProperty()). Similarly, use + newArray() to create a JavaScript array object. + + \section1 QObject Integration + + Use newQObject() to wrap a QObject (or subclass) + pointer. newQObject() returns a proxy script object; properties, + children, and signals and slots of the QObject are available as + properties of the proxy object. No binding code is needed because it + is done dynamically using the Qt meta object system. + + \snippet code/src_script_qjsengine.cpp 5 + + \sa QJSValue, {Making Applications Scriptable} + +*/ + +QT_BEGIN_NAMESPACE + + +/*! + Constructs a QJSEngine object. + + The globalObject() is initialized to have properties as described in + \l{ECMA-262}, Section 15.1. +*/ +QJSEngine::QJSEngine() + : d(new QV8Engine(this)) +{ +} + +/*! + Constructs a QJSEngine object with the given \a parent. + + The globalObject() is initialized to have properties as described in + \l{ECMA-262}, Section 15.1. +*/ + +QJSEngine::QJSEngine(QObject *parent) + : QObject(parent) + , d(new QV8Engine(this)) +{ +} + +/*! + \internal +*/ +QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent) + : QObject(dd, parent) + , d(new QV8Engine(this)) +{ +} + +/*! + Destroys this QJSEngine. + + Garbage is not collected from the persistent JS heap during QJSEngine + destruction. If you need all memory freed, call collectGarbage manually + right before destroying the QJSEngine. +*/ +QJSEngine::~QJSEngine() +{ + delete d; +} + +/*! + \fn QV8Engine *QJSEngine::handle() const + \internal +*/ + +/*! + Runs the garbage collector. + + The garbage collector will attempt to reclaim memory by locating and disposing of objects that are + no longer reachable in the script environment. + + Normally you don't need to call this function; the garbage collector will automatically be invoked + when the QJSEngine decides that it's wise to do so (i.e. when a certain number of new objects + have been created). However, you can call this function to explicitly request that garbage + collection should be performed as soon as possible. +*/ +void QJSEngine::collectGarbage() +{ + d->m_v4Engine->memoryManager->runGC(); +} + +/*! + Evaluates \a program, using \a lineNumber as the base line number, + and returns the result of the evaluation. + + The script code will be evaluated in the current context. + + The evaluation of \a program can cause an exception in the + engine; in this case the return value will be the exception + that was thrown (typically an \c{Error} object; see + QJSValue::isError()). + + \a lineNumber is used to specify a starting line number for \a + program; line number information reported by the engine that pertain + to this evaluation will be based on this argument. For example, if + \a program consists of two lines of code, and the statement on the + second line causes a script exception, the exception line number + would be \a lineNumber plus one. When no starting line number is + specified, line numbers will be 1-based. + + \a fileName is used for error reporting. For example in error objects + the file name is accessible through the "fileName" property if it's + provided with this function. + + \note If an exception was thrown and the exception value is not an + Error instance (i.e., QJSValue::isError() returns false), the + exception value will still be returned, but there is currently no + API for detecting that an exception did occur in this case. +*/ +QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber) +{ + QV4::ExecutionContext *ctx = d->m_v4Engine->current; + try { + QV4::Script script(ctx, program, fileName, lineNumber); + script.strictMode = ctx->strictMode; + script.inheritContext = true; + script.parse(); + QV4::Value result = script.run(); + return new QJSValuePrivate(d->m_v4Engine, result); + } catch (QV4::Exception& ex) { + ex.accept(ctx); + return new QJSValuePrivate(d->m_v4Engine, ex.value()); + } +} + +/*! + Creates a JavaScript object of class Object. + + The prototype of the created object will be the Object + prototype object. + + \sa newArray(), QJSValue::setProperty() +*/ +QJSValue QJSEngine::newObject() +{ + return new QJSValuePrivate(d->m_v4Engine->newObject()); +} + +/*! + Creates a JavaScript object of class Array with the given \a length. + + \sa newObject() +*/ +QJSValue QJSEngine::newArray(uint length) +{ + QV4::ArrayObject *array = d->m_v4Engine->newArrayObject(); + if (length < 0x1000) + array->arrayReserve(length); + array->setArrayLengthUnchecked(length); + return new QJSValuePrivate(array); +} + +/*! + Creates a JavaScript object that wraps the given QObject \a + object, using JavaScriptOwnership. + + Signals and slots, properties and children of \a object are + available as properties of the created QJSValue. + + If \a object is a null pointer, this function returns a null value. + + If a default prototype has been registered for the \a object's class + (or its superclass, recursively), the prototype of the new script + object will be set to be that default prototype. + + If the given \a object is deleted outside of the engine's control, any + attempt to access the deleted QObject's members through the JavaScript + wrapper object (either by script code or C++) will result in a + script exception. + + \sa QJSValue::toQObject() +*/ +QJSValue QJSEngine::newQObject(QObject *object) +{ + Q_D(QJSEngine); + QV4::ExecutionEngine *v4 = QV8Engine::getV4(d); + QQmlEngine::setObjectOwnership(object, QQmlEngine::JavaScriptOwnership); + return new QJSValuePrivate(v4, QV4::QObjectWrapper::wrap(v4, object)); +} + +/*! + Returns this engine's Global Object. + + By default, the Global Object contains the built-in objects that are + part of \l{ECMA-262}, such as Math, Date and String. Additionally, + you can set properties of the Global Object to make your own + extensions available to all script code. Non-local variables in + script code will be created as properties of the Global Object, as + well as local variables in global code. +*/ +QJSValue QJSEngine::globalObject() const +{ + return new QJSValuePrivate(d->m_v4Engine->globalObject); +} + +/*! + * \internal + * used by QJSEngine::toScriptValue + */ +QJSValue QJSEngine::create(int type, const void *ptr) +{ + Q_D(QJSEngine); + return new QJSValuePrivate(d->m_v4Engine, d->metaTypeToJS(type, ptr)); +} + +/*! + \internal + convert \a value to \a type, store the result in \a ptr +*/ +bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr) +{ + QJSValuePrivate *vp = QJSValuePrivate::get(value); + QV8Engine *engine = vp->engine ? vp->engine->v8Engine : 0; + if (engine) { + return engine->metaTypeFromJS(vp->getValue(engine->m_v4Engine), type, ptr); + } else { + switch (type) { + case QMetaType::Bool: + *reinterpret_cast<bool*>(ptr) = vp->value.toBoolean(); + return true; + case QMetaType::Int: + *reinterpret_cast<int*>(ptr) = vp->value.toInt32(); + return true; + case QMetaType::UInt: + *reinterpret_cast<uint*>(ptr) = vp->value.toUInt32(); + return true; + case QMetaType::LongLong: + *reinterpret_cast<qlonglong*>(ptr) = vp->value.toInteger(); + return true; + case QMetaType::ULongLong: + *reinterpret_cast<qulonglong*>(ptr) = vp->value.toInteger(); + return true; + case QMetaType::Double: + *reinterpret_cast<double*>(ptr) = vp->value.toNumber(); + return true; + case QMetaType::QString: + *reinterpret_cast<QString*>(ptr) = value.toString(); + return true; + case QMetaType::Float: + *reinterpret_cast<float*>(ptr) = vp->value.toNumber(); + return true; + case QMetaType::Short: + *reinterpret_cast<short*>(ptr) = vp->value.toInt32(); + return true; + case QMetaType::UShort: + *reinterpret_cast<unsigned short*>(ptr) = vp->value.toUInt16(); + return true; + case QMetaType::Char: + *reinterpret_cast<char*>(ptr) = vp->value.toInt32(); + return true; + case QMetaType::UChar: + *reinterpret_cast<unsigned char*>(ptr) = vp->value.toUInt16(); + return true; + case QMetaType::QChar: + *reinterpret_cast<QChar*>(ptr) = vp->value.toUInt16(); + return true; + default: + return false; + } + } +} + +/*! \fn QJSValue QJSEngine::toScriptValue(const T &value) + + Creates a QJSValue with the given \a value. + + \sa fromScriptValue() +*/ + +/*! \fn T QJSEngine::fromScriptValue(const QJSValue &value) + + Returns the given \a value converted to the template type \c{T}. + + \sa toScriptValue() +*/ + +QT_END_NAMESPACE + +#include "moc_qjsengine.cpp" diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h new file mode 100644 index 0000000000..0a575f84e9 --- /dev/null +++ b/src/qml/jsapi/qjsengine.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QJSENGINE_H +#define QJSENGINE_H + +#include <QtCore/qmetatype.h> + +#include <QtCore/qvariant.h> +#include <QtCore/qsharedpointer.h> +#include <QtCore/qobject.h> +#include <QtQml/qjsvalue.h> + +QT_BEGIN_NAMESPACE + + +class QV8Engine; + +template <typename T> +inline T qjsvalue_cast(const QJSValue &); + +class QJSEnginePrivate; +class Q_QML_EXPORT QJSEngine + : public QObject +{ + Q_OBJECT +public: + QJSEngine(); + explicit QJSEngine(QObject *parent); + virtual ~QJSEngine(); + + QJSValue globalObject() const; + + QJSValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1); + + QJSValue newObject(); + QJSValue newArray(uint length = 0); + + QJSValue newQObject(QObject *object); + + template <typename T> + inline QJSValue toScriptValue(const T &value) + { + return create(qMetaTypeId<T>(), &value); + } + template <typename T> + inline T fromScriptValue(const QJSValue &value) + { + return qjsvalue_cast<T>(value); + } + + void collectGarbage(); + + QV8Engine *handle() const { return d; } + +private: + QJSValue create(int type, const void *ptr); + + static bool convertV2(const QJSValue &value, int type, void *ptr); + + friend inline bool qjsvalue_cast_helper(const QJSValue &, int, void *); + +protected: + QJSEngine(QJSEnginePrivate &dd, QObject *parent = 0); + +private: + QV8Engine *d; + Q_DISABLE_COPY(QJSEngine) + Q_DECLARE_PRIVATE(QJSEngine) + friend class QV8Engine; +}; + +inline bool qjsvalue_cast_helper(const QJSValue &value, int type, void *ptr) +{ + return QJSEngine::convertV2(value, type, ptr); +} + +template<typename T> +T qjsvalue_cast(const QJSValue &value) +{ + T t; + const int id = qMetaTypeId<T>(); + + if (qjsvalue_cast_helper(value, id, &t)) + return t; + else if (value.isVariant()) + return qvariant_cast<T>(value.toVariant()); + + return T(); +} + +template <> +inline QVariant qjsvalue_cast<QVariant>(const QJSValue &value) +{ + return value.toVariant(); +} + +QT_END_NAMESPACE + +#endif // QJSENGINE_H diff --git a/src/qml/jsapi/qjsengine_p.h b/src/qml/jsapi/qjsengine_p.h new file mode 100644 index 0000000000..c12e647997 --- /dev/null +++ b/src/qml/jsapi/qjsengine_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QJSENGINE_P_H +#define QJSENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/private/qobject_p.h> +#include "qjsengine.h" + + +QT_BEGIN_NAMESPACE + + +class QJSEnginePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QJSEngine) + +public: + static QJSEnginePrivate* get(QJSEngine*e) { return e->d_func(); } + + QJSEnginePrivate() {} +}; + +QT_END_NAMESPACE + +#endif // QJSENGINE_P_H diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp new file mode 100644 index 0000000000..ec8cc2a1b3 --- /dev/null +++ b/src/qml/jsapi/qjsvalue.cpp @@ -0,0 +1,1047 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qstring.h> +#include <QtCore/qvarlengtharray.h> +#include <QtCore/qdatetime.h> +#include "qjsengine.h" +#include "qjsvalue.h" +#include "qjsvalue_p.h" +#include "qv4value_p.h" +#include "qv4object_p.h" +#include "qv4functionobject_p.h" +#include "qv4dateobject_p.h" +#include "qv4runtime_p.h" +#include "qv4variantobject_p.h" +#include "qv4regexpobject_p.h" +#include "private/qv8engine_p.h" +#include <private/qv4mm_p.h> +#include <private/qv4exception_p.h> + +QV4::Value QJSValuePrivate::getValue(QV4::ExecutionEngine *e) +{ + if (!this->engine) + this->engine = e; + else if (this->engine != e) { + qWarning("JSValue can't be reassigned to another engine."); + return QV4::Value::emptyValue(); + } + if (value.asString() == &string) { + value = QV4::Value::fromString(engine->newString(string.toQString())); + PersistentValuePrivate **listRoot = &engine->memoryManager->m_persistentValues; + prev = listRoot; + next = *listRoot; + *prev = this; + if (next) + next->prev = &this->next; + } + return value; +} + +/*! + \since 5.0 + \class QJSValue + + \brief The QJSValue class acts as a container for Qt/JavaScript data types. + + \ingroup qtjavascript + \inmodule QtQml + \mainclass + + QJSValue supports the types defined in the \l{ECMA-262} + standard: The primitive types, which are Undefined, Null, Boolean, + Number, and String; and the Object type. Additionally, built-in + support is provided for Qt/C++ types such as QVariant and QObject. + + For the object-based types (including Date and RegExp), use the + newT() functions in QJSEngine (e.g. QJSEngine::newObject()) + to create a QJSValue of the desired type. For the primitive types, + use one of the QJSValue constructor overloads. + + The methods named isT() (e.g. isBool(), isUndefined()) can be + used to test if a value is of a certain type. The methods named + toT() (e.g. toBool(), toString()) can be used to convert a + QJSValue to another type. You can also use the generic + QJSValue_cast() function. + + Object values have zero or more properties which are themselves + QJSValues. Use setProperty() to set a property of an object, and + call property() to retrieve the value of a property. + + \snippet code/src_script_qjsvalue.cpp 0 + + If you want to iterate over the properties of a script object, use + the QJSValueIterator class. + + Object values have an internal \c{prototype} property, which can be + accessed with prototype() and setPrototype(). + + Function objects (objects for which isCallable()) returns true) can + be invoked by calling call(). Constructor functions can be used to + construct new objects by calling callAsConstructor(). + + Use equals() or strictlyEquals() to compare a QJSValue to another. + + Note that a QJSValue for which isObject() is true only carries a + reference to an actual object; copying the QJSValue will only + copy the object reference, not the object itself. If you want to + clone an object (i.e. copy an object's properties to another + object), you can do so with the help of a \c{for-in} statement in + script code, or QJSValueIterator in C++. + + \sa QJSEngine, QJSValueIterator +*/ + +/*! + \enum QJSValue::SpecialValue + + This enum is used to specify a single-valued type. + + \value UndefinedValue An undefined value. + + \value NullValue A null value. +*/ + +QT_BEGIN_NAMESPACE + +using namespace QV4; + +/*! + Constructs a new QJSValue with a boolean \a value. +*/ +QJSValue::QJSValue(bool value) + : d(new QJSValuePrivate(0, Value::fromBoolean(value))) +{ +} + +QJSValue::QJSValue(QJSValuePrivate *dd) + : d(dd) +{ +} + +/*! + Constructs a new QJSValue with a number \a value. +*/ +QJSValue::QJSValue(int value) + : d(new QJSValuePrivate(0, Value::fromInt32(value))) +{ +} + +/*! + Constructs a new QJSValue with a number \a value. +*/ +QJSValue::QJSValue(uint value) + : d(new QJSValuePrivate(0, Value::fromUInt32(value))) +{ +} + +/*! + Constructs a new QJSValue with a number \a value. +*/ +QJSValue::QJSValue(double value) + : d(new QJSValuePrivate(0, Value::fromDouble(value))) +{ +} + +/*! + Constructs a new QJSValue with a string \a value. +*/ +QJSValue::QJSValue(const QString& value) + : d(new QJSValuePrivate(value)) +{ +} + +/*! + Constructs a new QJSValue with a special \a value. +*/ +QJSValue::QJSValue(SpecialValue value) + : d(new QJSValuePrivate(0, value == UndefinedValue ? Value::undefinedValue() : Value::nullValue())) +{ +} + +/*! + Constructs a new QJSValue with a string \a value. +*/ +QJSValue::QJSValue(const QLatin1String &value) + : d(new QJSValuePrivate(value)) +{ +} + +/*! + Constructs a new QJSValue with a string \a value. +*/ +#ifndef QT_NO_CAST_FROM_ASCII +QJSValue::QJSValue(const char *value) + : d(new QJSValuePrivate(QString::fromLatin1(value))) +{ +} +#endif + +/*! + Constructs a new QJSValue that is a copy of \a other. + + Note that if \a other is an object (i.e., isObject() would return + true), then only a reference to the underlying object is copied into + the new script value (i.e., the object itself is not copied). +*/ +QJSValue::QJSValue(const QJSValue& other) + : d(other.d) +{ + d->ref(); +} + +/*! + Destroys this QJSValue. +*/ +QJSValue::~QJSValue() +{ + d->deref(); +} + +/*! + Returns true if this QJSValue is of the primitive type Boolean; + otherwise returns false. + + \sa toBool() +*/ +bool QJSValue::isBool() const +{ + return d->value.isBoolean(); +} + +/*! + Returns true if this QJSValue is of the primitive type Number; + otherwise returns false. + + \sa toNumber() +*/ +bool QJSValue::isNumber() const +{ + return d->value.isNumber(); +} + +/*! + Returns true if this QJSValue is of the primitive type Null; + otherwise returns false. +*/ +bool QJSValue::isNull() const +{ + return d->value.isNull(); +} + +/*! + Returns true if this QJSValue is of the primitive type String; + otherwise returns false. + + \sa toString() +*/ +bool QJSValue::isString() const +{ + return d->value.isString(); +} + +/*! + Returns true if this QJSValue is of the primitive type Undefined; + otherwise returns false. +*/ +bool QJSValue::isUndefined() const +{ + return d->value.isUndefined(); +} + +/*! + Returns true if this QJSValue is an object of the Error class; + otherwise returns false. +*/ +bool QJSValue::isError() const +{ + Object *o = d->value.asObject(); + return o && o->asErrorObject(); +} + +/*! + Returns true if this QJSValue is an object of the Array class; + otherwise returns false. + + \sa QJSEngine::newArray() +*/ +bool QJSValue::isArray() const +{ + return d->value.asArrayObject(); +} + +/*! + Returns true if this QJSValue is of the Object type; otherwise + returns false. + + Note that function values, variant values, and QObject values are + objects, so this function returns true for such values. + + \sa QJSEngine::newObject() +*/ +bool QJSValue::isObject() const +{ + return d->value.asObject(); +} + +/*! + Returns true if this QJSValue can be called a function, otherwise + returns false. + + \sa call() +*/ +bool QJSValue::isCallable() const +{ + return d->value.asFunctionObject(); +} + +/*! + Returns true if this QJSValue is a variant value; + otherwise returns false. + + \sa toVariant() +*/ +bool QJSValue::isVariant() const +{ + Managed *m = d->value.asManaged(); + return m ? m->as<QV4::VariantObject>() : 0; +} + +/*! + Returns the string value of this QJSValue, as defined in + \l{ECMA-262} section 9.8, "ToString". + + Note that if this QJSValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's toString() function (and possibly valueOf()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa isString() +*/ +QString QJSValue::toString() const +{ + return d->value.toQString(); +} + +/*! + Returns the number value of this QJSValue, as defined in + \l{ECMA-262} section 9.3, "ToNumber". + + Note that if this QJSValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa isNumber(), toInt(), toUInt() +*/ +double QJSValue::toNumber() const +{ + QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0; + try { + return d->value.toNumber(); + } catch (Exception &e) { + e.accept(ctx); + return 0; + } +} + +/*! + Returns the boolean value of this QJSValue, using the conversion + rules described in \l{ECMA-262} section 9.2, "ToBoolean". + + Note that if this QJSValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa isBool() +*/ +bool QJSValue::toBool() const +{ + QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0; + try { + return d->value.toBoolean(); + } catch (Exception &e) { + e.accept(ctx); + return false; + } +} + +/*! + Returns the signed 32-bit integer value of this QJSValue, using + the conversion rules described in \l{ECMA-262} section 9.5, "ToInt32". + + Note that if this QJSValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa toNumber(), toUInt() +*/ +qint32 QJSValue::toInt() const +{ + QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0; + try { + return d->value.toInt32(); + } catch (Exception &e) { + e.accept(ctx); + return 0; + } +} + +/*! + Returns the unsigned 32-bit integer value of this QJSValue, using + the conversion rules described in \l{ECMA-262} section 9.6, "ToUint32". + + Note that if this QJSValue is an object, calling this function + has side effects on the script engine, since the engine will call + the object's valueOf() function (and possibly toString()) in an + attempt to convert the object to a primitive value (possibly + resulting in an uncaught script exception). + + \sa toNumber(), toInt() +*/ +quint32 QJSValue::toUInt() const +{ + QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0; + try { + return d->value.toUInt32(); + } catch (Exception &e) { + e.accept(ctx); + return 0; + } +} + +/*! + Returns the QVariant value of this QJSValue, if it can be + converted to a QVariant; otherwise returns an invalid QVariant. + The conversion is performed according to the following table: + + \table + \header \li Input Type \li Result + \row \li Undefined \li An invalid QVariant. + \row \li Null \li A QVariant containing a null pointer (QMetaType::VoidStar). + \row \li Boolean \li A QVariant containing the value of the boolean. + \row \li Number \li A QVariant containing the value of the number. + \row \li String \li A QVariant containing the value of the string. + \row \li QVariant Object \li The result is the QVariant value of the object (no conversion). + \row \li QObject Object \li A QVariant containing a pointer to the QObject. + \row \li Date Object \li A QVariant containing the date value (toDateTime()). + \row \li RegExp Object \li A QVariant containing the regular expression value. + \row \li Array Object \li The array is converted to a QVariantList. Each element is converted to a QVariant, recursively; cyclic references are not followed. + \row \li Object \li The object is converted to a QVariantMap. Each property is converted to a QVariant, recursively; cyclic references are not followed. + \endtable + + \sa isVariant() +*/ +QVariant QJSValue::toVariant() const +{ + return QV4::VariantObject::toVariant(d->value); +} + +/*! + Calls this QJSValue as a function, passing \a args as arguments + to the function, and using the globalObject() as the "this"-object. + Returns the value returned from the function. + + If this QJSValue is not callable, call() does nothing and + returns an undefined QJSValue. + + Calling call() can cause an exception to occur in the script engine; + in that case, call() returns the value that was thrown (typically an + \c{Error} object). You can call isError() on the return value to + determine whether an exception occurred. + + \sa isCallable(), callWithInstance(), callAsConstructor() +*/ +QJSValue QJSValue::call(const QJSValueList &args) +{ + FunctionObject *f = d->value.asFunctionObject(); + if (!f) + return QJSValue(); + + ExecutionEngine *engine = d->engine; + assert(engine); + + QVarLengthArray<Value, 9> arguments(args.length()); + for (int i = 0; i < args.size(); ++i) { + if (!args.at(i).d->checkEngine(engine)) { + qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine"); + return QJSValue(); + } + arguments[i] = args.at(i).d->getValue(engine); + } + + Value result; + QV4::ExecutionContext *ctx = engine->current; + try { + result = f->call(Value::fromObject(engine->globalObject), arguments.data(), arguments.size()); + } catch (Exception &e) { + e.accept(ctx); + result = e.value(); + } + + return new QJSValuePrivate(engine, result); +} + +/*! + Calls this QJSValue as a function, using \a instance as + the `this' object in the function call, and passing \a args + as arguments to the function. Returns the value returned from + the function. + + If this QJSValue is not a function, call() does nothing + and returns an undefined QJSValue. + + Note that if \a instance is not an object, the global object + (see \l{QJSEngine::globalObject()}) will be used as the + `this' object. + + Calling call() can cause an exception to occur in the script engine; + in that case, call() returns the value that was thrown (typically an + \c{Error} object). You can call isError() on the return value to + determine whether an exception occurred. + + \sa call() +*/ +QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList &args) +{ + FunctionObject *f = d->value.asFunctionObject(); + if (!f) + return QJSValue(); + + ExecutionEngine *engine = d->engine; + assert(engine); + + if (!instance.d->checkEngine(engine)) { + qWarning("QJSValue::call() failed: cannot call function with thisObject created in a different engine"); + return QJSValue(); + } + + QVarLengthArray<Value, 9> arguments(args.length()); + for (int i = 0; i < args.size(); ++i) { + if (!args.at(i).d->checkEngine(engine)) { + qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine"); + return QJSValue(); + } + arguments[i] = args.at(i).d->getValue(engine); + } + + Value result; + QV4::ExecutionContext *ctx = engine->current; + try { + result = f->call(instance.d->getValue(engine), arguments.data(), arguments.size()); + } catch (Exception &e) { + e.accept(ctx); + result = e.value(); + } + + return new QJSValuePrivate(engine, result); +} + +/*! + Creates a new \c{Object} and calls this QJSValue as a + constructor, using the created object as the `this' object and + passing \a args as arguments. If the return value from the + constructor call is an object, then that object is returned; + otherwise the default constructed object is returned. + + If this QJSValue is not a function, callAsConstructor() does + nothing and returns an undefined QJSValue. + + Calling this function can cause an exception to occur in the + script engine; in that case, the value that was thrown + (typically an \c{Error} object) is returned. You can call + isError() on the return value to determine whether an + exception occurred. + + \sa call(), QJSEngine::newObject() +*/ +QJSValue QJSValue::callAsConstructor(const QJSValueList &args) +{ + FunctionObject *f = d->value.asFunctionObject(); + if (!f) + return QJSValue(); + + ExecutionEngine *engine = d->engine; + assert(engine); + + QVarLengthArray<Value, 9> arguments(args.length()); + for (int i = 0; i < args.size(); ++i) { + if (!args.at(i).d->checkEngine(engine)) { + qWarning("QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine"); + return QJSValue(); + } + arguments[i] = args.at(i).d->getValue(engine); + } + + Value result; + QV4::ExecutionContext *ctx = engine->current; + try { + result = f->construct(arguments.data(), arguments.size()); + } catch (Exception &e) { + e.accept(ctx); + result = e.value(); + } + + return new QJSValuePrivate(engine, result); +} + +#ifdef QT_DEPRECATED + +/*! + \obsolete + + Returns the QJSEngine that created this QJSValue, + or 0 if this QJSValue is invalid or the value is not + associated with a particular engine. +*/ +QJSEngine* QJSValue::engine() const +{ + QV4::ExecutionEngine *engine = d->engine; + if (engine) + return engine->v8Engine->publicEngine(); + return 0; +} + +#endif // QT_DEPRECATED + +/*! + If this QJSValue is an object, returns the internal prototype + (\c{__proto__} property) of this object; otherwise returns an + undefined QJSValue. + + \sa setPrototype(), isObject() +*/ +QJSValue QJSValue::prototype() const +{ + Object *o = d->value.asObject(); + if (!o) + return QJSValue(); + if (!o->prototype) + return QJSValue(NullValue); + return new QJSValuePrivate(o->internalClass->engine, Value::fromObject(o->prototype)); +} + +/*! + If this QJSValue is an object, sets the internal prototype + (\c{__proto__} property) of this object to be \a prototype; + if the QJSValue is null, it sets the prototype to null; + otherwise does nothing. + + The internal prototype should not be confused with the public + property with name "prototype"; the public prototype is usually + only set on functions that act as constructors. + + \sa prototype(), isObject() +*/ +void QJSValue::setPrototype(const QJSValue& prototype) +{ + Object *o = d->value.asObject(); + if (!o) + return; + if (prototype.d->value.isNull()) { + o->prototype = 0; + return; + } + + Object *p = prototype.d->value.asObject(); + if (!p) + return; + if (o->engine() != p->engine()) { + qWarning("QJSValue::setPrototype() failed: cannot set a prototype created in a different engine"); + return; + } + Object *pp = p; + while (pp) { + if (pp == o) { + qWarning("QJSValue::setPrototype() failed: cyclic prototype value"); + return; + } + pp = pp->prototype; + } + o->prototype = p; +} + +/*! + Assigns the \a other value to this QJSValue. + + Note that if \a other is an object (isObject() returns true), + only a reference to the underlying object will be assigned; + the object itself will not be copied. +*/ +QJSValue& QJSValue::operator=(const QJSValue& other) +{ + if (d == other.d) + return *this; + d->deref(); + d = other.d; + d->ref(); +} + +/*! + Returns true if this QJSValue is equal to \a other, otherwise + returns false. The comparison follows the behavior described in + \l{ECMA-262} section 11.9.3, "The Abstract Equality Comparison + Algorithm". + + This function can return true even if the type of this QJSValue + is different from the type of the \a other value; i.e. the + comparison is not strict. For example, comparing the number 9 to + the string "9" returns true; comparing an undefined value to a null + value returns true; comparing a \c{Number} object whose primitive + value is 6 to a \c{String} object whose primitive value is "6" + returns true; and comparing the number 1 to the boolean value + \c{true} returns true. If you want to perform a comparison + without such implicit value conversion, use strictlyEquals(). + + Note that if this QJSValue or the \a other value are objects, + calling this function has side effects on the script engine, since + the engine will call the object's valueOf() function (and possibly + toString()) in an attempt to convert the object to a primitive value + (possibly resulting in an uncaught script exception). + + \sa strictlyEquals() +*/ +bool QJSValue::equals(const QJSValue& other) const +{ + return __qmljs_cmp_eq(d->value, other.d->value); +} + +/*! + Returns true if this QJSValue is equal to \a other using strict + comparison (no conversion), otherwise returns false. The comparison + follows the behavior described in \l{ECMA-262} section 11.9.6, "The + Strict Equality Comparison Algorithm". + + If the type of this QJSValue is different from the type of the + \a other value, this function returns false. If the types are equal, + the result depends on the type, as shown in the following table: + + \table + \header \li Type \li Result + \row \li Undefined \li true + \row \li Null \li true + \row \li Boolean \li true if both values are true, false otherwise + \row \li Number \li false if either value is NaN (Not-a-Number); true if values are equal, false otherwise + \row \li String \li true if both values are exactly the same sequence of characters, false otherwise + \row \li Object \li true if both values refer to the same object, false otherwise + \endtable + + \sa equals() +*/ +bool QJSValue::strictlyEquals(const QJSValue& other) const +{ + return __qmljs_strict_equal(d->value, other.d->value); +} + +/*! + Returns the value of this QJSValue's property with the given \a name. + If no such property exists, an undefined QJSValue is returned. + + If the property is implemented using a getter function (i.e. has the + PropertyGetter flag set), calling property() has side-effects on the + script engine, since the getter function will be called (possibly + resulting in an uncaught script exception). If an exception + occurred, property() returns the value that was thrown (typically + an \c{Error} object). + + \sa setProperty(), hasProperty(), QJSValueIterator +*/ +QJSValue QJSValue::property(const QString& name) const +{ + Object *o = d->value.asObject(); + if (!o) + return QJSValue(); + + ExecutionEngine *engine = d->engine; + String *s = engine->newString(name); + uint idx = s->asArrayIndex(); + if (idx < UINT_MAX) + return property(idx); + + s->makeIdentifier(); + QV4::ExecutionContext *ctx = engine->current; + try { + QV4::Value v = o->get(s); + return new QJSValuePrivate(engine, v); + } catch (QV4::Exception &e) { + e.accept(ctx); + return new QJSValuePrivate(engine, e.value()); + } +} + +/*! + \overload + + Returns the property at the given \a arrayIndex. + + This function is provided for convenience and performance when + working with array objects. + + If this QJSValue is not an Array object, this function behaves + as if property() was called with the string representation of \a + arrayIndex. +*/ +QJSValue QJSValue::property(quint32 arrayIndex) const +{ + Object *o = d->value.asObject(); + if (!o) + return QJSValue(); + + ExecutionEngine *engine = d->engine; + QV4::ExecutionContext *ctx = engine->current; + try { + QV4::Value v = arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex); + return new QJSValuePrivate(engine, v); + } catch (QV4::Exception &e) { + e.accept(ctx); + return new QJSValuePrivate(engine, e.value()); + } +} + +/*! + Sets the value of this QJSValue's property with the given \a name to + the given \a value. + + If this QJSValue is not an object, this function does nothing. + + If this QJSValue does not already have a property with name \a name, + a new property is created. + + \sa property(), deleteProperty() +*/ +void QJSValue::setProperty(const QString& name, const QJSValue& value) +{ + Object *o = d->value.asObject(); + if (!o) + return; + + if (!value.d->checkEngine(o->engine())) { + qWarning("QJSValue::setProperty(%s) failed: cannot set value created in a different engine", name.toUtf8().constData()); + return; + } + + ExecutionEngine *engine = d->engine; + String *s = engine->newString(name); + uint idx = s->asArrayIndex(); + if (idx < UINT_MAX) { + setProperty(idx, value); + return; + } + + QV4::ExecutionContext *ctx = engine->current; + s->makeIdentifier(); + try { + o->put(s, value.d->getValue(engine)); + } catch (QV4::Exception &e) { + e.accept(ctx); + } +} + +/*! + \overload + + Sets the property at the given \a arrayIndex to the given \a value. + + This function is provided for convenience and performance when + working with array objects. + + If this QJSValue is not an Array object, this function behaves + as if setProperty() was called with the string representation of \a + arrayIndex. +*/ +void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value) +{ + Object *o = d->value.asObject(); + if (!o) + return; + + ExecutionEngine *engine = d->engine; + QV4::ExecutionContext *ctx = engine->current; + try { + if (arrayIndex != UINT_MAX) + o->putIndexed(arrayIndex, value.d->getValue(engine)); + else + o->put(engine->id_uintMax, value.d->getValue(engine)); + } catch (QV4::Exception &e) { + e.accept(ctx); + } +} + +/*! + Attempts to delete this object's property of the given \a name. + Returns true if the property was deleted, otherwise returns false. + + The behavior of this function is consistent with the JavaScript + delete operator. In particular: + + \list + \li Non-configurable properties cannot be deleted. + \li This function will return true even if this object doesn't + have a property of the given \a name (i.e., non-existent + properties are "trivially deletable"). + \li If this object doesn't have an own property of the given + \a name, but an object in the prototype() chain does, the + prototype object's property is not deleted, and this function + returns true. + \endlist + + \sa setProperty(), hasOwnProperty() +*/ +bool QJSValue::deleteProperty(const QString &name) +{ + Object *o = d->value.asObject(); + if (!o) + return false; + + ExecutionEngine *engine = d->engine; + String *s = engine->newString(name); + return o->deleteProperty(s); +} + +/*! + Returns true if this object has a property of the given \a name, + otherwise returns false. + + \sa property(), hasOwnProperty() +*/ +bool QJSValue::hasProperty(const QString &name) const +{ + Object *o = d->value.asObject(); + if (!o) + return false; + + ExecutionEngine *engine = d->engine; + String *s = engine->newIdentifier(name); + return o->__hasProperty__(s); +} + +/*! + Returns true if this object has an own (not prototype-inherited) + property of the given \a name, otherwise returns false. + + \sa property(), hasProperty() +*/ +bool QJSValue::hasOwnProperty(const QString &name) const +{ + Object *o = d->value.asObject(); + if (!o) + return false; + + ExecutionEngine *engine = d->engine; + String *s = engine->newIdentifier(name); + return o->__getOwnProperty__(s); +} + +/*! + * If this QJSValue is a QObject, returns the QObject pointer + * that the QJSValue represents; otherwise, returns 0. + * + * If the QObject that this QJSValue wraps has been deleted, + * this function returns 0 (i.e. it is possible for toQObject() + * to return 0 even when isQObject() returns true). + * + * \sa isQObject() + */ +QObject *QJSValue::toQObject() const +{ + QV4::QObjectWrapper *o = d->value.as<QV4::QObjectWrapper>(); + if (!o) + return 0; + + return o->object(); +} + +/*! + Returns a QDateTime representation of this value, in local time. + If this QJSValue is not a date, or the value of the date is NaN + (Not-a-Number), an invalid QDateTime is returned. + + \sa isDate() +*/ +QDateTime QJSValue::toDateTime() const +{ + QV4::DateObject *date = d->value.asDateObject(); + if (!date) + return QDateTime(); + return date->toQDateTime(); +} + +/*! + Returns true if this QJSValue is an object of the Date class; + otherwise returns false. + + \sa QJSEngine::newDate() +*/ +bool QJSValue::isDate() const +{ + return d->value.asDateObject(); +} + +/*! + Returns true if this QJSValue is an object of the RegExp class; + otherwise returns false. +*/ +bool QJSValue::isRegExp() const +{ + return d->value.as<RegExpObject>(); +} + +/*! + Returns true if this QJSValue is a QObject; otherwise returns + false. + + Note: This function returns true even if the QObject that this + QJSValue wraps has been deleted. + + \sa toQObject(), QJSEngine::newQObject() +*/ +bool QJSValue::isQObject() const +{ + return d->value.as<QV4::QObjectWrapper>() != 0; +} + +QT_END_NAMESPACE diff --git a/src/qml/jsapi/qjsvalue.h b/src/qml/jsapi/qjsvalue.h new file mode 100644 index 0000000000..cf02ad819e --- /dev/null +++ b/src/qml/jsapi/qjsvalue.h @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QJSVALUE_H +#define QJSVALUE_H + +#include <QtQml/qtqmlglobal.h> +#include <QtCore/qstring.h> +#include <QtCore/qlist.h> +#include <QtCore/qmetatype.h> + +QT_BEGIN_NAMESPACE + + +class QJSValue; +class QJSEngine; +class QVariant; +class QObject; +struct QMetaObject; +class QDateTime; + +typedef QList<QJSValue> QJSValueList; +class QJSValuePrivate; + +class Q_QML_EXPORT QJSValue +{ +public: + enum SpecialValue { + NullValue, + UndefinedValue + }; + +public: + QJSValue(SpecialValue value = UndefinedValue); + ~QJSValue(); + QJSValue(const QJSValue &other); + + QJSValue(bool value); + QJSValue(int value); + QJSValue(uint value); + QJSValue(double value); + QJSValue(const QString &value); + QJSValue(const QLatin1String &value); +#ifndef QT_NO_CAST_FROM_ASCII + QT_ASCII_CAST_WARN QJSValue(const char *str); +#endif + + QJSValue &operator=(const QJSValue &other); + + bool isBool() const; + bool isNumber() const; + bool isNull() const; + bool isString() const; + bool isUndefined() const; + bool isVariant() const; + bool isQObject() const; + bool isObject() const; + bool isDate() const; + bool isRegExp() const; + bool isArray() const; + bool isError() const; + + QString toString() const; + double toNumber() const; + qint32 toInt() const; + quint32 toUInt() const; + bool toBool() const; + QVariant toVariant() const; + QObject *toQObject() const; + QDateTime toDateTime() const; + + bool equals(const QJSValue &other) const; + bool strictlyEquals(const QJSValue &other) const; + + QJSValue prototype() const; + void setPrototype(const QJSValue &prototype); + + QJSValue property(const QString &name) const; + void setProperty(const QString &name, const QJSValue &value); + + bool hasProperty(const QString &name) const; + bool hasOwnProperty(const QString &name) const; + + QJSValue property(quint32 arrayIndex) const; + void setProperty(quint32 arrayIndex, const QJSValue &value); + + bool deleteProperty(const QString &name); + + bool isCallable() const; + QJSValue call(const QJSValueList &args = QJSValueList()); + QJSValue callWithInstance(const QJSValue &instance, const QJSValueList &args = QJSValueList()); + QJSValue callAsConstructor(const QJSValueList &args = QJSValueList()); + +#ifdef QT_DEPRECATED + QT_DEPRECATED QJSEngine *engine() const; +#endif + + QJSValue(QJSValuePrivate *dd); +private: + friend class QJSValuePrivate; + // force compile error, prevent QJSValue(bool) to be called + QJSValue(void *) Q_DECL_EQ_DELETE; + + QJSValuePrivate *d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QJSValue) + +#endif diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h new file mode 100644 index 0000000000..ef94dea555 --- /dev/null +++ b/src/qml/jsapi/qjsvalue_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QJSVALUE_P_H +#define QJSVALUE_P_H + +#include <qjsvalue.h> +#include <private/qv4value_p.h> +#include <private/qv4string_p.h> +#include <private/qv4engine_p.h> +#include <private/qv4object_p.h> + +QT_BEGIN_NAMESPACE + +/*! + \internal + \class QJSValuePrivate +*/ +class QJSValuePrivate : public QV4::PersistentValuePrivate +{ +public: + QJSValuePrivate(QV4::ExecutionEngine *engine, const QV4::Value &v) + : PersistentValuePrivate(v, engine) + { + if (value.isEmpty()) + value = QV4::Value::undefinedValue(); + } + QJSValuePrivate(QV4::Object *o) + : PersistentValuePrivate(QV4::Value::fromObject(o)) + { } + QJSValuePrivate(QV4::String *s) + : PersistentValuePrivate(QV4::Value::fromString(s)) + { } + QJSValuePrivate(const QString &s) + : PersistentValuePrivate(QV4::Value::undefinedValue()) + , string(0, s) + { + value = QV4::Value::fromString(&string); + } + + QV4::Value getValue(QV4::ExecutionEngine *e); + + static QJSValuePrivate *get(const QJSValue &v) { return v.d; } + + QV4::String string; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jsapi/qjsvalueiterator.cpp b/src/qml/jsapi/qjsvalueiterator.cpp new file mode 100644 index 0000000000..aa1ecd6e54 --- /dev/null +++ b/src/qml/jsapi/qjsvalueiterator.cpp @@ -0,0 +1,206 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qjsvalueiterator.h" +#include "qjsvalueiterator_p.h" +#include "qjsvalue_p.h" +#include "private/qv4string_p.h" +#include "private/qv4object_p.h" +#include "private/qv4exception_p.h" + +QT_BEGIN_NAMESPACE + +QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v) + : value(v) + , iterator(QJSValuePrivate::get(v)->value.asObject(), QV4::ObjectIterator::NoFlags) + , currentName(0) + , currentIndex(UINT_MAX) + , nextName(0) + , nextIndex(UINT_MAX) +{ +} + + +/*! + \class QJSValueIterator + + \brief The QJSValueIterator class provides a Java-style iterator for QJSValue. + + \ingroup qtjavascript + \inmodule QtQml + + + The QJSValueIterator constructor takes a QJSValue 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 QJSValue: + + \snippet code/src_script_qjsvalueiterator.cpp 0 + + The next() advances the iterator. The name() and value() + functions return the name and value of the last item that was + jumped over. + + Note that QJSValueIterator only iterates over the QJSValue'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 code/src_script_qjsvalueiterator.cpp 1 + + \sa QJSValue::property() +*/ + +/*! + 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). +*/ +QJSValueIterator::QJSValueIterator(const QJSValue& object) + : d_ptr(new QJSValueIteratorPrivate(object)) +{ + d_ptr->iterator.next(&d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes); +} + +/*! + Destroys the iterator. +*/ +QJSValueIterator::~QJSValueIterator() +{ +} + +/*! + 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() +*/ +bool QJSValueIterator::hasNext() const +{ + if (!QJSValuePrivate::get(d_ptr->value)->value.isObject()) + return false; + return d_ptr->nextName != 0 || d_ptr->nextIndex != UINT_MAX; +} + +/*! + Advances the iterator by one position. + 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. + + Calling this function on an iterator located at the back of the + container leads to undefined results. + + \sa hasNext(), name() +*/ +bool QJSValueIterator::next() +{ + if (!QJSValuePrivate::get(d_ptr->value)->value.isObject()) + return false; + d_ptr->currentName = d_ptr->nextName; + d_ptr->currentIndex = d_ptr->nextIndex; + d_ptr->currentAttributes = d_ptr->nextAttributes; + + d_ptr->iterator.next(&d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes); + return d_ptr->nextName != 0 || d_ptr->nextIndex != UINT_MAX; +} + +/*! + Returns the name of the last property that was jumped over using + next(). + + \sa value() +*/ +QString QJSValueIterator::name() const +{ + if (!QJSValuePrivate::get(d_ptr->value)->value.isObject()) + return false; + if (d_ptr->currentName) + return d_ptr->currentName->toQString(); + if (d_ptr->currentIndex < UINT_MAX) + return QString::number(d_ptr->currentIndex); + return QString(); +} + + +/*! + Returns the value of the last property that was jumped over using + next(). + + \sa name() +*/ +QJSValue QJSValueIterator::value() const +{ + if (!QJSValuePrivate::get(d_ptr->value)->value.isObject()) + return QJSValue(); + + QV4::Object *o = d_ptr->iterator.object; + QV4::ExecutionEngine *engine = o->internalClass->engine; + QV4::ExecutionContext *ctx = engine->current; + try { + QV4::Value v; + if (d_ptr->currentName) + v = o->get(d_ptr->currentName); + else if (d_ptr->currentIndex != UINT_MAX) + v = o->getIndexed(d_ptr->currentIndex); + else + return QJSValue(); + return new QJSValuePrivate(engine, v); + } catch (QV4::Exception &e) { + e.accept(ctx); + return QJSValue(); + } +} + + +/*! + 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). +*/ +QJSValueIterator& QJSValueIterator::operator=(QJSValue& object) +{ + d_ptr->iterator = QV4::ObjectIterator(QJSValuePrivate::get(object)->value.asObject(), QV4::ObjectIterator::NoFlags); + d_ptr->iterator.next(&d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes); + return *this; +} + +QT_END_NAMESPACE diff --git a/src/qml/jsapi/qjsvalueiterator.h b/src/qml/jsapi/qjsvalueiterator.h new file mode 100644 index 0000000000..e204558e90 --- /dev/null +++ b/src/qml/jsapi/qjsvalueiterator.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSCRIPTVALUEITERATOR_H +#define QSCRIPTVALUEITERATOR_H + +#include <QtQml/qjsvalue.h> +#include <QtQml/qtqmlglobal.h> +#include <QtCore/qscopedpointer.h> + +QT_BEGIN_NAMESPACE + + +class QString; + +class QJSValueIteratorPrivate; +class Q_QML_EXPORT QJSValueIterator +{ +public: + QJSValueIterator(const QJSValue &value); + ~QJSValueIterator(); + + bool hasNext() const; + bool next(); + + QString name() const; + + QJSValue value() const; + QJSValueIterator& operator=(QJSValue &value); + +private: + QScopedPointer<QJSValueIteratorPrivate> d_ptr; + + Q_DECLARE_PRIVATE(QJSValueIterator) + Q_DISABLE_COPY(QJSValueIterator) +}; + +QT_END_NAMESPACE + +#endif // QSCRIPTVALUEITERATOR_H diff --git a/src/qml/jsapi/qjsvalueiterator_p.h b/src/qml/jsapi/qjsvalueiterator_p.h new file mode 100644 index 0000000000..7687f896a1 --- /dev/null +++ b/src/qml/jsapi/qjsvalueiterator_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QJSVALUEITERATOR_P_H +#define QJSVALUEITERATOR_P_H + +#include "qjsvalue.h" +#include "private/qv4objectiterator_p.h" + +QT_BEGIN_NAMESPACE + +class QV8Engine; + +class QJSValueIteratorPrivate +{ +public: + QJSValueIteratorPrivate(const QJSValue &v); + + QJSValue value; + QV4::ObjectIterator iterator; + QV4::PropertyAttributes currentAttributes; + QV4::String *currentName; + uint currentIndex; + QV4::PropertyAttributes nextAttributes; + QV4::String *nextName; + uint nextIndex; +}; + + +QT_END_NAMESPACE + +#endif // QJSVALUEITERATOR_P_H |