/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the documentation of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:BSD$ ** You may use this file under the terms of the BSD license as follows: ** ** "Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are ** met: ** * Redistributions of source code must retain the above copyright ** notice, this list of conditions and the following disclaimer. ** * Redistributions in binary form must reproduce the above copyright ** notice, this list of conditions and the following disclaimer in ** the documentation and/or other materials provided with the ** distribution. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor ** the names of its contributors may be used to endorse or promote ** products derived from this software without specific prior written ** permission. ** ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ** $QT_END_LICENSE$ ** ****************************************************************************/ //! [0] #include //! [0] //! [1] QT += script //! [1] //! [2] function myInterestingScriptFunction() { ... } ... myQObject.somethingChanged.connect(myInterestingScriptFunction); //! [2] //! [3] myQObject.somethingChanged.connect(myOtherQObject.doSomething); //! [3] //! [4] myQObject.somethingChanged.disconnect(myInterestingFunction); myQObject.somethingChanged.disconnect(myOtherQObject.doSomething); //! [4] //! [5] var obj = { x: 123 }; var fun = function() { print(this.x); }; myQObject.somethingChanged.connect(obj, fun); //! [5] //! [6] myQObject.somethingChanged.disconnect(obj, fun); //! [6] //! [7] var obj = { x: 123, fun: function() { print(this.x); } }; myQObject.somethingChanged.connect(obj, "fun"); //! [7] //! [8] myQObject.somethingChanged.disconnect(obj, "fun"); //! [8] //! [9] try { myQObject.somethingChanged.connect(myQObject, "slotThatDoesntExist"); } catch (e) { print(e); } //! [9] //! [10] myQObject.somethingChanged("hello"); //! [10] //! [11] myQObject.myOverloadedSlot(10); // will call the int overload myQObject.myOverloadedSlot("10"); // will call the QString overload //! [11] //! [12] myQObject['myOverloadedSlot(int)']("10"); // call int overload; the argument is converted to an int myQObject['myOverloadedSlot(QString)'](10); // call QString overload; the argument is converted to a string //! [12] //! [13] Q_PROPERTY(bool enabled READ enabled WRITE setEnabled) //! [13] //! [14] myQObject.enabled = true; ... myQObject.enabled = !myQObject.enabled; //! [14] //! [15] myDialog.okButton //! [15] //! [16] myDialog.okButton.objectName = "cancelButton"; // from now on, myDialog.cancelButton references the button //! [16] //! [17] var okButton = myDialog.findChild("okButton"); if (okButton != null) { // do something with the OK button } var buttons = myDialog.findChildren(RegExp("button[0-9]+")); for (var i = 0; i < buttons.length; ++i) { // do something with buttons[i] } //! [17] //! [18] QScriptValue myQObjectConstructor(QScriptContext *context, QScriptEngine *engine) { // let the engine manage the new object's lifetime. return engine->newQObject(new MyQObject(), QScriptEngine::ScriptOwnership); } //! [18] //! [19] class MyObject : public QObject { Q_OBJECT public: MyObject( ... ); void aNonScriptableFunction(); public slots: // these functions (slots) will be available in QtScript void calculate( ... ); void setEnabled( bool enabled ); bool isEnabled() const; private: .... }; //! [19] //! [20] class MyObject : public QObject { Q_OBJECT public: Q_INVOKABLE void thisMethodIsInvokableInQtScript(); void thisMethodIsNotInvokableInQtScript(); ... }; //! [20] //! [21] var obj = new MyObject; obj.setEnabled( true ); print( "obj is enabled: " + obj.isEnabled() ); //! [21] //! [22] var obj = new MyObject; obj.enabled = true; print( "obj is enabled: " + obj.enabled ); //! [22] //! [23] class MyObject : public QObject { Q_OBJECT // define the enabled property Q_PROPERTY( bool enabled WRITE setEnabled READ isEnabled ) public: MyObject( ... ); void aNonScriptableFunction(); public slots: // these functions (slots) will be available in QtScript void calculate( ... ); void setEnabled( bool enabled ); bool isEnabled() const; private: .... }; //! [23] //! [24] Q_PROPERTY(int nonScriptableProperty READ foo WRITE bar SCRIPTABLE false) //! [24] //! [25] class MyObject : public QObject { Q_OBJECT // define the enabled property Q_PROPERTY( bool enabled WRITE setEnabled READ isEnabled ) public: MyObject( ... ); void aNonScriptableFunction(); public slots: // these functions (slots) will be available in QtScript void calculate( ... ); void setEnabled( bool enabled ); bool isEnabled() const; signals: // the signals void enabledChanged( bool newState ); private: .... }; //! [25] //! [26] function enabledChangedHandler( b ) { print( "state changed to: " + b ); } function init() { var obj = new MyObject(); // connect a script function to the signal obj["enabledChanged(bool)"].connect(enabledChangedHandler); obj.enabled = true; print( "obj is enabled: " + obj.enabled ); } //! [26] //! [27] var o = new Object(); o.foo = 123; print(o.hasOwnProperty('foo')); // true print(o.hasOwnProperty('bar')); // false print(o); // calls o.toString(), which returns "[object Object]" //! [27] //! [28] function Person(name) { this.name = name; } //! [28] //! [29] Person.prototype.toString = function() { return "Person(name: " + this.name + ")"; } //! [29] //! [30] var p1 = new Person("John Doe"); var p2 = new Person("G.I. Jane"); print(p1); // "Person(name: John Doe)" print(p2); // "Person(name: G.I. Jane)" //! [30] //! [31] print(p1.hasOwnProperty('name')); // 'name' is an instance variable, so this returns true print(p1.hasOwnProperty('toString')); // returns false; inherited from prototype print(p1 instanceof Person); // true print(p1 instanceof Object); // true //! [31] //! [32] function Employee(name, salary) { Person.call(this, name); // call base constructor this.salary = salary; } // set the prototype to be an instance of the base class Employee.prototype = new Person(); // initialize prototype Employee.prototype.toString = function() { ... } //! [32] //! [33] var e = new Employee("Johnny Bravo", 5000000); print(e instanceof Employee); // true print(e instanceof Person); // true print(e instanceof Object); // true print(e instanceof Array); // false //! [33] //! [34] QScriptValue Person_ctor(QScriptContext *context, QScriptEngine *engine) { QString name = context->argument(0).toString(); context->thisObject().setProperty("name", name); return engine->undefinedValue(); } //! [34] //! [35] QScriptValue Person_prototype_toString(QScriptContext *context, QScriptEngine *engine) { QString name = context->thisObject().property("name").toString(); QString result = QString::fromLatin1("Person(name: %0)").arg(name); return result; } //! [35] //! [36] QScriptEngine engine; QScriptValue ctor = engine.newFunction(Person_ctor); ctor.property("prototype").setProperty("toString", engine.newFunction(Person_prototype_toString)); QScriptValue global = engine.globalObject(); global.setProperty("Person", ctor); //! [36] //! [37] QScriptValue Employee_ctor(QScriptContext *context, QScriptEngine *engine) { QScriptValue super = context->callee().property("prototype").property("constructor"); super.call(context->thisObject(), QScriptValueList() << context->argument(0)); context->thisObject().setProperty("salary", context->argument(1)); return engine->undefinedValue(); } //! [37] //! [38] QScriptValue empCtor = engine.newFunction(Employee_ctor); empCtor.setProperty("prototype", global.property("Person").construct()); global.setProperty("Employee", empCtor); //! [38] //! [39] Q_DECLARE_METATYPE(QPointF) Q_DECLARE_METATYPE(QPointF*) QScriptValue QPointF_prototype_x(QScriptContext *context, QScriptEngine *engine) { // Since the point is not to be modified, it's OK to cast to a value here QPointF point = qscriptvalue_cast(context->thisObject()); return point.x(); } QScriptValue QPointF_prototype_setX(QScriptContext *context, QScriptEngine *engine) { // Cast to a pointer to be able to modify the underlying C++ value QPointF *point = qscriptvalue_cast(context->thisObject()); if (!point) return context->throwError(QScriptContext::TypeError, "QPointF.prototype.setX: this object is not a QPointF"); point->setX(context->argument(0).toNumber()); return engine->undefinedValue(); } //! [39] //! [40] var o = new Object(); (o.__proto__ === Object.prototype); // this evaluates to true //! [40] //! [41] var o = new Object(); o.__defineGetter__("x", function() { return 123; }); var y = o.x; // 123 //! [41] //! [42] var o = new Object(); o.__defineSetter__("x", function(v) { print("and the value is:", v); }); o.x = 123; // will print "and the value is: 123" //! [42] //! [43] class MyObject : public QObject { Q_OBJECT ... }; Q_DECLARE_METATYPE(MyObject*) QScriptValue myObjectToScriptValue(QScriptEngine *engine, MyObject* const &in) { return engine->newQObject(in); } void myObjectFromScriptValue(const QScriptValue &object, MyObject* &out) { out = qobject_cast(object.toQObject()); } ... qScriptRegisterMetaType(&engine, myObjectToScriptValue, myObjectFromScriptValue); //! [43] //! [44] QScriptValue QPoint_ctor(QScriptContext *context, QScriptEngine *engine) { int x = context->argument(0).toInt32(); int y = context->argument(1).toInt32(); return engine->toScriptValue(QPoint(x, y)); } ... engine.globalObject().setProperty("QPoint", engine.newFunction(QPoint_ctor)); //! [44] //! [45] QScriptValue myPrintFunction(QScriptContext *context, QScriptEngine *engine) { QString result; for (int i = 0; i < context->argumentCount(); ++i) { if (i > 0) result.append(" "); result.append(context->argument(i).toString()); } QScriptValue calleeData = context->callee().data(); QPlainTextEdit *edit = qobject_cast(calleeData.toQObject()); edit->appendPlainText(result); return engine->undefinedValue(); } //! [45] //! [46] int main(int argc, char **argv) { QApplication app(argc, argv); QScriptEngine eng; QPlainTextEdit edit; QScriptValue fun = eng.newFunction(myPrintFunction); fun.setData(eng.newQObject(&edit)); eng.globalObject().setProperty("print", fun); eng.evaluate("print('hello', 'world')"); edit.show(); return app.exec(); } //! [46] //! [47] QScriptEngine eng; QLineEdit *edit = new QLineEdit(...); QScriptValue handler = eng.evaluate("(function(text) { print('text was changed to', text); })"); qScriptConnect(edit, SIGNAL(textChanged(const QString &)), QScriptValue(), handler); //! [47] //! [48] QLineEdit *edit1 = new QLineEdit(...); QLineEdit *edit2 = new QLineEdit(...); QScriptValue handler = eng.evaluate("(function() { print('I am', this.name); })"); QScriptValue obj1 = eng.newObject(); obj1.setProperty("name", "the walrus"); QScriptValue obj2 = eng.newObject(); obj2.setProperty("name", "Sam"); qScriptConnect(edit1, SIGNAL(returnPressed()), obj1, handler); qScriptConnect(edit2, SIGNAL(returnPressed()), obj2, handler); //! [48] //! [49] var getProperty = function(name) { return this[name]; }; name = "Global Object"; // creates a global variable print(getProperty("name")); // "Global Object" var myObject = { name: 'My Object' }; print(getProperty.call(myObject, "name")); // "My Object" myObject.getProperty = getProperty; print(myObject.getProperty("name")); // "My Object" getProperty.name = "The getProperty() function"; getProperty.getProperty = getProperty; getProperty.getProperty("name"); // "The getProperty() function" //! [49] //! [50] var o = { a: 1, b: 2, sum: function() { return a + b; } }; print(o.sum()); // reference error, or sum of global variables a and b!! //! [50] //! [51] var o = { a: 1, b: 2, sum: function() { return this.a + this.b; } }; print(o.sum()); // 3 //! [51] //! [52] QScriptValue getProperty(QScriptContext *ctx, QScriptEngine *eng) { QString name = ctx->argument(0).toString(); return ctx->thisObject().property(name); } //! [52] //! [53] QScriptValue myCompare(QScriptContext *ctx, QScriptEngine *eng) { double first = ctx->argument(0).toNumber(); double second = ctx->argument(1).toNumber(); int result; if (first == second) result = 0; else if (first < second) result = -1; else result = 1; return result; } //! [53] //! [54] QScriptEngine eng; QScriptValue comparefn = eng.newFunction(myCompare); QScriptValue array = eng.evaluate("new Array(10, 5, 20, 15, 30)"); array.property("sort").call(array, QScriptValueList() << comparefn); // prints "5,10,15,20,30" qDebug() << array.toString(); //! [54] //! [55] QScriptValue rectifier(QScriptContext *ctx, QScriptEngine *eng) { QRectF magicRect = qscriptvalue_cast(ctx->callee().data()); QRectF sourceRect = qscriptvalue_cast(ctx->argument(0)); return eng->toScriptValue(sourceRect.intersected(magicRect)); } ... QScriptValue fun = eng.newFunction(rectifier); QRectF magicRect = QRectF(10, 20, 30, 40); fun.setData(eng.toScriptValue(magicRect)); eng.globalObject().setProperty("rectifier", fun); //! [55] //! [56] function add(a, b) { return a + b; } //! [56] //! [57] function add() { return arguments[0] + arguments[1]; } //! [57] //! [58] QScriptValue add(QScriptContext *ctx, QScriptEngine *eng) { double a = ctx->argument(0).toNumber(); double b = ctx->argument(1).toNumber(); return a + b; } //! [58] //! [59] function add() { if (arguments.length != 2) throw Error("add() takes exactly two arguments"); return arguments[0] + arguments[1]; } //! [59] //! [60] function add() { if (arguments.length != 2) throw Error("add() takes exactly two arguments"); if (typeof arguments[0] != "number") throw TypeError("add(): first argument is not a number"); if (typeof arguments[1] != "number") throw TypeError("add(): second argument is not a number"); return arguments[0] + arguments[1]; } //! [60] //! [61] function add() { if (arguments.length != 2) throw Error("add() takes exactly two arguments"); return Number(arguments[0]) + Number(arguments[1]); } //! [61] //! [62] QScriptValue add(QScriptContext *ctx, QScriptEngine *eng) { if (ctx->argumentCount() != 2) return ctx->throwError("add() takes exactly two arguments"); double a = ctx->argument(0).toNumber(); double b = ctx->argument(1).toNumber(); return a + b; } //! [62] //! [63] QScriptValue add(QScriptContext *ctx, QScriptEngine *eng) { if (ctx->argumentCount() != 2) return ctx->throwError("add() takes exactly two arguments"); if (!ctx->argument(0).isNumber()) return ctx->throwError(QScriptContext::TypeError, "add(): first argument is not a number"); if (!ctx->argument(1).isNumber()) return ctx->throwError(QScriptContext::TypeError, "add(): second argument is not a number"); double a = ctx->argument(0).toNumber(); double b = ctx->argument(1).toNumber(); return a + b; } //! [63] //! [64] function concat() { var result = ""; for (var i = 0; i < arguments.length; ++i) result += String(arguments[i]); return result; } //! [64] //! [65] QScriptValue concat(QScriptContext *ctx, QScriptEngine *eng) { QString result = ""; for (int i = 0; i < ctx->argumentCount(); ++i) result += ctx->argument(i).toString(); return result; } //! [65] //! [66] function sort(comparefn) { if (comparefn == undefined) comparefn = /* the built-in comparison function */; else if (typeof comparefn != "function") throw TypeError("sort(): argument must be a function"); ... } //! [66] //! [67] QScriptValue sort(QScriptContext *ctx, QScriptEngine *eng) { QScriptValue comparefn = ctx->argument(0); if (comparefn.isUndefined()) comparefn = /* the built-in comparison function */; else if (!comparefn.isFunction()) return ctx->throwError(QScriptContext::TypeError, "sort(): argument is not a function"); ... } //! [67] //! [68] function foo() { // Let bar() take care of this. print("calling bar() with " + arguments.length + "arguments"); var result = return bar.apply(this, arguments); print("bar() returned" + result); return result; } //! [68] //! [69] QScriptValue foo(QScriptContext *ctx, QScriptEngine *eng) { QScriptValue bar = eng->globalObject().property("bar"); QScriptValue arguments = ctx->argumentsObject(); qDebug() << "calling bar() with" << arguments.property("length").toInt32() << "arguments"; QScriptValue result = bar.apply(ctx->thisObject(), arguments); qDebug() << "bar() returned" << result.toString(); return result; } //! [69] //! [70] function counter() { var count = 0; return function() { return count++; } } //! [70] //! [71] var c1 = counter(); // create a new counter function var c2 = counter(); // create a new counter function print(c1()); // 0 print(c1()); // 1 print(c2()); // 0 print(c2()); // 1 //! [71] //! [72] QScriptValue counter(QScriptContext *ctx, QScriptEngine *eng) { QScriptValue act = ctx->activationObject(); act.setProperty("count", 0); QScriptValue result = eng->newFunction(counter_inner); result.setScope(act); return result; } //! [72] //! [73] QScriptValue counter_inner(QScriptContext *ctx, QScriptEngine *eng) { QScriptValue outerAct = ctx->callee().scope(); double count = outerAct.property("count").toNumber(); outerAct.setProperty("count", count+1); return count; } //! [73] //! [74] QScriptValue counter_hybrid(QScriptContext *ctx, QScriptEngine *eng) { QScriptValue act = ctx->activationObject(); act.setProperty("count", 0); return eng->evaluate("(function() { return count++; })"); } //! [74] //! [75] function Book(isbn) { this.isbn = isbn; } var coolBook1 = new Book("978-0131872493"); var coolBook2 = new Book("978-1593271473"); //! [75] //! [76] QScriptValue Person_ctor(QScriptContext *ctx, QScriptEngine *eng) { QScriptValue object; if (ctx->isCalledAsConstructor()) { object = ctx->thisObject(); } else { object = eng->newObject(); object.setPrototype(ctx->callee().property("prototype")); } object.setProperty("name", ctx->argument(0)); return object; } //! [76] //! [77] QScriptContext *ctx = eng.pushContext(); QScriptValue act = ctx->activationObject(); act.setProperty("digit", 7); qDebug() << eng.evaluate("digit + 1").toNumber(); // 8 eng.popContext(); //! [77] //! [78] QScriptValue getSet(QScriptContext *ctx, QScriptEngine *eng) { QScriptValue obj = ctx->thisObject(); QScriptValue data = obj.data(); if (!data.isValid()) { data = eng->newObject(); obj.setData(data); } QScriptValue result; if (ctx->argumentCount() == 1) { QString str = ctx->argument(0).toString(); str.replace("Roberta", "Ken"); result = str; data.setProperty("x", result); } else { result = data.property("x"); } return result; } //! [78] //! [79] QScriptEngine eng; QScriptValue obj = eng.newObject(); obj.setProperty("x", eng.newFunction(getSet), QScriptValue::PropertyGetter|QScriptValue::PropertySetter); //! [79] //! [80] obj.x = "Roberta sent me"; print(obj.x); // "Ken sent me" obj.x = "I sent the bill to Roberta"; print(obj.x); // "I sent the bill to Ken" //! [80] //! [81] obj = {}; obj.__defineGetter__("x", function() { return this._x; }); obj.__defineSetter__("x", function(v) { print("setting x to", v); this._x = v; }); obj.x = 123; //! [81] //! [82] myButton.text = qsTr("Hello world!"); //! [82] //! [83] myButton.text = qsTranslate("MyAwesomeScript", "Hello world!"); //! [83] //! [84] FriendlyConversation.prototype.greeting = function(type) { if (FriendlyConversation['greeting_strings'] == undefined) { FriendlyConversation['greeting_strings'] = [ QT_TR_NOOP("Hello"), QT_TR_NOOP("Goodbye") ]; } return qsTr(FriendlyConversation.greeting_strings[type]); } //! [84] //! [85] FriendlyConversation.prototype.greeting = function(type) { if (FriendlyConversation['greeting_strings'] == undefined) { FriendlyConversation['greeting_strings'] = [ QT_TRANSLATE_NOOP("FriendlyConversation", "Hello"), QT_TRANSLATE_NOOP("FriendlyConversation", "Goodbye") ]; } return qsTranslate("FriendlyConversation", FriendlyConversation.greeting_strings[type]); } //! [85] //! [86] FileCopier.prototype.showProgress = function(done, total, currentFileName) { this.label.text = qsTr("%1 of %2 files copied.\nCopying: %3") .arg(done) .arg(total) .arg(currentFileName)); } //! [86] //! [87] lupdate myscript.qs -ts myscript_la.ts //! [87] //! [88] lupdate -extensions qs scripts/ -ts scripts_la.ts //! [88] //! [89] lrelease myscript_la.ts //! [89] //! [90] ({ unitName: "Celsius", toKelvin: function(x) { return x + 273; } }) //! [90] //! [91] QScriptValue object = engine.evaluate("({ unitName: 'Celsius', toKelvin: function(x) { return x + 273; } })"); QScriptValue toKelvin = object.property("toKelvin"); QScriptValue result = toKelvin.call(object, QScriptValueList() << 100); qDebug() << result.toNumber(); // 373 //! [91] //! [92] QScriptValue add = engine.globalObject().property("add"); qDebug() << add.call(QScriptValue(), QScriptValueList() << 1 << 2).toNumber(); // 3 //! [92] //! [93] typedef QSharedPointer XmlStreamReaderPointer; Q_DECLARE_METATYPE(XmlStreamReaderPointer) QScriptValue constructXmlStreamReader(QScriptContext *context, QScriptEngine *engine) { if (!context->isCalledAsConstructor()) return context->throwError(QScriptContext::SyntaxError, "please use the 'new' operator"); QIODevice *device = qobject_cast(context->argument(0).toQObject()); if (!device) return context->throwError(QScriptContext::TypeError, "please supply a QIODevice as first argument"); // Create the C++ object QXmlStreamReader *reader = new QXmlStreamReader(device); XmlStreamReaderPointer pointer(reader); // store the shared pointer in the script object that we are constructing return engine->newVariant(context->thisObject(), QVariant::fromValue(pointer)); } //! [93] //! [94] QScriptValue xmlStreamReader_atEnd(QScriptContext *context, QScriptEngine *) { XmlStreamReaderPointer reader = qscriptvalue_cast(context->thisObject()); if (!reader) return context->throwError(QScriptContext::TypeError, "this object is not an XmlStreamReader"); return reader->atEnd(); } //! [94] //! [95] QScriptEngine engine; QScriptValue xmlStreamReaderProto = engine.newObject(); xmlStreamReaderProto.setProperty("atEnd", engine.newFunction(xmlStreamReader_atEnd)); QScriptValue xmlStreamReaderCtor = engine.newFunction(constructXmlStreamReader, xmlStreamReaderProto); engine.globalObject().setProperty("XmlStreamReader", xmlStreamReaderCtor); //! [95]