diff options
author | Kent Hansen <khansen@trolltech.com> | 2009-08-18 10:39:16 (GMT) |
---|---|---|
committer | Kent Hansen <khansen@trolltech.com> | 2009-08-18 10:39:16 (GMT) |
commit | 0b96a20f201dbd91599ee890f42dd8e452d15f79 (patch) | |
tree | fbefbfe77e669f7d58a39c2be612a7098e6f7e17 /doc/src/scripting/scripting.qdoc | |
parent | 379073630202d37cf8e3927dc9745134ac2f5512 (diff) | |
parent | 7a64a3f67d53a99e6e2200f6481c98013004b4e4 (diff) | |
download | Qt-0b96a20f201dbd91599ee890f42dd8e452d15f79.zip Qt-0b96a20f201dbd91599ee890f42dd8e452d15f79.tar.gz Qt-0b96a20f201dbd91599ee890f42dd8e452d15f79.tar.bz2 |
Merge branch 'master' of git@scm.dev.nokia.troll.no:qt/qt into qtscript-jsc-backend
Conflicts:
src/script/qscriptclass.cpp
src/script/qscriptcontext.cpp
src/script/qscriptengine.cpp
src/script/qscriptvalue.cpp
Diffstat (limited to 'doc/src/scripting/scripting.qdoc')
-rw-r--r-- | doc/src/scripting/scripting.qdoc | 1891 |
1 files changed, 1891 insertions, 0 deletions
diff --git a/doc/src/scripting/scripting.qdoc b/doc/src/scripting/scripting.qdoc new file mode 100644 index 0000000..2973f09 --- /dev/null +++ b/doc/src/scripting/scripting.qdoc @@ -0,0 +1,1891 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, 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. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \group script + \title Scripting Classes and Overviews + + \brief Classes that add scripting capabilities to Qt applications. +*/ + +/*! + \page scripting.html + \title Making Applications Scriptable + \ingroup frameworks-technologies + + Qt 4.3 and later provides support for application scripting with ECMAScript. + The following guides and references cover aspects of programming with + ECMAScript and Qt. + + \tableofcontents + + \section1 Scripting Classes + + The following classes add scripting capabilities to Qt applications. + + \annotatedlist script + + \section1 Language Overview + + Qt Script is based on the ECMAScript scripting language, as defined + in standard \l{ECMA-262}. Microsoft's JScript, and Netscape's + JavaScript are also based on the ECMAScript standard. For an + overview of ECMAScript, see the + \l{ECMAScript Reference}{ECMAScript reference}. + If you are not familiar with the ECMAScript language, there are + several existing tutorials and books that cover this subject, such + as \l{JavaScript: The Definitive Guide}. + + Existing users of \l{Qt Script for Applications (QSA)} may find the + \l{Moving from QSA to Qt Script} document useful when porting + QSA scripts to Qt Script. + + \section1 Basic Usage + + To evaluate script code, you create a QScriptEngine and call its + evaluate() function, passing the script code (text) to evaluate + as argument. + + \snippet doc/src/snippets/qtscript/evaluation/main.cpp 0 + + The return value will be the result of the evaluation (represented + as a QScriptValue object); this can be converted to standard C++ + and Qt types. + + Custom properties can be made available to scripts by registering + them with the script engine. This is most easily done by setting + properties of the script engine's \e{Global Object}: + + \snippet doc/src/snippets/qtscript/registeringvalues/main.cpp 0 + + This places the properties in the script environment, thus making them + available to script code. + + \section1 Making a QObject Available to the Script Engine + + Any QObject-based instance can be made available for use with scripts. + + When a QObject is passed to the QScriptEngine::newQObject() function, + a Qt Script wrapper object is created that can be used to make the + QObject's signals, slots, properties, and child objects available + to scripts. + + Here's an example of making an instance of a QObject subclass + available to script code under the name \c{"myObject"}: + + \snippet doc/src/snippets/qtscript/registeringobjects/main.cpp 0 + + This will create a global variable called \c{myObject} in the + script environment. The variable serves as a proxy to the + underlying C++ object. Note that the name of the script variable + can be anything; i.e., it is not dependent upon QObject::objectName(). + + The \l{QScriptEngine::}{newQObject()} function accepts two additional + optional arguments: one is the ownership mode, and the other is a + collection of options that allow you to control certain aspects of how + the QScriptValue that wraps the QObject should behave. We will come + back to the usage of these arguments later. + + \section2 Using Signals and Slots + + Qt Script adapts Qt's central \l{Signals and Slots} feature for + scripting. There are three principal ways to use signals and slots + with Qt Script: + + \list + \i \bold{Hybrid C++/script}: C++ application code connects a + signal to a script function. The script function can, for example, be + a function that the user has typed in, or one that you have read from a + file. This approach is useful if you have a QObject but don't want + to expose the object itself to the scripting environment; you just + want a script to be able to define how a signal should be reacted + to, and leave it up to the C++ side of your application to establish + the connection. + + \i \bold{Hybrid script/C++}: A script can connect signals and slots + to establish connections between pre-defined objects that the + application exposes to the scripting environment. In this scenario, + the slots themselves are still written in C++, but the definition of + the connections is fully dynamic (script-defined). + + \i \bold{Purely script-defined}: A script can both define signal + handler functions (effectively "slots written in Qt Script"), + \e{and} set up the connections that utilize those handlers. For + example, a script can define a function that will handle the + QLineEdit::returnPressed() signal, and then connect that signal to the + script function. + \endlist + + Use the qScriptConnect() function to connect a C++ signal to a + script function. In the following example a script signal handler is + defined that will handle the QLineEdit::textChanged() signal: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 47 + + The first two arguments to qScriptConnect() are the same + as you would pass to QObject::connect() to establish a normal C++ + connection. The third argument is the script object that will act + as the \c this object when the signal handler is invoked; in the above + example we pass an invalid script value, so the \c this object will + be the Global Object. The fourth argument is the script function + ("slot") itself. The following example shows how the \c this argument + can be put to use: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 48 + + We create two QLineEdit objects and define a single signal handler + function. The connections use the same handler function, but the + function will be invoked with a different \c this object depending on + which object's signal was triggered, so the output of the print() + statement will be different for each. + + In script code, Qt Script uses a different syntax for connecting to + and disconnecting from signals than the familiar C++ syntax; i.e., + QObject::connect(). + To connect to a signal, you reference the relevant signal as a property + of the sender object, and invoke its \c{connect()} function. There + are three overloads of \c{connect()}, each with a corresponding + \c{disconnect()} overload. The following subsections describe these + three forms. + + \section3 Signal to Function Connections + + \c{connect(function)} + + In this form of connection, the argument to \c{connect()} is the + function to connect to the signal. + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 2 + + The argument can be a Qt Script function, as in the above + example, or it can be a QObject slot, as in + the following example: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 3 + + When the argument is a QObject slot, the argument types of the + signal and slot do not necessarily have to be compatible; + QtScript will, if necessary, perform conversion of the signal + arguments to match the argument types of the slot. + + To disconnect from a signal, you invoke the signal's + \c{disconnect()} function, passing the function to disconnect + as argument: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 4 + + When a script function is invoked in response to a signal, the + \c this object will be the Global Object. + + \section3 Signal to Member Function Connections + + \c{connect(thisObject, function)} + + In this form of the \c{connect()} function, the first argument + is the object that will be bound to the variable, \c this, when + the function specified using the second argument is invoked. + + If you have a push button in a form, you typically want to do + something involving the form in response to the button's + \c{clicked} signal; passing the form as the \c this object + makes sense in such a case. + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 5 + + To disconnect from the signal, pass the same arguments to \c{disconnect()}: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 6 + + \section3 Signal to Named Member Function Connections + + \c{connect(thisObject, functionName)} + + In this form of the \c{connect()} function, the first argument is + the object that will be bound to the variable, \c this, when + a function is invoked in response to the signal. The second argument + specifies the name of a function that is connected to the signal, + and this refers to a member function of the object passed as the + first argument (\c thisObject in the above scheme). + + Note that the function is resolved when the connection is made, not + when the signal is emitted. + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 7 + + To disconnect from the signal, pass the same arguments to \c{disconnect()}: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 8 + + \section3 Error Handling + + When \c{connect()} or \c{disconnect()} succeeds, the function will + return \c{undefined}; otherwise, it will throw a script exception. + You can obtain an error message from the resulting \c{Error} object. + Example: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 9 + + \section3 Emitting Signals from Scripts + + To emit a signal from script code, you simply invoke the signal + function, passing the relevant arguments: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 10 + + It is currently not possible to define a new signal in a script; + i.e., all signals must be defined by C++ classes. + + \section3 Overloaded Signals and Slots + + When a signal or slot is overloaded, QtScript will attempt to + pick the right overload based on the actual types of the QScriptValue arguments + involved in the function invocation. For example, if your class has slots + \c{myOverloadedSlot(int)} and \c{myOverloadedSlot(QString)}, the following + script code will behave reasonably: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 11 + + You can specify a particular overload by using array-style property access + with the \l{QMetaObject::normalizedSignature()}{normalized signature} of + the C++ function as the property name: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 12 + + If the overloads have different number of arguments, QtScript will + pick the overload with the argument count that best matches the + actual number of arguments passed to the slot. + + For overloaded signals, Qt Script will throw an error if you try to connect + to the signal by name; you have to refer to the signal with the full + normalized signature of the particular overload you want to connect to. + + \section2 Accessing Properties + + The properties of the QObject are available as properties + of the corresponding QtScript object. When you manipulate + a property in script code, the C++ get/set method for that + property will automatically be invoked. For example, if your + C++ class has a property declared as follows: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 13 + + then script code can do things like the following: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 14 + + \section2 Accessing Child QObjects + + Every named child of the QObject (that is, for which + QObject::objectName() is not an empty string) is by default available as + a property of the QtScript wrapper object. For example, + if you have a QDialog with a child widget whose \c{objectName} property is + \c{"okButton"}, you can access this object in script code through + the expression + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 15 + + Since \c{objectName} is itself a Q_PROPERTY, you can manipulate + the name in script code to, for example, rename an object: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 16 + + You can also use the functions \c{findChild()} and \c{findChildren()} + to find children. These two functions behave identically to + QObject::findChild() and QObject::findChildren(), respectively. + + For example, we can use these functions to find objects using strings + and regular expressions: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 17 + + You typically want to use \c{findChild()} when manipulating a form + that uses nested layouts; that way the script is isolated from the + details about which particular layout a widget is located in. + + \section2 Controlling QObject Ownership + + Qt Script uses garbage collection to reclaim memory used by script + objects when they are no longer needed; an object's memory can be + automatically reclaimed when it is no longer referenced anywhere in + the scripting environment. Qt Script lets you control what happens + to the underlying C++ QObject when the wrapper object is reclaimed + (i.e., whether the QObject is deleted or not); you do this when you + create an object by passing an ownership mode as the second argument + to QScriptEngine::newQObject(). + + Knowing how Qt Script deals with ownership is important, since it can + help you avoid situations where a C++ object isn't deleted when it + should be (causing memory leaks), or where a C++ object \e{is} + deleted when it shouldn't be (typically causing a crash if C++ code + later tries to access that object). + + \section3 Qt Ownership + + By default, the script engine does not take ownership of the + QObject that is passed to QScriptEngine::newQObject(); the object + is managed according to Qt's object ownership (see + \l{Object Trees and Object Ownership}). This mode is appropriate + when, for example, you are wrapping C++ objects that are part of + your application's core; that is, they should persist regardless of + what happens in the scripting environment. Another way of stating + this is that the C++ objects should outlive the script engine. + + \section3 Script Ownership + + Specifying QScriptEngine::ScriptOwnership as the ownership mode + will cause the script engine to take full ownership of the QObject + and delete it when it determines that it is safe to do so + (i.e., when there are no more references to it in script code). + This ownership mode is appropriate if the QObject does not have a + parent object, and/or the QObject is created in the context of the + script engine and is not intended to outlive the script engine. + + For example, a constructor function that constructs QObjects + only to be used in the script environment is a good candidate: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 18 + + \section3 Auto-Ownership + + With QScriptEngine::AutoOwnership the ownership is based on whether + the QObject has a parent or not. + If the QtScript garbage collector finds that the QObject is no + longer referenced within the script environment, the QObject will + be deleted \e{only} if it does not have a parent. + + \section3 What Happens When Someone Else Deletes the QObject? + + It is possible that a wrapped QObject is deleted outside of + Qt Script's control; i.e., without regard to the ownership mode + specified. In this case, the wrapper object will still + be an object (unlike the C++ pointer it wraps, the script object + won't become null). Any attempt to access properties of the script + object will, however, result in a script exception being thrown. + + Note that QScriptValue::isQObject() will still return true for a + deleted QObject, since it tests the type of the script object, not + whether the internal pointer is non-null. In other words, if + QScriptValue::isQObject() returns true but QScriptValue::toQObject() + returns a null pointer, this indicates that the QObject has been + deleted outside of Qt Script (perhaps accidentally). + + \section2 Customizing Access to the QObject + + QScriptEngine::newQObject() can take a third argument which allows + you to control various aspects of the access to the QObject through + the QtScript wrapper object it returns. + + QScriptEngine::ExcludeChildObjects specifies that child objects of + the QObject should not appear as properties of the wrapper object. + + QScriptEngine::ExcludeSuperClassProperties and + QScriptEngine::ExcludeSuperClassMethods can be used to avoid + exposing members that are inherited from the QObject's superclass. + This is useful for defining a "pure" interface where inherited members + don't make sense from a scripting perspective; e.g., you don't want + script authors to be able to change the \c{objectName} property of + the object or invoke the \c{deleteLater()} slot. + + QScriptEngine::AutoCreateDynamicProperties specifies that properties + that don't already exist in the QObject should be created as dynamic + properties of the QObject, rather than as properties of the QtScript + wrapper object. If you want new properties to truly become persistent + properties of the QObject, rather than properties that are destroyed + along with the wrapper object (and that aren't shared if the QObject + is wrapped multiple times with QScriptEngine::newQObject()), you + should use this option. + + QScriptEngine::SkipMethodsInEnumeration specifies that signals and + slots should be skipped when enumerating the properties of the QObject + wrapper in a for-in script statement. This is useful when defining + prototype objects, since by convention function properties of + prototypes should not be enumerable. + + \section2 Making a QObject-based Class New-able from a Script + + The QScriptEngine::newQObject() function is used to wrap an + existing QObject instance, so that it can be made available to + scripts. A different scenario is that you want scripts to be + able to construct new objects, not just access existing ones. + + The Qt meta-type system currently does not provide dynamic + binding of constructors for QObject-based classes. If you want to + make such a class new-able from scripts, Qt Script can generate + a reasonable script constructor for you; see + QScriptEngine::scriptValueFromQMetaObject(). + + You can also use QScriptEngine::newFunction() to wrap your own + factory function, and add it to the script environment; see + QScriptEngine::newQMetaObject() for an example. + + \section2 Enum Values + + Values for enums declared with Q_ENUMS are not available as + properties of individual wrapper objects; rather, they are + properties of the QMetaObject wrapper object that can be created + with QScriptEngine::newQMetaObject(). + + \section1 Conversion Between QtScript and C++ Types + + QtScript will perform type conversion when a value needs to be + converted from the script side to the C++ side or vice versa; for + instance, when a C++ signal triggers a script function, when + you access a QObject property in script code, or when + you call QScriptEngine::toScriptValue() or + QScriptEngine::fromScriptValue() in C++. QtScript provides default + conversion operations for many of the built-in Qt types. You can + change the conversion operation for a type (including your custom + C++ types) by registering your own conversion functions with + qScriptRegisterMetaType(). + + \section2 Default Conversion from Qt Script to C++ + + The following table describes the default conversion from a + QScriptValue to a C++ type. + + \table 80% + \header \o C++ Type \o Default Conversion + \row \o bool \o QScriptValue::toBool() + \row \o int \o QScriptValue::toInt32() + \row \o uint \o QScriptValue::toUInt32() + \row \o float \o float(QScriptValue::toNumber()) + \row \o double \o QScriptValue::toNumber() + \row \o short \o short(QScriptValue::toInt32()) + \row \o ushort \o QScriptValue::toUInt16() + \row \o char \o char(QScriptValue::toInt32()) + \row \o uchar \o unsigned char(QScriptValue::toInt32()) + \row \o qlonglong \o qlonglong(QScriptValue::toInteger()) + \row \o qulonglong \o qulonglong(QScriptValue::toInteger()) + \row \o QString \o An empty string if the QScriptValue is null + or undefined; QScriptValue::toString() otherwise. + \row \o QDateTime \o QScriptValue::toDateTime() + \row \o QDate \o QScriptValue::toDateTime().date() + \row \o QRegExp \o QScriptValue::toRegExp() + \row \o QObject* \o QScriptValue::toQObject() + \row \o QWidget* \o QScriptValue::toQObject() + \row \o QVariant \o QScriptValue::toVariant() + \row \o QChar \o If the QScriptValue is a string, the result + is the first character of the string, or a null QChar + if the string is empty; otherwise, the result is a QChar + constructed from the unicode obtained by converting the + QScriptValue to a \c{ushort}. + \row \o QStringList \o If the QScriptValue is an array, the + result is a QStringList constructed from the result of + QScriptValue::toString() for each array element; otherwise, + the result is an empty QStringList. + \row \o QVariantList \o If the QScriptValue is an array, the result + is a QVariantList constructed from the result of + QScriptValue::toVariant() for each array element; otherwise, + the result is an empty QVariantList. + \row \o QVariantMap \o If the QScriptValue is an object, the result + is a QVariantMap with a (key, value) pair of the form + (propertyName, propertyValue.toVariant()) for each property, + using QScriptValueIterator to iterate over the object's + properties. + \row \o QObjectList \o If the QScriptValue is an array, the result + is a QObjectList constructed from the result of + QScriptValue::toQObject() for each array element; otherwise, + the result is an empty QObjectList. + \row \o QList<int> \o If the QScriptValue is an array, the result is + a QList<int> constructed from the result of + QScriptValue::toInt32() for each array element; otherwise, + the result is an empty QList<int>. + \endtable + + Additionally, QtScript will handle the following cases: + + \list + \i If the QScriptValue is a QObject and the target type name ends with + \c * (i.e., it is a pointer), the QObject pointer will be cast to the + target type with qobject_cast(). + \i If the QScriptValue is a QVariant and the target type name ends with + \c * (i.e., it is a pointer), and the \l{QVariant::userType()}{userType()} + of the QVariant is the type that the target type points to, the result + is a pointer to the QVariant's data. + \i If the QScriptValue is a QVariant and it can be converted to the + target type (according to QVariant::canConvert()), the QVariant will + be cast to the target type with qvariant_cast(). + \endlist + + \section2 Default Conversion from C++ to Qt Script + + The following table describes the default behavior when a QScriptValue is + constructed from a C++ type: + + \table 80% + \header \o C++ Type \o Default Construction + \row \o void \o QScriptEngine::undefinedValue() + \row \o bool \o QScriptValue(engine, value) + \row \o int \o QScriptValue(engine, value) + \row \o uint \o QScriptValue(engine, value) + \row \o float \o QScriptValue(engine, value) + \row \o double \o QScriptValue(engine, value) + \row \o short \o QScriptValue(engine, value) + \row \o ushort \o QScriptValue(engine, value) + \row \o char \o QScriptValue(engine, value) + \row \o uchar \o QScriptValue(engine, value) + \row \o QString \o QScriptValue(engine, value) + \row \o qlonglong \o QScriptValue(engine, qsreal(value)). Note that + the conversion may lead to loss of precision, since not all + 64-bit integers can be represented using the qsreal type. + \row \o qulonglong \o QScriptValue(engine, qsreal(value)). Note that + the conversion may lead to loss of precision, since not all + 64-bit unsigned integers can be represented using the qsreal + type. + \row \o QChar \o QScriptValue(this, value.unicode()) + \row \o QDateTime \o \l{QScriptEngine::newDate()}{QScriptEngine::newDate}(value) + \row \o QDate \o \l{QScriptEngine::newDate()}{QScriptEngine::newDate}(value) + \row \o QRegExp \o \l{QScriptEngine::newRegExp()}{QScriptEngine::newRegExp}(value) + \row \o QObject* \o \l{QScriptEngine::newQObject()}{QScriptEngine::newQObject}(value) + \row \o QWidget* \o \l{QScriptEngine::newQObject()}{QScriptEngine::newQObject}(value) + \row \o QVariant \o \l{QScriptEngine::newVariant()}{QScriptEngine::newVariant}(value) + \row \o QStringList \o A new script array (created with + QScriptEngine::newArray()), whose elements are created using + the QScriptValue(QScriptEngine *, QString) constructor for + each element of the list. + \row \o QVariantList \o A new script array (created with + QScriptEngine::newArray()), whose elements are created using + QScriptEngine::newVariant() for each element of the list. + \row \o QVariantMap \o A new script object (created with + QScriptEngine::newObject()), whose properties are initialized + according to the (key, value) pairs of the map. + \row \o QObjectList \o A new script array (created with + QScriptEngine::newArray()), whose elements are created using + QScriptEngine::newQObject() for each element of the list. + \row \o QList<int> \o A new script array (created with + QScriptEngine::newArray()), whose elements are created using + the QScriptValue(QScriptEngine *, int) constructor for each + element of the list. + \endtable + + Other types (including custom types) will be wrapped using + QScriptEngine::newVariant(). For null pointers of any type, the + result is QScriptEngine::nullValue(). + + \section1 How to Design and Implement Application Objects + + This section explains how to implement application objects and + provides the necessary technical background material. + + \section2 Making a C++ object available to Scripts Written in QtScript + + Making C++ classes and objects available to a scripting language is + not trivial because scripting languages tend to be more dynamic than + C++, and it must be possible to introspect objects (query information + such as function names, function signatures, properties, etc., at + run-time). Standard C++ does not provide features for this. + + We can achieve the functionality we want by extending C++, using + C++'s own facilities so our code is still standard C++. The Qt + meta-object system provides the necessary additional functionality. + It allows us to write using an extended C++ syntax, but converts this + into standard C++ using a small utility program called \l{moc} + (Meta-Object Compiler). Classes that wish to take advantage of the + meta-object facilities are either subclasses of QObject, or use the + \c{Q_OBJECT} macro. Qt has used this approach for many years and it has + proven to be solid and reliable. QtScript uses this meta-object + technology to provide scripters with dynamic access to C++ classes + and objects. + + To completely understand how to make C++ objects available to Qt + Script, some basic knowledge of the Qt meta-object system is very + helpful. We recommend that you read the \l{Qt Object Model}. The + information in this document and the documents it links to are very + useful for understanding how to implement application objects. + + However, this knowledge is not essential in the simplest cases. + To make an object available in QtScript, it must derive from + QObject. All classes which derive from QObject can be introspected + and can provide the information needed by the scripting engine at + run-time; e.g., class name, functions, signatures. Because we obtain + the information we need about classes dynamically at run-time, there + is no need to write wrappers for QObject derived classes. + + \section2 Making C++ Class Member Functions Available in QtScript + + The meta-object system also makes information about signals and slots + dynamically available at run-time. By default, for QObject subclasses, + only the signals and slots are automatically made available to scripts. + This is very convenient because, in practice, we normally only want to + make specially chosen functions available to scripters. When you create + a QObject subclass, make sure that the functions you want to expose to + QtScript are public slots. + + For example, the following class definition enables scripting only for + certain functions: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 19 + + In the example above, aNonScriptableFunction() is not declared as a + slot, so it will not be available in QtScript. The other three + functions will automatically be made available in QtScript because + they are declared in the \c{public slots} section of the class + definition. + + It is possible to make any function script-invokable by specifying + the \c{Q_INVOKABLE} modifier when declaring the function: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 20 + + Once declared with \c{Q_INVOKABLE}, the method can be invoked from + QtScript code just as if it were a slot. Although such a method is + not a slot, you can still specify it as the target function in a + call to \c{connect()} in script code; \c{connect()} accepts both + native and non-native functions as targets. + + \section2 Making C++ Class Properties Available in QtScript + + In the previous example, if we wanted to get or set a property using + QtScript we would have to write code like the following: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 21 + + Scripting languages often provide a property syntax to modify and + retrieve properties (in our case the enabled state) of an + object. Many script programmers would want to write the above code + like this: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 22 + + To make this possible, you must define properties in the C++ QObject + subclass. For example, the following \c MyObject class declaration + declares a boolean property called \c enabled, which uses the function + \c{setEnabled(bool)} as its setter function and \c{isEnabled()} as its + getter function: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 23 + + The only difference from the original code is the use of the macro + \c{Q_PROPERTY}, which takes the type and name of the property, and + the names of the setter and getter functions as arguments. + + If you don't want a property of your class to be accessible in + QtScript, you set the \c{SCRIPTABLE} attribute to \c false when + declaring the property; by default, the \c{SCRIPTABLE} attribute is + \c true. For example: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 24 + + \section2 Reacting to C++ Objects Signals in Scripts + + In the Qt object model, signals are used as a notification mechanism + between QObjects. This means one object can connect a signal to + another object's slot and, every time the signal is emitted, the slot + is called. This connection is established using the QObject::connect() + function. + + The signals and slots mechanism is also available to QtScript + programmers. The code to declare a signal in C++ is the same, + regardless of whether the signal will be connected to a slot in C++ + or in QtScript. + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 25 + + The only change we have made to the code in the previous section is + to declare a signals section with the relevant signal. Now, the + script writer can define a function and connect to the object like + this: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 26 + + \section2 Design of Application Objects + + The previous section described how to implement C++ objects which + can be used in QtScript. Application objects are the same kind of + objects, and they make your application's functionality available to + QtScript scripters. Since the C++ application is already written + in Qt, many objects are already QObjects. The easiest approach would + be to simply add all these QObjects as application objects to the + scripting engine. For small applications this might be sufficient, + but for larger applications this is probably not the right + approach. The problem is that this method reveals too much of the + internal API and gives script programmers access to application + internals which should not be exposed. + + Generally, the best way of making application functionality available + to scripters is to code some QObjects which define the applications + public API using signals, slots, and properties. This gives you + complete control of the functionality made available by the + application. The implementations of these objects simply call the + functions in the application which do the real work. So, instead of + making all your QObjects available to the scripting engine, just add + the wrapper QObjects. + + \section3 Returning QObject Pointers + + If you have a slot that returns a QObject pointer, you should note + that, by default, Qt Script only handles conversion of the types + QObject* and QWidget*. This means that if your slot is declared + with a signature like "MyObject* getMyObject()", QtScript doesn't + automatically know that MyObject* should be handled in the same way + as QObject* and QWidget*. The simplest way to solve this is to only + use QObject* and QWidget* in the method signatures of your scripting + interface. + + Alternatively, you can register conversion functions for your custom + type with the qScriptRegisterMetaType() function. In this way, you + can preserve the precise typing in your C++ declarations, while + still allowing pointers to your custom objects to flow seamlessly + between C++ and scripts. Example: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 43 + + \section1 Function Objects and Native Functions + + In Qt Script, functions are first-class values; they are objects that + can have properties of their own, just like any other type of + object. They can be stored in variables and passed as arguments to + other functions. Knowing how function calls in Qt Script behave is + useful when you want to define and use your own script functions. + This section discusses this matter, and also explains how you can + implement native functions; that is, Qt Script functions written in + C++, as opposed to functions written in the scripting language + itself. Even if you will be relying mostly on the dynamic QObject + binding that Qt Script provides, knowing about these powerful + concepts and techniques is important to understand what's actually + going on when script functions are executed. + + \section2 Calling a Qt Script Function from C++ + + Calling a Qt Script function from C++ is achieved with the + QScriptValue::call() function. A typical scenario is that you evaluate a + script that defines a function, and at some point you want to call that + function from C++, perhaps passing it some arguments, and then handle the + result. The following script defines a Qt Script object that has a + toKelvin() function: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 90 + + The toKelvin() function takes a temperature in Kelvin as argument, and + returns the temperature converted to Celsius. The following snippet shows + how the toKelvin() function might be obtained and called from C++: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 91 + + If a script defines a global function, you can access the function as a + property of QScriptEngine::globalObject(). For example, the following script + defines a global function add(): + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 56 + + C++ code might call the add() function as follows: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 92 + + As already mentioned, functions are just values in Qt Script; a function by + itself is not "tied to" a particular object. This is why you have to specify + a \c{this} object (the first argument to QScriptValue::call()) that the + function should be applied to. + + If the function is supposed to act as a method (i.e. it can only be applied + to a certain class of objects), it is up to the function itself to check + that it is being called with a compatible \c{this} object. + + Passing an invalid QScriptValue as the \c{this} argument to + QScriptValue::call() indicates that the Global Object should be used as the + \c{this} object; in other words, that the function should be invoked as a + global function. + + \section2 The \c this Object + + When a Qt Script function is invoked from a script, the \e{way} in which it + is invoked determines the \c this object when the function body is executed, + as the following script example illustrates: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 49 + + An important thing to note is that in Qt Script, unlike C++ and Java, the + \c this object is not part of the execution scope. This means that + member functions (i.e., functions that operate on \c this) must always + use the \c this keyword to access the object's properties. For example, + the following script probably doesn't do what you want: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 50 + + You will get a reference error saying that 'a is not defined' or, worse, + two totally unrelated global variables \c a and \c b will be used to + perform the computation, if they exist. Instead, the script should look + like this: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 51 + + Accidentally omitting the \c this keyword is a typical source of + error for programmers who are used to the scoping rules of C++ and Java. + + \section2 Wrapping a Native Function + + Qt Script provides QScriptEngine::newFunction() as a way of wrapping a + C++ function pointer; this enables you to implement a function in + C++ and add it to the script environment, so that scripts can invoke + your function as if it were a "normal" script function. Here is how the + previous \c{getProperty()} function can be written in C++: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 52 + + Call QScriptEngine::newFunction() to wrap the function. This will + produce a special type of function object that carries a pointer to + the C++ function internally. Once the resulting wrapper has been + added to the scripting environment (e.g., by setting it as a property + of the Global Object), scripts can call the function without having + to know nor care that it is, in fact, a native function. + + Note that the name of the C++ function doesn't matter in the + scripting sense; the name by which the function is invoked by + scripts depends only on what you call the script object property + in which you store the function wrapper. + + It is currently not possible to wrap member functions; i.e., methods + of a C++ class that require a \c this object. + + \section2 The QScriptContext Object + + A QScriptContext holds all the state associated with a particular + invocation of your function. Through the QScriptContext, you can: + \list + \i Get the arguments that were passed to the function. + \i Get the \c this object. + \i Find out whether the function was called with the \c new operator + (the significance of this will be explained later). + \i Throw a script error. + \i Get the function object that's being invoked. + \i Get the activation object (the object used to hold local variables). + \endlist + + The following sections explain how to make use of this + functionality. + + \section2 Processing Function Arguments + + Two things are worth noting about function arguments: + + \list 1 + \o Any script function \mdash including native functions \mdash can + be invoked with any number of arguments. This means that it is up to + the function itself to check the argument count if necessary, and act + accordingly (e.g., throw an error if the number of arguments is + too large, or prepare a default value if the number is too small). + \o A value of any type can be supplied as an argument to any + function. This means that it is up to you to check the type of the + arguments if necessary, and act accordingly (e.g., throw an error + if an argument is not an object of a certain type). + \endlist + + In summary: Qt Script does not automatically enforce any constraints on the + number or type of arguments involved in a function call. + + \section3 Formal Parameters and the Arguments Object + + A native Qt Script function is analogous to a script function that defines no + formal parameters and only uses the built-in \c arguments variable to + process its arguments. To see this, let's first consider how a + script would normally define an \c{add()} function that takes two + arguments, adds them together and returns the result: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 56 + + When a script function is defined with formal parameters, their + names can be viewed as mere aliases of properties of the \c + arguments object; for example, in the \c{add(a, b)} definition's + function body, \c a and \c arguments[0] refer to the same + variable. This means that the \c{add()} function can equivalently be + written like this: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 57 + + This latter form closely matches what a native implementation + typically looks like: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 58 + + \section3 Checking the Number of Arguments + + Again, remember that the presence (or lack) of formal parameter + names in a function definition does not affect how the function + may be invoked; \c{add(1, 2, 3)} is allowed by the engine, as is + \c{add(42)}. In the case of the \c {add()} function, the function + really needs two arguments in order to do something useful. This + can be expressed by the script definition as follows: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 59 + + This would result in an error being thrown if a script invokes + \c{add()} with anything other than two arguments. The native + function can be modified to perform the same check: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 62 + + \section3 Checking the Types of Arguments + + In addition to expecting a certain number of arguments, a function might + expect that those arguments are of certain types (e.g., that the first + argument is a number and that the second is a string). Such a function + should explicitly check the type of arguments and/or perform a conversion, + or throw an error if the type of an argument is incompatible. + + As it is, the native implementation of \c{add()} shown above doesn't + have the exact same semantics as the script counterpart; this is + because the behavior of the Qt Script \c{+} operator depends on the + types of its operands (for example, if one of the operands is a string, + string concatenation is performed). To give the script function + stricter semantics (namely, that it should only add numeric + operands), the argument types can be tested: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 60 + + Then an invocation like \c{add("foo", new Array())} will + cause an error to be thrown. + + The C++ version can call QScriptValue::isNumber() to perform similar + tests: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 63 + + A less strict script implementation might settle for performing an + explicit to-number conversion before applying the \c{+} operator: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 61 + + In a native implementation, this is equivalent to calling + QScriptValue::toNumber() without performing any type test first, + since QScriptValue::toNumber() will automatically perform a type + conversion if necessary. + + To check if an argument is of a certain object type (class), + scripts can use the \c instanceof operator (e.g., \c{"arguments[0] + instanceof Array"} evaluates to true if the first argument is an + Array object); native functions can call QScriptValue::instanceOf(). + + To check if an argument is of a custom C++ type, you typically use + qscriptvalue_cast() and check if the result is valid. For object types, + this means casting to a pointer and checking if it is non-zero; for + value types, the class should have an \c{isNull()}, \c{isValid()} + or similar method. Alternatively, since most custom types are + transported in \l{QVariant}s, you can check if the script value is a + QVariant using QScriptValue::isVariant(), and then check if the + QVariant can be converted to your type using QVariant::canConvert(). + + \section3 Functions with Variable Numbers of Arguments + + Because of the presence of the built-in \c arguments object, + implementing functions that take a variable number of arguments + is simple. In fact, as we have seen, in the technical sense \e{all} + Qt Script functions can be seen as variable-argument functions). + As an example, consider a concat() function that takes an arbitrary + number of arguments, converts the arguments to their string + representation and concatenates the results; for example, + \c{concat("Qt", " ", "Script ", 101)} would return "Qt Script 101". + A script definition of \c{concat()} might look like this: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 64 + + Here is an equivalent native implementation: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 65 + + A second use case for a variable number of arguments is to implement + optional arguments. Here's how a script definition typically does + it: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 66 + + And here's the native equivalent: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 67 + + A third use case for a variable number of arguments is to simulate + C++ overloads. This involves checking the number of arguments and/or + their type at the beginning of the function body (as already shown), + and acting accordingly. It might be worth thinking twice before + doing this, and instead favor unique function names; e.g., having + separate \c{processNumber(number)} and \c{processString(string)} + functions rather than a generic \c{process(anything)} function. + On the caller side, this makes it harder for scripts to accidentally + call the wrong overload (since they don't know or don't comprehend + your custom sophisticated overloading resolution rules), and on the + callee side, you avoid the need for potentially complex (read: + error-prone) checks to resolve ambiguity. + + \section3 Accessing the Arguments Object + + Most native functions use the QScriptContext::argument() function to + access function arguments. However, it is also possible to access + the built-in \c arguments object itself (the one referred to by the + \c arguments variable in script code), by calling the + QScriptContext::argumentsObject() function. This has three principal + applications: + + \list + \o The \c arguments object can be used to easily forward a function + call to another function. In script code, this is what it + typically looks like: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 68 + + For example, \c{foo(10, 20, 30)} would result in the \c{foo()} function + executing the equivalent of \c{bar(10, 20, 30)}. This is useful if + you want to perform some special pre- or post-processing when + calling a function (e.g., to log the call to \c{bar()} without having + to modify the \c{bar()} function itself, like the above example), or if + you want to call a "base implementation" from a prototype + function that has the exact same "signature". In C++, the forwarding + function might look like this: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 69 + + \o The arguments object can serve as input to a QScriptValueIterator, + providing a generic way to iterate over the arguments. A debugger + might use this to display the arguments object in a general purpose + "Qt Script Object Explorer", for example. + + \o The arguments object can be serialized (e.g., with JSON) and transferred + to another entity (e.g., a script engine running in another thread), + where the object can be deserialized and passed as argument to + another script function. + \endlist + + \section2 Constructor Functions + + Some script functions are constructors; they are expected to initialize + new objects. The following snippet is a small example: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 75 + + There is nothing special about constructor functions. In fact, any + script function can act as a constructor function (i.e., any function + can serve as the operand to \c{new}). Some functions behave differently + depending on whether they are called as part of a \c{new} expression + or not; for example, the expression \c{new Number(1)} will create a + Number object, whereas \c{Number("123")} will perform a type + conversion. Other functions, like \c{Array()}, will always create + and initialize a new object (e.g., \c{new Array()} and \c{Array()} have + the same effect). + + A native Qt Script function can call the + QScriptContext::isCalledAsConstructor() function to determine if it + is being called as a constructor or as a regular function. When a + function is called as a constructor (i.e., it is the operand in a + \c{new} expression), this has two important implications: + + \list + \i The \c this object, QScriptContext::thisObject(), contains + the new object to be initialized; the engine creates this + new object automatically before invoking your function. This means + that your native constructor function normally doesn't have to (and + shouldn't) create a new object when it is called as a + constructor, since the engine has already prepared a new + object. Instead your function should operate on the supplied + \c this object. + \i The constructor function should return an undefined value, + QScriptEngine::undefinedValue(), to tell the engine that the + \c this object should be the final result of the \c new + operator. Alternatively, the function can return the \c this + object itself. + \endlist + + When QScriptContext::isCalledAsConstructor() returns false, how your + constructor handles this case depends on what behavior you desire. + If, like the built-in \c{Number()} function, a plain function call should + perform a type conversion of its argument, then you perform the conversion + and return the result. If, on the other hand, you want your constructor + to behave \e{as if it was called as a constructor} (with + \c{new}), you have to explicitly create a new object (that is, + ignore the \c this object), initialize that object, and return it. + + The following example implements a constructor function that always + creates and initializes a new object: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 76 + + Given this constructor, scripts would be able to use either the + expression \c{new Person("Bob")} or \c{Person("Bob")} to create a + new \c{Person} object; both behave in the same way. + + There is no equivalent way for a function defined in script + code to determine whether or not it was invoked as a constructor. + + Note that, even though it is not considered good practice, there is + nothing that stops you from choosing to ignore the default + constructed (\c this) object when your function is called as a + constructor and creating your own object anyway; simply have the + constructor return that object. The object will "override" the + default object that the engine constructed (i.e., the default + object will simply be discarded internally). + + \section2 Associating Data with a Function + + Even if a function is global \mdash i.e., not associated with any particular + (type of) object \mdash you might still want to associate some data with it, + so that it becomes self-contained; for example, the function could have + a pointer to some C++ resource that it needs to access. If your application + only uses a single script engine, or the same C++ resource can/should be + shared among all script engines, you can simply use a static C++ variable + and access it from within the native Qt Script function. + + In the case where a static C++ variable or singleton class is + not appropriate, you can call QScriptValue::setProperty() on the + function object, but be aware that those properties will also be + accessible to script code. The alternative is to use QScriptValue::setData(); + this data is not script-accessible. The implementation can access this + internal data through the QScriptContext::callee() function, which + returns the function object being invoked. The following example + shows how this might be used: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 55 + + \section2 Native Functions as Arguments to Functions + + As previously mentioned, a function object can be passed as argument + to another function; this is also true for native functions, + naturally. As an example, here's a native comparison function + that compares its two arguments numerically: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 53 + + The above function can be passed as argument to the standard + \c{Array.prototype.sort} function to sort an array numerically, + as the following C++ code illustrates: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 54 + + Note that, in this case, we are truly treating the native function + object as a value \mdash i.e., we don't store it as a property of the + scripting environment \mdash we simply pass it on as an "anonymous" + argument to another script function and then forget about it. + + \section2 The Activation Object + + Every Qt Script function invocation has an \e{activation object} + associated with it; this object is accessible through the + QScriptContext::activationObject() function. The activation object + is a script object whose properties are the local variables + associated with the invocation (including the arguments for which + the script function has a corresponding formal parameter name). + Thus, getting, modifying, creating and deleting local variables + from C++ is done using the regular QScriptValue::property() and + QScriptValue::setProperty() functions. The activation object itself + is not directly accessible from script code (but it is implicitly + accessed whenever a local variable is read from or written to). + + For C++ code, there are two principal applications of the + activation object: + + \list + \i The activation object provides a standard way to traverse the + variables associated with a function call, by using it as the input + to QScriptValueIterator. This is useful for debugging purposes. + + \i The activation object can be used to prepare local variables + that should be available when a script is evaluated inline; this + can be viewed as a way of passing arguments to the script + itself. This technique is typically used in conjunction with + QScriptEngine::pushContext(), as in the following example: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 77 + + We create a temporary execution context, create a local variable + for it, evaluate the script, and finally restore the old context. + \endlist + + \section2 Property Getters and Setters + + A script object property can be defined in terms of a getter/setter + function, similar to how a Qt C++ property has read and write + functions associated with it. This makes it possible for a script to + use expressions like \c{object.x} instead of \c{object.getX()}; the + getter/setter function for \c{x} will implicitly be invoked + whenever the property is accessed. To scripts, the property looks + and behaves just like a regular object property. + + A single Qt Script function can act as both getter and setter for + a property. When it is called as a getter, the argument count is 0. + When it is called as a setter, the argument count is 1; the argument + is the new value of the property. In the following example, we + define a native combined getter/setter that transforms the value + slightly: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 78 + + The example uses the internal data of the object to store and + retrieve the transformed value. Alternatively, the property + could be stored in another, "hidden" property of the object itself + (e.g., \c{__x__}). A native function is free to implement whatever + storage scheme it wants, as long as the external behavior of the + property itself is consistent (e.g., that scripts should not be able + to distinguish it from a regular property). + + The following C++ code shows how an object property can be defined + in terms of the native getter/setter: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 79 + + When the property is accessed, like in the following script, the + getter/setter does its job behind the scenes: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 80 + + \note It is important that the setter function, not just the getter, + returns the value of the property; i.e., the setter should \e{not} + return QScriptValue::UndefinedValue. This is because the result of + the property assignment is the value returned by the setter, and + not the right-hand side expression. Also note that you normally + should not attempt to read the same property that the getter modifies + within the getter itself, since this will cause the getter to be + called recursively. + + You can remove a property getter/setter by calling + QScriptValue::setProperty(), passing an invalid QScriptValue + as the getter/setter. Remember to specify the + QScriptValue::PropertyGetter/QScriptValue::PropertySetter flag(s), + otherwise the only thing that will happen is that the setter will be + invoked with an invalid QScriptValue as its argument! + + Property getters and setters can be defined and installed by script + code as well, as in the following example: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 81 + + Getters and setters can only be used to implement "a priori + properties"; i.e., the technique can't be used to react to an access + to a property that the object doesn't already have. To gain total + control of property access in this way, you need to subclass + QScriptClass. + + \section1 Making Use of Prototype-Based Inheritance + + In ECMAScript, inheritance is based on the concept of \e{shared + prototype objects}; this is quite different from the class-based + inheritance familiar to C++ programmers. With QtScript, you can + associate a custom prototype object with a C++ type using + QScriptEngine::setDefaultPrototype(); this is the key to providing + a script interface to that type. Since the QtScript module is built + on top of Qt's meta-type system, this can be done for any C++ type. + + You might be wondering when exactly you would need to use this + functionality in your application; isn't the automatic binding + provided by QScriptEngine::newQObject() enough? No, not under all + circumstances. + Firstly, not every C++ type is derived from QObject; types that + are not QObjects cannot be introspected through Qt's meta-object + system (they do not have properties, signals and slots). Secondly, + even if a type is QObject-derived, the functionality you want to + expose to scripts might not all be available, since it is unusual to + define every function to be a slot (and it's not always + possible/desirable to change the C++ API to make it so). + + It is perfectly possible to solve this problem by using "conventional" + C++ techniques. For instance, the QRect class could effectively be + made scriptable by creating a QObject-based C++ wrapper class with + \c{x}, \c{y}, \c{width} properties and so on, which forwarded property + access and function calls to the wrapped value. However, as we shall + see, by taking advantage of the ECMAScript object model and combining + it with Qt's meta-object system, we can arrive at a solution that is + more elegant, consistent and lightweight, supported by a small API. + + This section explains the underlying concepts of prototype-based + inheritance. Once these concepts are understood, the associated + practices can be applied throughout the QtScript API in order to + create well-behaved, consistent bindings to C++ that will fit nicely + into the ECMAScript universe. + + When experimenting with QtScript objects and inheritance, it can be + helpful to use the interactive interpreter included with the + \l{Qt Script Examples}, located in \c{examples/script/qscript}. + + \section2 Prototype Objects and Shared Properties + + The purpose of a QtScript \e{prototype object} is to define + behavior that should be shared by a set of other QtScript + objects. We say that objects which share the same prototype object + belong to the same \e{class} (again, on the technical side this + should not to be confused with the class constructs of languages + like C++ and Java; ECMAScript has no such construct). + + The basic prototype-based inheritance mechanism works as follows: Each + QtScript object has an internal link to another object, its + \e{prototype}. When a property is looked up in an object, and the + object itself does not have the property, the property is looked up + in the prototype object instead; if the prototype has the property, + then that property is returned. Otherwise, the property is looked up + in the prototype of the prototype object, and so on; this chain of + objects constitutes a \e{prototype chain}. The chain of prototype + objects is followed until the property is found or the end of the + chain is reached. + + For example, when you create a new object by the expression \c{new + Object()}, the resulting object will have as its prototype the + standard \c{Object} prototype, \c{Object.prototype}; through this + prototype relation, the new object inherits a set of properties, + including the \c{hasOwnProperty()} function and \c{toString()} + function: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 27 + + The \c{toString()} function itself is not defined in \c{o} (since we + did not assign anything to \c{o.toString}), so instead the + \c{toString()} function in the standard \c{Object} prototype is + called, which returns a highly generic string representation of + \c{o} ("[object Object]"). + + Note that the properties of the prototype object are not \e{copied} to + the new object; only a \e{link} from the new object to the prototype + object is maintained. This means that changes done to the prototype + object will immediately be reflected in the behavior of all objects + that have the modified object as their prototype. + + \section2 Defining Classes in a Prototype-Based Universe + + In QtScript, a class is not defined explicitly; there is no + \c{class} keyword. Instead, you define a new class in two steps: + + \list 1 + \i Define a \e{constructor function} that will initialize new objects. + \i Set up a \e{prototype object} that defines the class interface, and + assign this object to the public \c{prototype} property of the + constructor function. + \endlist + + With this arrangement, the constructor's public \c{prototype} + property will automatically be set as the prototype of objects created + by applying the \c{new} operator to your constructor function; + e.g., the prototype of an object created by \c{new Foo()} will be the + value of \c{Foo.prototype}. + + Functions that don't operate on the \c this object ("static" methods) + are typically stored as properties of the constructor function, not + as properties of the prototype object. The same is true for + constants, such as enum values. + + The following code defines a simple constructor function for a class + called \c{Person}: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 28 + + Next, you want to set up \c{Person.prototype} as your prototype + object; i.e., define the interface that should be common to all + \c{Person} objects. QtScript automatically creates a default + prototype object (by the expression \c{new Object()}) for every + script function; you can add properties to this object, or you can + assign your own custom object. (Generally speaking, any QtScript + object can act as prototype for any other object.) + + Here's an example of how you might want to override the + \c{toString()} function that \c{Person.prototype} inherits from + \c{Object.prototype}, to give your \c{Person} objects a more + appropriate string representation: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 29 + + This resembles the process of reimplementing a virtual function + in C++. Henceforth, when the property named \c{toString} is + looked up in a \c{Person} object, it will be resolved in + \c{Person.prototype}, not in \c{Object.prototype} as before: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 30 + + There are also some other interesting things we can learn about a + \c{Person} object: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 31 + + The \c{hasOwnProperty()} function is not inherited from + \c{Person.prototype}, but rather from \c{Object.prototype}, which is + the prototype of \c{Person.prototype} itself; i.e., the prototype + chain of \c{Person} objects is \c{Person.prototype} followed by + \c{Object.prototype}. This prototype chain establishes a \e{class + hierarchy}, as demonstrated by applying the \c{instanceof} operator; + \c{instanceof} checks if the value of the public \c{prototype} + property of the constructor function on the right-hand side is + reached by following the prototype chain of the object on the + left-hand side. + + When defining subclasses, there's a general pattern you can use. The + following example shows how one can create a subclass of \c{Person} + called \c{Employee}: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 32 + + Again, you can use the \c{instanceof} to verify that the + class relationship between \c{Employee} and \c{Person} has been + correctly established: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 33 + + This shows that the prototype chain of \c{Employee} objects is the + same as that of \c{Person} objects, but with \c{Employee.prototype} + added to the front of the chain. + + \section2 Prototype-Based Programming with the QtScript C++ API + + You can use QScriptEngine::newFunction() to wrap + native functions. When implementing a constructor function, + you also pass the prototype object as an argument to + QScriptEngine::newFunction(). + You can call QScriptValue::construct() to call a constructor + function, and you can use QScriptValue::call() from within a + native constructor function if you need to call a base class + constructor. + + The QScriptable class provides a convenient way to implement a + prototype object in terms of C++ slots and properties. Take a look + at the \l{Default Prototypes Example} to see how this is done. + Alternatively, the prototype functionality can be implemented in + terms of standalone native functions that you wrap with + QScriptEngine::newFunction() and set as properties of your prototype + object by calling QScriptValue::setProperty(). + + In the implementation of your prototype functions, you use + QScriptable::thisObject() (or QScriptContext::thisObject()) to + obtain a reference to the QScriptValue being operated upon; then you + call qscriptvalue_cast() to cast it to your C++ type, and perform + the relevant operations using the usual C++ API for the type. + + You associate a prototype object with a C++ type by calling + QScriptEngine::setDefaultPrototype(). Once this mapping is + established, QtScript will automatically assign the correct + prototype when a value of such a type is wrapped in a QScriptValue; + either when you explicitly call QScriptEngine::toScriptValue(), or + when a value of such a type is returned from a C++ slot and + internally passed back to script code by the engine. This means you + \e{don't} have to implement wrapper classes if you use this + approach. + + As an example, let's consider how the \c{Person} class from the + preceding section can be implemented in terms of the Qt Script API. + We begin with the native constructor function: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 34 + + Here's the native equivalent of the \c{Person.prototype.toString} + function we saw before: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 35 + + The \c{Person} class can then be initialized as follows: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 36 + + The implementation of the \c{Employee} subclass is similar. We + use QScriptValue::call() to call the super-class (Person) constructor: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 37 + + The \c{Employee} class can then be initialized as follows: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 38 + + When implementing the prototype object of a class, you may want to use + the QScriptable class, as it enables you to define the API of your + script class in terms of Qt properties, signals and slots, and + automatically handles value conversion between the Qt Script and C++ + side. + + \section2 Implementing Prototype Objects for Value-based Types + + When implementing a prototype object for a value-based type -- + e.g. QPointF -- the same general technique applies; you populate + a prototype object with functionality that should be shared + among instances. You then associate the prototype object with + the type by calling QScriptEngine::setDefaultPrototype(). This + ensures that when e.g. a value of the relevant type is returned + from a slot back to the script, the prototype link of the script + value will be initialized correctly. + + When values of the custom type are stored in QVariants -- which Qt + Script does by default --, qscriptvalue_cast() enables you to safely + cast the script value to a pointer to the C++ type. This makes it + easy to do type-checking, and, for prototype functions that should + modify the underlying C++ value, lets you modify the actual value + contained in the script value (and not a copy of it). + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 39 + + \section2 Implementing Constructors for Value-based Types + + You can implement a constructor function for a value-based type + by wrapping a native factory function. For example, the following + function implements a simple constructor for QPoint: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 44 + + In the above code we simplified things a bit, e.g. we didn't check + the argument count to decide which QPoint C++ constructor to use. + In your own constructors you have to do this type of resolution + yourself, i.e. by checking the number of arguments passed to the + native function, and/or by checking the type of the arguments and + converting the arguments to the desired type. If you detect a problem + with the arguments you may want to signal this by throwing a script + exception; see QScriptContext::throwError(). + + \section2 Managing Non-QObject-based Objects + + For value-based types (e.g. QPoint), the C++ object will be destroyed when + the Qt Script object is garbage-collected, so managing the memory of the C++ + object is not an issue. For QObjects, Qt Script provides several + alternatives for managing the underlying C++ object's lifetime; see the + \l{Controlling QObject Ownership} section. However, for polymorphic types + that don't inherit from QObject, and when you can't (or won't) wrap the type + in a QObject, you have to manage the lifetime of the C++ object yourself. + + A behavior that's often reasonable when a Qt Script object wraps a C++ + object, is that the C++ object is deleted when the Qt Script object is + garbage-collected; this is typically the case when the objects can be + constructed by scripts, as opposed to the application providing the scripts + with pre-made "environment" objects. A way of making the lifetime of the C++ + object follow the lifetime of the Qt Script object is by using a shared + pointer class, such as QSharedPointer, to hold a pointer to your object; + when the Qt Script object containing the QSharedPointer is + garbage-collected, the underlying C++ object will be deleted if there are no + other references to the object. + + The following snippet shows a constructor function that constructs + QXmlStreamReader objects that are stored using QSharedPointer: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 93 + + Prototype functions can use qscriptvalue_cast() to cast the \c this object + to the proper type: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 94 + + The prototype and constructor objects are set up in the usual way: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 95 + + Scripts can now construct QXmlStreamReader objects by calling the \c + XmlStreamReader constructor, and when the Qt Script object is + garbage-collected (or the script engine is destroyed), the QXmlStreamReader + object is destroyed as well. + + \section1 Defining Custom Script Classes with QScriptClass + + There are cases where neither the dynamic QObject binding provided + by QScriptEngine::newQObject() or the manual binding provided by + QScriptEngine::newFunction() is sufficient. For example, you might + want to implement a dynamic script proxy to an underlying object; + or you might want to implement an array-like class (i.e. that gives + special treatment to properties that are valid array indexes, and + to the property "length"). In such cases, you can subclass + QScriptClass to achieve the desired behavior. + + QScriptClass allows you to handle all property access for a + (class of) script object through virtual get/set property functions. + Iteration of custom properties is also supported through the + QScriptClassPropertyIterator class; this means you can advertise + properties to be reported by for-in script statements and + QScriptValueIterator. + + \section1 Error Handling and Debugging Facilities + + Syntax errors in scripts will be reported as soon as a script is + evaluated; QScriptEngine::evaluate() will return a SyntaxError object + that you can convert to a string to get a description of the error. + + The QScriptEngine::uncaughtExceptionBacktrace() function gives you + a human-readable backtrace of the last uncaught exception. In order + to get useful filename information in backtraces, you should pass + proper filenames to QScriptEngine::evaluate() when evaluating your + scripts. + + Often an exception doesn't happen at the time the script is evaluated, + but at a later time when a function defined by the script is actually + executed. For C++ signal handlers, this is tricky; consider the case + where the clicked() signal of a button is connected to a script function, + and that script function causes a script exception when it is handling + the signal. Where is that script exception propagated to? + + The solution is to connect to the QScriptEngine::signalHandlerException() + signal; this will give you notification when a signal handler causes + an exception, so that you can find out what happened and/or recover + from it. + + In Qt 4.4 the QScriptEngineAgent class was introduced. QScriptEngineAgent + provides an interface for reporting low-level "events" in a script engine, + such as when a function is entered or when a new script statement is + reached. By subclassing QScriptEngineAgent you can be notified of these + events and perform some action, if you want. QScriptEngineAgent itself + doesn't provide any debugging-specific functionality (e.g. setting + breakpoints), but it is the basis of tools that do. + + The QScriptEngineDebugger class introduced in Qt 4.5 provides a + \l{Qt Script Debugger Manual}{Qt Script debugger} that can be embedded + into your application. + + \section2 Redefining print() + + Qt Script provides a built-in print() function that can be useful for + simple debugging purposes. The built-in print() function writes to + standard output. You can redefine the print() function (or add your + own function, e.g. debug() or log()) that redirects the text to + somewhere else. The following code shows a custom print() that adds + text to a QPlainTextEdit. + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 45 + + The following code shows how the custom print() function may be + initialized and used. + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 46 + + A pointer to the QPlainTextEdit is stored as an internal property + of the script function itself, so that it can be retrieved when + the function is called. + + \section1 Using QtScript Extensions + + The QScriptEngine::importExtension() function can be used to load plugins + into a script engine. Plugins typically add some extra functionality to + the engine; for example, a plugin might add full bindings for the Qt + Arthur painting API, so that those classes may be used from Qt Script + scripts. There are currently no script plugins shipped with Qt. + + If you are implementing some Qt Script functionality that you want other + Qt application developers to be able to use, \l{Creating QtScript Extensions} + {developing an extension} (e.g. by subclassing QScriptExtensionPlugin) is + worth looking into. + + \section1 Internationalization + + Since Qt 4.5, Qt Script supports internationalization of scripts by building + on the C++ internationalization functionality (see \l{Internationalization + with Qt}). + + \section2 Use qsTr() for All Literal Text + + Wherever your script uses "quoted text" for text that will be presented to + the user, ensure that it is processed by the QCoreApplication::translate() + function. Essentially all that is necessary to achieve this is to use + the qsTr() script function. Example: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 82 + + This accounts for 99% of the user-visible strings you're likely to write. + + The qsTr() function uses the basename of the script's filename (see + QFileInfo::baseName()) as the translation context; if the filename is not + unique in your project, you should use the qsTranslate() function and pass a + suitable context as the first argument. Example: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 83 + + If you need to have translatable text completely outside a function, there + are two functions to help: QT_TR_NOOP() and QT_TRANSLATE_NOOP(). They merely + mark the text for extraction by the \c lupdate utility described below. At + runtime, these functions simply return the text to translate unmodified. + + Example of QT_TR_NOOP(): + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 84 + + Example of QT_TRANSLATE_NOOP(): + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 85 + + \section2 Use String.prototype.arg() for Dynamic Text + + The String.prototype.arg() function (which is modeled after QString::arg()) + offers a simple means for substituting arguments: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 86 + + \section2 Produce Translations + + Once you are using qsTr() and/or qsTranslate() throughout your scripts, you + can start producing translations of the user-visible text in your program. + + The \l{Qt Linguist manual} provides further information about + Qt's translation tools, \e{Qt Linguist}, \c lupdate and \c + lrelease. + + Translation of Qt Script scripts is a three-step process: + + \list 1 + + \o Run \c lupdate to extract translatable text from the script source code + of the Qt application, resulting in a message file for translators (a TS + file). The utility recognizes qsTr(), qsTranslate() and the + \c{QT_TR*_NOOP()} functions described above and produces TS files + (usually one per language). + + \o Provide translations for the source texts in the TS file, using + \e{Qt Linguist}. Since TS files are in XML format, you can also + edit them by hand. + + \o Run \c lrelease to obtain a light-weight message file (a QM + file) from the TS file, suitable only for end use. Think of the TS + files as "source files", and QM files as "object files". The + translator edits the TS files, but the users of your application + only need the QM files. Both kinds of files are platform and + locale independent. + + \endlist + + Typically, you will repeat these steps for every release of your + application. The \c lupdate utility does its best to reuse the + translations from previous releases. + + When running \c lupdate, you must specify the location of the script(s), + and the name of the TS file to produce. Examples: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 87 + + will extract translatable text from \c myscript.qs and create the + translation file \c myscript_la.qs. + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 88 + + will extract translatable text from all files ending with \c{.qs} in the + \c scripts folder and create the translation file \c scripts_la.qs. + + Alternatively, you can create a separate qmake project file that sets up + the \c SOURCES and \c TRANSLATIONS variables appropriately; then run + \c lupdate with the project file as input. + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 89 + + When running \c lrelease, you must specify the name of the TS input + file; or, if you are using a qmake project file to manage script + translations, you specify the name of that file. \c lrelease will create + \c myscript_la.qm, the binary representation of the translation. + + \section2 Apply Translations + + In your application, you must use QTranslator::load() to load the + translation files appropriate for the user's language, and install them + using QCoreApplication::installTranslator(). Finally, you must call + QScriptEngine::installTranslatorFunctions() to make the script translation + functions (qsTr(), qsTranslate() and \c{QT_TR*_NOOP()}) available to scripts + that are subsequently evaluated by QScriptEngine::evaluate(). For scripts + that are using the qsTr() function, the proper filename must be passed as + second argument to QScriptEngine::evaluate(). + + \c linguist, \c lupdate and \c lrelease are installed in the \c bin + subdirectory of the base directory Qt is installed into. Click Help|Manual + in \e{Qt Linguist} to access the user's manual; it contains a tutorial + to get you started. + + See also the \l{Hello Script Example}. + + \section1 ECMAScript Compatibility + + QtScript implements all the built-in classes and functions defined + in ECMA-262. + + The Date parsing and string conversion functions are implemented using + QDateTime::fromString() and QDateTime::toString(), respectively. + + The RegExp class is a wrapper around QRegExp. The QRegExp semantics + do not precisely match the semantics for regular expressions defined + in ECMA-262. + + \section1 QtScript Extensions to ECMAScript + + \list + \i \c{__proto__} \br + The prototype of an object (QScriptValue::prototype()) + can be accessed through its \c{__proto__} property in script code. + This property has the QScriptValue::Undeletable flag set. + For example: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 40 + + \i \c{Object.prototype.__defineGetter__} \br + This function installs a + getter function for a property of an object. The first argument is + the property name, and the second is the function to call to get + the value of that property. When the function is invoked, the + \c this object will be the object whose property is accessed. + For example: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 41 + + \i \c{Object.prototype.__defineSetter__} \br + This function installs a + setter function for a property of an object. The first argument is + the property name, and the second is the function to call to set + the value of that property. When the function is invoked, the + \c this object will be the object whose property is accessed. + For example: + + \snippet doc/src/snippets/code/doc_src_qtscript.qdoc 42 + + \i \c{Function.prototype.connect} \br + This function connects + a signal to a slot. Usage of this function is described in + the section \l{Using Signals and Slots}. + + \i \c{Function.prototype.disconnect} \br + This function disconnects + a signal from a slot. Usage of this function is described in + the section \l{Using Signals and Slots}. + + \i \c{QObject.prototype.findChild} \br + This function is semantically equivalent to QObject::findChild(). + + \i \c{QObject.prototype.findChildren} \br + This function is semantically equivalent to QObject::findChildren(). + + \i \c{QObject.prototype.toString} \br + This function returns a default string representation of a QObject. + + \i \c{gc} \br + This function invokes the garbage collector. + + \i \c{Error.prototype.backtrace} \br + This function returns a human-readable backtrace, in the form of + an array of strings. + + \i Error objects have the following additional properties: + \list + \i \c{lineNumber}: The line number where the error occurred. + \i \c{fileName}: The file name where the error occurred (if a file name + was passed to QScriptEngine::evaluate()). + \i \c{stack}: An array of objects describing the stack. Each object has + the following properties: + \list + \i \c{functionName}: The function name, if available. + \i \c{fileName}: The file name, if available. + \i \c{lineNumber}: The line number, if available. + \endlist + \endlist + + \endlist + + */ |