Intro

The purpose of this tutorial is to offer a step-by-step introduction how to integrate Kross into your application. While you can integrate Kross also in non-kpartified applications, it's easier to do with the KPart system. This tutorial will assume that you have a kpart application and what we will do is to go step by step through the process of creating a KPart plugin that integrates into your application and provides all the scripting. The scripting functionality is strictly separated from the application. The plugin that implements scripting is optional and the application does not need to know any details about what the plugin does.

This tutorial needs kdelibs4 based on Qt 4.2. While Kross and the KDE Javascript backend are included in kdelibs4, it is needed to compile the KOffice2 libraries to install the Ruby and Python support (will be moved to kdebindings soon).

The whole sourcecode we will produce within this tutorial could also be downloaded as kross2tutorial.tar.gz and contains all files needed to build a simple example that demonstrates how Kross could be used. Download and extract the tarball. Compile, install and run the kross2tutorialapp application and its kross2tutorial KPart plugin now with;

Kross

The Kross scripting framework provides full
Python, Ruby and
KDE JavaScript scripting support. The goal was
to limit the work needed on applications to have them fully scriptable and to provide a modular
way to transparently integrate additional interpreters and in that way extend your application
with a new scripting-backend without any new line of code and even without any recompile. To
achieve this internally Qt's introspection-functionality like signals, slots, properties,
enums, QVariant, QObject, QMetaObject, QMetaType, etc. are used to deal with functionality
at runtime.

The Interpreter plugins

Kross offers a plugin-interface to integrate interpreter backends like Python, Ruby and
KDE-Javascript. They are loaded on demand at runtime. Neither the application nor Kross
needs to know any details about the backends. This clear separation between the application
and scripting details enables at the one hand, to deal with scripting at an abstract level without
being bound to only one backend, and at the other hand makes it easy to integrate scripting
into an already existing application.

The Kross::Interpreter
class is a singleton controlled by the
Kross::Manager
and could be used to setup the interpreter or do other things to share functionality between
instances of the Script class.

The Kross::Script
class handles exactly one script instance. An application is able to deal with multiple
scripts at the same time where each of them has it's own instance of the Kross::Script
class controlled by an instance of the more abstract
Kross::Action class.

The Module plugins

Modules are plugins loaded on demand at runtime to provide additional functionality. They are
somewhat wrappers/bindings/adaptors to offer access to functionality your application or
a library of your application likes to expose to scripting backends. TODO: this parag doesn't parse for me

Since Qt's introspection functionality is used, we are able to throw in just QObject's
and have them act as classes/objects within a scripting backend. Slots are membermethods
while properties and enumerations are membervariables. If your application also likes
to offer DBus support it may be
an idea to reuse the
QDBusAbstractAdaptor
implementations your application has also for scripting, like for example
KSpread did.

Let's take a look at the following code that implements such a module;

Then we just need to have our myobject.h and myobject.cpp files, filled with the content
above, defined in the CMakeLists.txt file. The library needs to be named "krossmodule..." where
the "..." is then the name the module is accessible as. For our example we use
"krossmodulemyobjectmod" and therefore we are able to access the module if installed
as "myobjectmod". The example does not depend on Kross, so you may like to replace
${KROSS_INCLUDES} with whatever else your module depends on.

The following Python sample code accesses then the module at runtime and uses the QObject,
calls it's slots and properties and connects a signal with a python function (e.g. save as
file named "myobjecttest.py" and execute with "kross ./myobjecttest.py");

Manager, GuiClient, Action

The Kross::Manager
class is a singleton that provides access to the interpreters, to actions and to the modules.
The Kross::Manager is available within scripting code as module named "Kross". Following Python
script uses the Kross module to create a new Kross::Action instance, fills it with JavaScript
code and executes that JavaScript code.

The Kross::GuiClient
class implements KXMLGUIClient to provide GUI functionality, handling of XML configuration files
on a more abstract level and offers some predefined actions that could be optionally used in
your application.

The Kross::Action
class offers an abstract container to deal with scripts like a single standalone scriptfile.
Each action holds a reference to the by the matching
Kross::Interpreter
instance created by Kross::Script
instance. Following Python script accesses the Kross module and the self variable which is
our Kross::Action instance that provides the context for the running Python script.

DBus and Kross

With the QtDBus module Qt provides a library that a Qt/KDE application is able to use to make Inter-Process Communication using the D-BUS protocol.

The QtDBus module uses the Qt Signals and Slots mechanism. Applications that like to provide parts of there functionality to the DBus world are able to do so by implementing classes that inherit from the QDBusAbstractAdaptor class.

Kross is able to reuse such by an application provided bindings. So, once your application supports dbus, Kross is able to reuse those already existing code and offers transparent access to the scripting-backends to them. How does this differ from e.g. the python-dbus package? Well, first method-calls don't go through the dbus-socket and then it's not dbus-related at all except, that we are able to reuse what your application offers anyway: a clean interface to the outside world. But that's not all, we are not limited to what's possible with dbus. We are also able to exchange instance-pointers to QObject or QWidget instances.

For an example you may like to take a look at how it was done in the KSpread ScriptingModule class.

The application

This section deals with the question how to integrate Kross into a KPart-application to
be able to extend your application with scripting.

For testing purposes we first create a simple KPart application. If you already have an application
you may like to skip this section and continue with the KPart Plugin.