Further information

In the previous sections we have seen a basic example of KTutorial covering the main concepts. This section explores some of these concepts in greater depth and introduces others not shown before.

KTutorial provides some default WaitFor subclasses to model common conditions to wait for:

  • WaitForEvent: a simple condition that waits for an event to be received in some object. Note that the wait ends when the event of the specified type is received, no further checks are made. For example, if you wait for a MousePressed event, the wait will end whenever a mouse button is pressed (on the specified object). If you want to end it when the left button is pressed but not when the right button is pressed you have to subclass WaitForEvent to implement a finer grained behavior.

  • WaitForSignal: a simple condition that waits for a signal to be emitted by some object. Like WaitForEvent, it just waits for the signal to be emitted. No argument value is checked. You have to provide your own WaitFor to do the checks (or make them, when possible, in the slot called when the condition is met).

  • WaitForProperty: a simple condition that waits for a property to have certain value. To wait for a property, the property must have a notify signal. However, no matter if it has a notify signal or not, a property can be used to check its value when another condition is met. For example, instead of calling a slot to check if a widget is visible once some signal is emitted, the WaitForSignal can be composed with a WaitForProperty for the visible property of the widget, even when the visible property does not have a notify signal.

  • WaitForWindow: a simple condition that waits for certain window (or dialog) to be shown. Although it can be used with windows, modal dialogs and modeless dialogs, it was created mainly to deal with modal dialogs. Due to Qt's internals, waiting for a signal that is connected to a slot that shows a modal dialog does not work (the signal is not delivered to the WaitForSignal until the dialog is closed). Waiting for the modal dialog to be shown must be used instead in that case.

  • WaitForStepActivation: a simple condition that waits for its step to be activated. Its purpose is to create preconditions for a step. For example, if some item of a combo box is not selected when a step is activated, instead of showing that step the tutorial can change to another one that tells the user to select that item.

  • WaitForAnd: a composed condition that waits for all its child conditions to be met.

  • WaitForOr: a composed condition that waits for any of its child conditions to be met.

  • WaitForNot: a special composed condition to be used only as a child of a WaitForAnd. Its purpose is negate the condition it contains, so you can wait for one or more conditions unless other conditions were already met.

Please refer to the API documentation, the examples in KTutorial test app and the tutorials in KTutorial editor for further information.

In the previous tutorial examples everything was initialized when the tutorial was created. In the C++ tutorial, steps and their reactions were created and initialized in the tutorial constructor. In the JavaScript tutorial, they were created and initialized in the main script body. But, what happens if we need, for example, to wait for a signal emitted by an object that did not exist when the tutorial was created?

For example, suppose that some step has to wait until a dialog is accepted. It is very unlikely that the dialog exists when the tutorials are created, that is, when KTutorial is set up. If the object doesn't exist, findObject can't return it, so the step ends waiting for a signal emitted by a null object, the waiting never ends, and the tutorial never changes to another step.

The methods setup and tearDown in Tutorial and Step classes are the solution. They are executed when a tutorial is started or finished, or when a step is activated or deactivated (the tutorial changes to that step, or changes from that step to another one).

In C++ tutorials, setup and tearDown methods must be redefined in subclasses.


In scripted tutorials, a function to be connected to the setup and tearDown signals of tutorial or step objects must be done.


The most common use for step setup methods is creating and initializing the reactions of that step that depend on "dynamic" objects (objects that may or may not be created depending on the user actions, like dialogs). However, there is no harm in creating every reaction of a step in its setup method. In fact, KTutorial editor generated code uses that approach to be on the safe side.

Also note that reactions (WaitFors and Options) created in step setup methods are automatically removed and deleted in step tearDown, so you don't have to worry about cleaning up them.

Most of the time, the name of the objects, when set, will be unique. However, it is not always the case. Think, for example, in the Ok button of a dialog. Its object name will likely be Ok button or something like that, and inside its dialog it will be unique; in the whole application, on the other hand, it probably will not. So, if you try to find the object called Ok button and there are several dialogs opened at that moment you can't be sure that you will end getting the desired one.

In cases like this one the way to identify an object using its name is also including its ancestor names. That is, instead of calling findObject with the parameter Ok button, call it with Configuration dialog/Ok button. Note that the ancestor does not need to be the direct parent; any ancestor will work. And also note that as many ancestor names as desired can be included. For example, Configuration dialog/Button bar/Ok button.

It is advisable that at least one of the ancestors has a unique name. However, it is not a must. Using ancestors with a name not unique is also valid if the full path itself is unique. For example, if there are several objects called Chart and several objects called Dialog, but only one Chart object is descendant of a Dialog object, then Dialog/Chart is a valid name to look for.

Anyway, sometimes an object may not have a unique name. For example, think in two nested dialogs (a parent dialog and a child dialog) with an Ok button each. If the Ok button in the parent dialog is its direct child, its name would be Parent dialog/Ok button. But that name will represent too the Ok button of the child dialog, as the parent dialog is its ancestor too. So, when a name is not unique, a set of ambiguity solving rules is applied when findind the object it represents. Please refer to the API documentation of findObject(QString) method in KTutorial class for further information.

Tutorials usually refer to widgets when explaining the user what has to be done: show the item list in the combobox, click this or that button, write something in a text editor, etc. However, a user may not know what a combobox is, or may not be sure which button in a toolbar push, or may just want a confirmation that the tutorial expects him to write where he is going to write.

For cases like those ones, KTutorial provides a way to create links to widgets in the step text. When the link is clicked, the referenced widget will be highlighted. The highlighting will stop when the link is clicked again, the widget gets the focus or the link to another widget is clicked.

The links are like standard HTML links, but using a special URI: widget: theObjectNameOfTheWidget . So, for example, to link to a button which object name is addButton in some text you will write something like Click on <a href="widget:addButton">the button with the plus sign</a> to create a new entry or, if KDE semantic markup is used, Click on <link url="widget:addButton">the button with the plus sign</link> to create a new entry .

KTutorial provides a default KDE user interface ready to be used in your application, but it also offers you the possibility to use your own user interface. Instead of initializing KTutorial through the setup(KXmlGuiWindow*) method in KTutorial class, you have to initialize it using the setup(KTutorialCustomization*) method, passing it your own implementation of KTutorialCustomization interface.

That class has to set up the user interface of KTutorial, which is composed of two main elements: a user interface for the tutorial manager, and a user interface for the tutorials. The tutorial manager UI is responsible for showing the available tutorials to the user so he can decide which one to start, while the tutorial UI is responsible for showing an specific tutorial to the user.

Please refer to the API documentation of KTutorialCustomization interface and the code itself of DefaultKdeCustomization class for further information.

Note that the default tutorial, Using the tutorials , is highly coupled to the default KDE user interface of KTutorial, so it is registered only when that default UI is used. If you customize KTutorial you should also provide a tutorial explaining how to use the tutorials with your user interface.

Although the bridge made by Kross between Qt Meta-Object System and scripts is pretty nice, sometimes it is not enough. Sometimes you may need a feature that can't be accessed from properties or slots. For example, if you need to get a QTextCursor in a QTextEdit to know the currently selected text. Or if you need to define a class in the scripting language to be used as an event filter (which needs a QObject derived class).

What happens in these cases? Are we condemned to a scripting world stuck to Qt Meta-Object System? Not at all. Fortunately, being just a bridge Kross allows us to use the scripting language bindings if they are available. So we can use PyQt, PyKDE, or the Smoke based bindings (QtRuby/Korundum, JSmoke...) like we would do in a normal script :D

Can you show us an example, please, please? Yes I can. And so I will do ;)

PyQt4 are the bindings of Qt4 for Python. It makes possible to use all Qt classes from Python code, and even defining Python classes that inherit from Qt classes. Impressed? You should. But there is still more. Go on reading to find out what else can PyQt4 do for you.

The following example will show, step by step, how to install an event filter in a C++ QTextEdit that emits a signal when the mouse left button is pressed. The event filter will be defined in Python code and its Python signal will be connected in C++ code. Cool, isn't it? :)

Finally, the time to connect the Python signal in C++ code has come. In this case, it will be done setting the signal to wait for in the WaitForSignal object. The method setSignal receives the object that emits the signal and the name of the signal to connect to. Even being an object from a Python class, it is gracefully converted by Kross and PyQt to a QObject pointer, as the Python class inherits from QObject.

Internally, the method just adds a "2" in front of the signal name (as that is what connect expects) and calls connect with the object emitting the signal, the signal name prefixed with "2", the receiver object and its slot. Yes, exactly the same that would be needed to connect a C++ signal without using SIGNAL macro. As already said, this is so easy because PyQt >= 4.5 adds the signal to the QMetaObject of the Python classes that inherit from QObject.

In the example below, and to push even further the limits of Kross and PyQt, when the signal is emitted, it is handled by the C++ code which, in turn, calls a Python function!

Sadly, at the time of this writing, there is an open bug in Kross that makes the application crash in this scenario. Hopefully by the time when you are reading this, it will be already fixed ;) For further information, refer to krosspython: crash when PyQt signal is connected to C++ method that calls a function in the script.