Note: this article was written on 2007-04-27, and the circumstances may probably change in the future.
I was about to write a very positive story about Kommander, a development tool from KDE. However, I think I’m only going to do so during the first lines and in the end I’m going to write a pretty long rant about it. Not because I think it deserves being bashed in public. Kommander is, IMHO, a great idea which needs a lot of technical improvements. The core idea is very good, but Kommander has many problems and bugs that need to be solved if it wants to be much more useful. I am currently using Kommander for a couple of things and fully acknowledge its power. There’s also a Kommander scripts section at http://www.kde-apps.org.
Kommander is composed of two main programs. kmdr-executor is the program that runs Kommander scripts. kmdr-editor is the one that lets you create those scripts. A Kommander script is an XML file that describes something to be run. When you launch kmdr-editor, you find a tool similar to the Qt designer, if you know it, but simplified. The idea behind Kommander is that you must take into account 3 different aspects of your application. First, the editor lets you create dialogs (that is, windows) with widgets (buttons, labels, checkboxes, line edits, text edits, etc). Then, you must specify associations between events and actions. The events come from the different widgets, like a specific button being clicked. The actions are also associated to other widgets, because widgets can perform actions. In Qt, this is called signals and slots, and those are the terms Kommander uses. Finally, the core of those actions is a very simple programming language that lets you manipulate the application widgets by their name (which you set, like MyLovelyCheckBox), setting their text and/or state, perform basic operations with text strings, doing basic flow control (if, for), and run programs and scripts in any language, taking their output and manipulating it. That’s what makes Kommander powerful. You can take the texts and selections in the widgets, use them as parameters to run scripts in arbitrary languages (shell, awk, perl, python, php…) and process the output of those scripts to use them in other widgets. Kommander acts as a powerful glue that binds all those actions together in a GUI.
Kommander Handbook (F1)
The main problem with Kommander is its documentation and specially its handbook. The introduction is very hard to understand for programmers and non-programmers, and you don’t get to see an example of what Kommander is about because the tutorials, which should appear later in the documentation, are missing. It contains a lot of philosophy that should probably be put in a different section.
There are also contradictions present in the project goals and features, in my humble opinion. Quoting from the introduction:
The primary objective is to create as much functionality as possible without using any scripting language.
Yet the power of Kommander, as mentioned before, is being able to run scripts in many differente languages and bind them all together. This is acknowledged later in the introduction:
By being language neutral and allowing a Kommander dialog to be extended by using any scripting language Kommander positions itself in a unique position for wide spread adoption. Multiple script languages can be used in a single dialog and applications can be taken over by people using a different language than the original developer and gradually converting and extending it. New widgets and features can be instantly leveraged by all available languages.
In fact, the Kommander programming language (the one you use to code “actions”) is very simple and limited. If they wanted to be able to create as much functionality as possible without using any scripting language they should make the internal language powerful, don’t you think? Furthermore, Kommander tries to appeal to novices and non-programmers:
We hope that Kommander begins to get the developer support and recognition required to achieve the potential it offers. Our end goal is to make Kommander useful for novice users to extend and merge their applications.
However, no novice user is going to use Kommander if it has that lack of documentation and tutorials, and if the power resides in binding together scripts in arbitrary languages, the user will need to know one or more scripting languages to do something useful, and that’s not very novice-friendly.
Despite all that, I think Kommander is going the right way. I don’t mind contradictions between the project goals and the project state as long as I like the project state, obviously.
I think Kommander developpers need to urgently rewrite the introduction and create an easy to follow tutorial so people will see how to create dialogs, use layouts in them, connect signals and slots and use different scripting languages, as well as the Kommander language, to do something useful. This way, us Kommander newbies could easily see what a Kommander program is supposed to look like, according to them.
The names the Kommander developpers have chosen for some components are unexplained and unfamiliar to programmers. In Kommander, words with special meanings are preceded by the @ character. For example, you have @if, @endif, @exec, @String.replace() and also widget names like @MyLovelyCheckBox. These are called specials and can refer, as you see, to reserved words, widget names, function names, etc. However, the name special isn’t used in any mainstream language that I know of. Please, mail me if I’m missing some important language with specials. Also, the introduction description of them is very poor.
Widgets have two types of text associated to them. One is the widget text, which is the content of the widget. For example, a button label like “Click me” or a text you have introduced in a line edit. On the other hand, widgets can “perform actions” to react upon events, and these actions are described in a special scripting language, like I mentioned before. These scripts are called Kommander text and that name is confusing because everytime you want to talk about a widget and modifying its text using Kommander text you end up talking about text and nobody knows what you’re refering to. This happens in the handbook introduction. I would have chosen another name like Kommander scripts, Kommander actions, or anything that doesn’t have the word “text” in it.
The documentation is also plain wrong at some points because Kommander has changed and some things can be no longer done the way they’re described in the documentation. So it’s not only imcomplete, but sometimes wrong.
Key components go undocumented
Many key aspects and components of Kommander are completely undocumented, despite the fact that they should be the first ones to get documentation. Most widgets can have two Kommander texts. One is called the default Kommander text and the other one is called the population Kommander text. The one you will need to use more, I suppose (due to the lack of documentation I can’t be sure of what I’m saying), is the population Kommander text. However, when you edit the Kommander text of a widget, you have to manually choose to edit the population Kommander text, because the initial option is to edit the default Kommander text. It’s funny, because I still don’t know what the default Kommander text in a line edit is supposed to do or when it is supposed to be run. The importance of the population Kommander text is mentioned in the handbook introduction:
Signals and Slots is a little less intuitive to a new user. It is under review for how we process things in the first major release. These offer a limited event model for when a button is pushed or a widget is changed. Combined with “Population Text” it is rather powerful.
Furthermore, the usage of the population Kommander text is very confusing, and it took me a good amount of minutes to figure out what I was supposed to do with it, and let me explain the confusion in detail. Let’s suppose you want to create a simple dialog with a read-only line edit (the user can’t modify its contents) that displays your kernel version. The kernel version can be obtained from running uname -r. You create a dialog and place a line edit in the middle. You mark the dialog as read-only in the properties panel to the left. You then associate the widgetOpened dialog event to the line edit populate action, so that the line edit is populated with the kernel version when the application starts. How do you get and set the line edit text? The @exec special is the name of a function that runs a program and gets its output, so you need to run @exec(uname -r). Suppose you called your line edit KernelVersionEdit. Widgets have a set of properties that can be used to read or set its contents. For example, line edits, among other widgets, have a property or method called setText, which receives a text string. By invoking the following, you can achieve the intended effect: @KernelVersionEdit.setText(@exec(uname -r)). Or that was what I thought, because it turns out the population Kommander text has to contain a string or something that returns a string, which will be used to fill the widget contents, like @exec(uname -r). The other full expression won’t work, because its execution won’t return a string. When I tried to create my first application I thought something wasn’t working, and I didn’t know if it was my mistake or a program bug. I didn’t know if I was right assuming that when the populate action is associated with an event, the population Kommander text was executed. I finally got it running by specifying only @exec(uname -r) as the population Kommander text, and I don’t know if I had read it somewhere or if I was simply trying alternatives. I swear I don’t remember, but discovering it was painful. If the handbook had a tutorial, this wouldn’t have happened.
Another key component is the script widget. It’s a special invisible widget that has an execute action, and you can bind it to events. You can write things to do in the default Kommander text for the script widget, then bind an event to the execute action and it will do those things. The previous example could have used a script widget in addition to the line edit. I could have written @KernelVersionEdit.setText(@exec(uname -r)) in its default Kommander text and bind the widgetOpened event to its execute action, achieving the same effect. The script widget is a key component when the action involves more than just setting some widget text. For example, in one of my tests I created a GUI for the locate command. It lets you specify a regular expression to search, then launches locate with that regular expression and sends the result to a listbox, and if you doubleclick on any entry, it will launch kfmclient exec with the selected file or directory. It’s very neat, but locate can take some seconds to run, and the program appeared to have frozen, so I decided to add a status bar that contains “Searching…” while locate is being run, and after it has finished it contains “Found [x] files.”, where [x] is the number of rows in the listbox (there’s a listbox property to get the number, very easy). However, that group of actions need a script widget, or otherwise it can’t be done. The script widget isn’t mentioned in the documentation at all. Now, I ask, wouldn’t it be better if the populate action for the widgets would simply run their contents, including some setText calls if the user wants to? You wouldn’t have to use the script widget, and I wouldn’t have hit the problem in mentioned in the previous paragraph. Maybe people don’t usually hit that problem and it was just me. An issue with this suggestion is that, while the event is attached to the action of a widget, you could modify any other widget from that action. This is slightly unelegant.
The only way to evaluate arithmetic expressions is to use the @expr special, but the documentation does not mention if it’s floating point or integer, or which operations are supported. I suppose the basics (+, -, *, /) are supported, but what about others? Experimentation is the only way to find out these things.
The @if special lets you execute some things if a condition is met, but it doesn’t have an @else counterpart. The boolean checks you can perform aren’t mentioned either. You’ll have to find out trying. Not having @else may be due to the lack of a grouping character (like the curly braces in many languages). This could be solved by introducing those grouping characters or by specifying in the @else and @endif the condition of the @if block they belong to (users of CMake will recognize this approach). Some other constructions use the @endif special as terminator, eventhough they’re not if blocks. Wouldn’t @endfor make more sense? Or something like bourne shell, where both the beginning and the end are marked with do and done.
The usage of double quotes to indicate strings is undocumented, as well as the escape sequences. Kommander interprets everything as strings, like for example mIRC does, so instead of @Somespecial(“The string parameter”) you use @SomeSpecial(The string parameter). This creates unneeded problems, in my humble opinion, and leads to confusing situations. How do you indicate a single space or end of line as argument, without receiving a syntax error? The answer is using ” “ and “\n”, quotes included, as far as I have seen.
Despite its orientation to manipulating strings and the output of programs, there’s no easy way of joining two strings without spaces between them. If you have two line edits, and one of them contains Hello and the other one World, you can join them with something like @LineEdit1.text @LineEdit2.text and get Hello World, but what if you want to get HelloWorld? I use the hack of putting each one of them in one line and calling @String.remove() on that, with “\n” as the second argument.
In a couple of places in the documentation the format a string must have is mentioned using a description like key\tvalue\n. I doubt a novice user will know what \t or \n mean, and if, on top of that, you put that description in italics, the backlash may end up looking like a vertical bar, making the description even more confusing.
I haven’t found a simple way of processing lines as they are received. Suppose you want to create a GUI for a program that outputs a completion percentage as it’s working, and you want to use it to create a progress bar. @exec returns all the output when the program finishes, but you can’t process the program output while it’s working. Using @forAll doesn’t solve the problem either. Is there a way to do this? If not, how can you use the progress bar widget in a useful way?
There are some bugs processing comments (lines that start with the # character), because sometimes I have commented lines of code to try a couple of alternatives and the programs have gone wild, doing weird things. These problems were solved as soon as I removed the comment line. I’m sure it was not my fault because I tried this several times, putting the comment line back again, even writting it again manually, and it was obvious the comment line was the source of the problems.
Despite all these problems, Kommander looks promising and I recommend you to experiment with it. Try not to get very frustrated when things don’t work and avoid doing complex things. You’ll find you are able to create very useful GUIs in a handful of minutes. You can easily use Kommander to display information coming from several programs or scripts, and create launchers for command line programs. I created a couple of GUIs for the cifras and letras programs and they work very well.