\chapter How to Design and Implement Application Objects

\section1 Overview

This chapter explains how to implement application objects and
provides the necessary technical background material.

\section1 Making a C++ object available to Scripts Written in Qt Script 

Making C++ classes and objects available to a scripting language is
not trivial since scripting languages are more dynamic than C++ and
it must be possible to introspect objects (query information such as
functions names, function signatures, properties, etc., at runtime).
Standard C++ doesn't provide 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 \link
http://doc.trolltech.com/moc.html moc\endlink (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.
\QSA 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 \link
http://doc.trolltech.com/3.0/object.html Qt Object Model \endlink. 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.

To make an object available in Qt Script, it must derive from QObject.
All classes which derive from QObject are introspective and can
provide the information needed by the scripting engine, e.g.
classname, functions, signatures, etc., at runtime. 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 Qt Script

The meta object system makes information about slots dynamically available
at runtime. This means that for QObject derived classes,
only the 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 be available to scripters are public slots:

\code
class MyObject : public QObject
{
    Q_OBJECT

public:
    MyObject( ... );

    void aNonScriptableFunction();

public slots: // these functions (slots) will be available in Qt Script
    void calculate( ... );
    void setEnabled( bool enabled );
    bool isEnabled() const;

private:
   ....

};
\endcode

In the example above, aNonScriptableFunction() is not declared as a
slot, so it will not be available in \QS. The other three functions
will automatically be made available in \QS.

\section2 Making C++ Class Properties Available in Qt Script

In the previous example, if we wanted to get or set a property
using \QS we would have to write code like the following:

\code
var obj = new MyObject;
obj.setEnabled( true );
debug( "obj is enabled: " + obj.isEnabled() );
\endcode

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:

\code
var obj = new MyObject;
obj.enabled = true;
debug( "obj is enabled: " + obj.enabled );
\endcode

To make this possible, you must define properties in the C++ QObject
subclass. The class declaration of \c MyObject must look like the
following to declare a property \c enabled of the type \c bool, which
should use the function \c setEnabled(bool) as its setter function and
the function \c isEnabled() as its getter function:

\code
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 Qt Script
    void calculate( ... );
    void setEnabled( bool enabled );
    bool isEnabled() const;

private:
   ....

};
\endcode

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.

\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 fired (emitted)
the slot is called. This connection is established using the \c
QObject::connect() function. This mechanism is also available to \QS
programmers. The C++ code for declaring a signal is no different for a
C++ class that is to be used by \QS than a C++ class used with \QT.

\code
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 Qt Script
    void calculate( ... );
    void setEnabled( bool enabled );
    bool isEnabled() const;

signals: // the signals
    void enabledChanged( bool newState );

private:
   ....

};
\endcode

The only change this time is to declare a \c signals section, and
declare the relevant signal in it.

Now the script writer can write a function and connect
to the object like this:

\code
function enabledChangedHandler( b )
{
    debug( "state changed to: " + b );
}

function init()
{
    var obj = new MyObject;
    // connect a script function to the signal
    connect( obj, "enabledChanged(bool)", this, "enabledChangedHandler" );
    obj.enabled = true;
    debug( "obj is enabled: " + obj.enabled );
}

\endcode

\omit
Please note that connections can also be made using point-and-click in \QSAD. 
\endomit

\section1 Design of Application Objects

The previous section described how to implement C++ objects which can
be used in \QS. Application objects are the same kind of objects, and
they make your application's functionality available to \QS 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 application's
public API using signals, slots, and properties. This gives you
complete control of the functionality you make available. The
implementation of these objects simply calls 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". For an example of this technique, see the implementation of
an application object in the \c SheetInterface (\c
examples/spreadsheet/sheetinterface.{cpp|h}).
