<para>In this section we go beyond listing widgets to actually using &kommander;. If you want to have a good experience you will find this section very helpful.</para>
<sect1 id="tutorial-editor">
<title>Using the Editor</title>
<para>
At first glance the editor looks pretty obvious, and in many ways it is. Click on the icon to create a new form, then click a widget and click or click and drag on the form. There are the widget handles that will be familiar to anyone who ever put a picture in a word processing document. What is less obvious are the little things. One thing to mention up front is widget naming. Names must be unique and &kommander; employs a naming scheme of the formal widget name and a number unique to that widget type. You can rename a widget and &kommander; will not allow a duplicate name. However if you build a complex dialog and decide to start renaming you're going to have problems. Signals and slots will manage naming for you and any widget you change will be reflected in the signals and slots connections. Unfortunately we never got this feature in the widget functions. So ever call to that widget will be wrong. You could close the dialog and open it in a text editor like KWrite and do find and replace. A better solution is to start out with some idea what kind of descriptive names you want to give to key widgets. It may be a waste of time naming Labels, but scripts and container widgets for data quickly prove a real mistake not to name. You can also set icons for scripts making them even quicker to visually identify.
</para>
<sect2 id="tutorial-editor-tools">
<title>Editor Tools</title>
<para>
The first thing you will notice is a properties window, generally docked on the left. Explore this! Here you will find many useful settings for forms and widgets. Some of them would be layout settings, icons, if something is active, text and more. For instance if you put a TreeWidget in a form you can change the default path separator, which is useful if you have data in there. It's easy for a slash to create a sub-item accidentally. Here you will also find selection modes, whether to highlight the whole row in multi column widgets and more. Before you assune something is just how &kommander; is check this.
</para>
<para>
If you play with layouts and lose a widget behind another or off the form the object explorer will come in handy. It's also nice for seeing structure. The next very useful view is the log view which shows stdout and stderr. The error view is indispensable. This is where your debug() commands prints and where you get detailed information. For instance when using the database plugin this gives you additional information with data errors. It also shows you all shell calls and more. The Stdout view lets you see what would go to the shell or an application using this like Quanta. The dialog view is of little use unless you have a lot of dialogs open. The Action view is only active with MainWindow use and in that case it is the only way to add Actions, menu and toolbar items.
</para>
</sect2>
<sect2 id="tututorial-add-tools">
<title>Adding Custom Tools</title>
<para>
&kommander; makes it easy to add custom tools, which you can develop in &kommander;, to the editor. We will be shipping some with &kommander; as well as making some available for download. You can add your own easily. First have a look and see where they are. If they are installed they are on the tools menu below the splitter. The &kommander; menu offers access to widgets. The Custom menu offers access to installed plugins. The Editor menu is where your custom tools go. To manually add a tool first decide if you are going to make it available system wide or just to your desktop. System wide start from the directory KDE is installed in. For your desktop user start in the hidden KDE directory in your home directory, usually ~/kde. From either the path is/share/apps/kmdr-editor/editor/ If the dialog you add needs access to tools or files you can put them in a subdirectory. Whatever &kommander; dialogs you put there will be recognized and added to your menu on startup. Clicking the menu will load the dialog. You will note there is a templates directory there too and you can add templates for new dialogs.
</para>
</sect2>
<sect2 id="included-tools">
<title>Included custom tools</title>
<para>
Several tools are included with this release, already installed on the tools meu under editor. More tools are under development for project management, database front end development, code snippets and more. The most imporant and useful tool to look for is the examples dialog. As the editor is no longer under development for KDE3 it cannot insert a dialog in the current editor, but it will open any selected dialog in a new instance of the editor. There are old dialogs from the early days of &kommander;, tutorials from more recent development and the current section showing new features of this release. Looking at these should help. Keep an eye on our web site for more.
</para>
</sect2>
<sect2 id="tutorial-layout">
<title>Using Layout</title>
<para>
People love to share &kommander; dialogs. Almost without fail they don't know about laying them out. Make a dialog and then try resizing it and see what happens. Wouldn't it be nice if it behaved like it should instead of leaving your widgets the same? It gets worse when you share it and differences in fonts, monitor size and X pixel resolution conspire to make your masterpiece look like it was put together by a three year old using bubblegum and thumbtacks. Always, always always... Lay out your dialogs!
</para>
<para>
Okay, you're sold you don't want a frustrated email from me asking you to please layout your dialog. How do you do it. There are layout buttons on the toolbar and the context menu. Since &kommander; is based on an older version of Qt Designer you can look at Qt Designer docs and tutorials here. I'm just going to mention a few basics and a few tips.
</para>
<itemizedlist>
<listitem><para>Use the Grid. This will place everything in a <quote>best guess</quote> location</para></listitem>
<listitem><para>Remember containers are separate. A TabWidget, GroupBox or layout group has it's own layout. So don't forget the window.</para></listitem>
<listitem><para>Widgets that are not visible during execution can make layout seem more challenging. What to do with them? I recommend grouping them in their own layour next to or below your main layout. Your visible widgets will simply push these aside and give you a predictable result.</para></listitem>
<listitem><para>Look at your properties were you can set a widget to expand or do other things as well as minimum and maximum size. A little experimentation will teach you a lot. You can also set a tighter spacing here,</para></listitem>
</itemizedlist>
<para>And now for a few tricks and tips.</para>
<itemizedlist>
<listitem><para>Along with basic layout you can use splitters. When your dialog is running you can drag the splitter up and down or right and left to get a better look at things. It may look like there is a limitation here or it doesn't work. It works and has no limitations. Just make sure to put multiple widgets into two layouts and make sure when you click or right click to get the layout and not just a child widget. You are free to create a maze of splitters as long as you adhere to the rules.</para></listitem>
<listitem><para>Fake docs are possible! Create a GroupBox and drop widgets on it. Position it in your layout so that when it's invisible other widgets/layouts will expand to take it's place. Now toggle it's visibility with a button or menu. </para></listitem>
<listitem><para>ToolBox tricks - The Toolbox has an editor bug where you can't add widget panels in the editor without it going nuts. As a result you need to add them at run time. However it looks for one widget and if you want something complex you should use a groupbox and lay it out. then layout your dialog with the groupbox at the outside, even if it goes off the edge of the window. Now load it on initialization into the ToolBox. Your window layout will snap into place.</para></listitem>
<listitem><para>Layout glitches can occur where widgets set to something like Minimum/Expanding can end up obscured before you complete layout on the window. The layout system will honor your oddness and can be shrunk to obscure scrollbars and more. Make sure all is visible before finishing layout and consider not using minimum in that case.</para></listitem>
</itemizedlist>
<para>For more on this look up the Qt Designer docs for Qt 3.x.</para>
</sect2>
<sect2 id="signals-slots">
<title>Signals and Slots</title>
<para>
One of the very useful features inherited from Qt Designer was signals and slots. Of course the interface has been redesigned in an attempt to make it friendly to &kommander;. Signals and slots are internal event control for Qt/KDE applications. We try to make it so you don't have to know the difference between C++ data types, but if you use the new function to create connections on the fly it is handy to be able to copy that information from the connection tool. Let's look at what all this means. Something happens in one of you widgets. It could be click on, double clicked, have it's value changed, something selected or a menu could be requested. That is just some of the possible events that would enable a signal to be sent. You may want to change the list in a ListBox if a new selection is made in a ComboBox. That's a useful feature in a sophisticated application and the only way to do it without having to press a button next is to have a signal connected to a slot. That slot could be in a script or button. When the slot receives the signal it goes about doing what it was told. There is a tool to edit these connections. Pay attention when do this as there are a good number of inherited signals and slots. Telling a script which is invisible when the dialog is run to adjust it's size by accident when you meant to execute will have you wondering what happened.
</para>
<para>
To access the connection tool you can open it by right clicking anywhere on the dialog and selecting it. Click the menu and you will see a list of connections made at the bottom. Above that are two lists of signals and slots and above them the respective sender and receiver are selected. An easy way to make connections is visually. Look at the toolbar or the Tools menu. There are three items grouped there. A pointer, signals and slot connections and the tab order or widgets. Selecting this sets connection mode for the curios. Click on your widget to send the signal and drag it to your widget to receive it in a slot. As you do this you will see a line and drop indications on the widget under the mouse. The StatusBar on the Editor will tell you what is being connected.
</para>
<note><para>In version 1.3 there is a &kommander; function connect() which allows you to connect signals and slots on the fly. This is useful if you just used createWidget. Obviously you can't use the dialog for something &kommander; doesn't yet know exists. Unfortunately there are too many combinations to list so you have to type out signals and slots. <emphasis>These must be typed verbatim or they will fail.</emphasis> This is where the connection tool is handy again. Open it and select two widgets like the two you want to connect and read the connection information. if it says <command>execute(const QString&)</command> that is exactly what you must type.</para></note>
</sect2>
<sect2 id="slot-functions">
<title>Slot Functions</title>
<para>
As of version 1.3 &kommander; adds Slot functions. You can see this in the Function Browser, which is uncharacteristicly less than friendly with descriptions here. What &kommander; is doing is reading every slot registered for a given widget and making it available directly. This is very useful. For instance the Table widget doesn't have a default method to auto adjust column width. You may find this annoying, but if you look under slots there it is. The TextEdit is also lacking in built in functions for any real editing, but look under slots and there is anything you could wish for. You may have to reference some docs or just experiment. It is simply too difficult to document every slot available in builtin widgets and plugins. Most slots however are self explanatory.
</para>
</sect2>
</sect1>
<sect1 id="tutorial-basics">
<title>Basic Tutorials</title>
<para>
Most of the information in this section is based on example dialogs some time ago, which unfortunately were not widely available as they were shipped with the source, but not installed. You should find them in your tools menu under examples in the <quote>tutorial</quote> section. Keep in mind most of these particular examples use the old parser. That is neither good nor bad. Most of the functionality in &kommander; is shared in both parsers. It's just each is particularly suited to do a better job with a given task. As &kommander; now defaults to the new parser you can set either one. Please see the <link linkend="new_parserdocs">New Parser docs</link> for more information on the two parsers.
</para>
<para>
When examining example dialogs remember to look in the following places to see how things are done.
</para>
<itemizedlist>
<listitem><para>Dialog Initialization - middle click on the dialog face or right click and select &kommander; Text. Here you see what is run when the dialog starts.</para></listitem>
<listitem><para>Buttons - middle click the button, or right click. Scripts are typically here.</para></listitem>
<listitem><para>Widgets - some widgets like Timers and Konsoles will hold instructions inside them.</para></listitem>
<listitem><para><link linkend="signals-slots">Signals and Slots</link> - this is how Qt/KDE programs internally communicate. </para></listitem>
</itemizedlist>
<para>
The following list of dialogs may be brief so as to focus on where more information is required to explain more complex tasks possible with &kommander;. They were copied from Michal's notes.
</para>
<sect2 id="tutorial-globals">
<title>Globals</title>
<para>Shows using global and setGlobal &DCOP; calls to provide global variables for script</para>
<blockquote><para>
Functions/concepts:
- global
- setGlobal
- changeWidgetText
</para></blockquote>
</sect2>
<sect2 id="tutorial-dcop">
<title>&DCOP;</title>
<para>Shows how to use both local and external &DCOP; calls to communicate with external application (here: KMail).</para>
<blockquote><para>
Functions/concepts:
- external DCOP
- addListItem
- enableWidget
- @selectedWidgetText
- @widgetText
</para></blockquote>
</sect2>
<sect2 id="tutorlal-slots">
<title>Slots</title>
<para>Shows how to us connections/slot to handle events. Both population and standard slots are used.</para>
<note><para>Population text was originally developed before &kommander; DCOP, specials and scripting. Given that everything it does can be done in other ways and that it is easy to forget to look here for problems, along with the inherent difference of introducing an additional behavior to explain, this is a deprecated function. It is left in for illustration, however while &kommander; dialogs will be easy to port to KDE4 this feature is not assured to work in the future. <emphasis>Don't use it!</emphasis> </para></note>
<blockquote><para>
standard slots are used.
- slots/connections
- populate()
</para></blockquote>
</sect2>
<sect2 id="tutorial-settings">
<title>Settings</title>
<para>Shows how to use @readSetting and @writeSetting functions to write/restore widget content. Also, show how to use populate() slot to initialize widget content.</para>
<blockquote><para>
Functions/concepts:
- @readSetting
- @writeSetting
- populate()
- slots/connections
- destroy
</para></blockquote>
</sect2>
<sect2 id="tutorial-append">
<title>Append</title>
<para>Shows how you can append text to TextEdit and how you can use it to display formatted text. See newer examples for how to use slots to edit rich text and new font and color dialogs too.</para>
<blockquote><para>
Functions/concepts:
- changeWidetText
- RichTextEdit
</para></blockquote>
</sect2>
<sect2 id="tutorial-cmdline">
<title>Command Line</title>
<para>Shows how you can pass parameters to &kommander; dialog via command line. Also, shows how to change list content and button text. See the section on <link linkend="passargs">passing arguments</link> in the new parser for more on this.</para>
<blockquote><para>
Functions/concepts:
- command-line arguments
- global
- changeWidgetText
- addListItem
- clearList
</para></blockquote>
</sect2>
<sect2 id="tutorial-initialize">
<title>Initialize</title>
<para>
Shows how you use 'initialization' to 'destroy' scripts of main dialog to initialize and store some settings.
</para>
<blockquote><para>
Functions/concepts:
- initialization
- destroy
- readSetting
- writeSetting
</para></blockquote>
</sect2>
<sect2 id="tutorial-array">
<title>Array</title>
<para>
Shows how to use associative arrays to store and restore information
associated with container items.</para>
<blockquote><para>
Functions/concepts:
- @Array functions
</para></blockquote>
</sect2>
<sect2 id="tutorial-strings">
<title>Strings</title>
<para>
Shows how to use string-handling functions
Functions/concepts:
</para>
<blockquote><para>
- @String functions
- rich text editor
</para></blockquote>
</sect2>
<sect2 id="tutorial-tree">
<title>Tree</title>
<para>
Shows how to use tree widget
</para>
<blockquote><para>
- tree widget
- FileSelector
- initialization
- env
</para></blockquote>
</sect2>
<sect2 id="tutorial-widgets">
<title>Widgets</title>
<para>
Shows how to get widget information
</para>
<blockquote><para>
- type method
- children method
</para></blockquote>
</sect2>
<sect2 id="tutorial-statusbar">
<title>StatusBar</title>
<para>
Shows how to use statusbar widget
</para>
<blockquote><para>
- statusbar widget
- populate
</para></blockquote>
</sect2>
<sect2 id="tutorial-loop">
<title>Loop</title>
<para>
Shows how to use internal loops
</para>
<blockquote><para>
- for
- forEach
</para></blockquote>
</sect2>
<sect2 id="tutorial-calc">
<title>Calc</title>
<para>
Shows how to use @expr function to do some calculations
</para>
<blockquote><para>
- expr
- String.replace
</para></blockquote>
<note><para>The @expr() function is no longer required in the new parser as expressions can be directly interpreted anywhere you would logically want to use them.</para></note>
</sect2>
<sect2 id="tutorial-picview">
<title>Picview</title>
<para>
Shows how to use PixmapLabel widget using populate() function
</para>
<blockquote><para>
- PixmapLabel
- populate
- FileSelector
- slots/connections
</para></blockquote>
</sect2>
<sect2 id="tutorial-table">
<title>Table</title>
<para>
Shows how to use Table widget
</para>
<blockquote><para>
- insertRow
- insertColumn
- currentRow
- currentColumn
- setColumnCaption
- setRowCaption
- removeRow
- removeColumn
</para></blockquote>
</sect2>
</sect1>
<sect1 id="examples">
<title>Current Examples</title>
<para>
These examples reflect the most recent development state of &kommander;. In its current state &kommander; has few limitations for developing small to medium applications. It certainly is not suitable for building a KWord clone, but for a simple editor, database frontend, GUI for commandline programs or any application in the spirit of Unix/Linux small applications it is a good choice. The examples presented here are intended to show the potential as well as how to work around limitations. There are some useful tricks included in these if you want to do a more capable small application with &kommander;. Remember &kommander; is not intended to do everything, but to do most things. For this concession you should be able to build something in &kommander; faster than other alternatives ad add GUI to scripting languages not otherwise supported in KDE.
The examples are installed to <command>$KDEDIR/share/apps/kmdr-editor/editor</command>. In case you do not have them there, get from <ulink url="http://kommander.tdewebdev.org">our home page</ulink>, by downloading the latest release.
The little dialog that grew into a Mainwindow. As &kommander; does not have a native MainWindow widget it has been assumed it only does dialogs. In fact only dialogs are officially supported... but you can run MainWindows in &kommander;. This is an example editor. If you want to create a MainWindow application in &kommander; just open Qt Designer and make one, save it and rename the *.ui file to a *.kmdr file. Now open it in &kommander; and do what you would do normally.
</para>
<note><para>As of this writing what is known not to work on the &kommander; side is the settings read and write. There is no Initialize or Destroy section as there is no &kommander; Text, however there are signals for this on the window, so the functionality is intact. On the MainWindow side it is not possible to talk to any actions via DCOP as these are QActions from Designer and KActions are not derived from QActions in KDE 3.x. This means a DCOP call to list actions or set states will not work. It is also not possible to talk to the Statusbar. Also submenus on the menubar and dropdown actions on the Toolbar will not work. Even though this is not a &kommander; widget, or officicially supported, it seems suitable for many small application uses.</para></note>
<para>
There is a quick help dialog this editor launches that discusses in depth what is happening inside.
&kommander; can be used with databases and has an optional <ulink url="http://kommander.tdewebdev.org/releases.php#plugins">database plugin</ulink>. One shortcoming is not being able to store key/value pairs in the ComboBox. An ingenious trick was realized for this. It requires only that the content of the ComboBox not be changed unless it is done using the arrays that go with it. As this is commonly used with SQL in small data sets it's quite fast even to reload the whole Combobox. The inherent problem is that &kommander; does not have internally indexed arrays by default. This is compounded by the fact that to accommodate shell commands that return lines separated by newlines &kommander;'s array functions will load what is effectively an array of keys. Such an array can only be accessed with a foreach loop. This is the reason new indexed array functions were added. It is important to remember that these arrays are not self maintaining, but their insert and delete functions will help you.
Getting back to the ComboBox, it will return selected text, but it also will return the current index. It does rigidly maintain a contiguous zero based array. That's the key. We loop through a data set with a zero based index counter and create two arrays, as &kommander; also cannot create arrays of arrays. It can however use an array value to represent a key just like any value could. .If you look at the included dialog the code actually managing this is in <quote>ScriptObject36</quote>. We will extract the key code here.
</para>
<screen>
c = ListBox1.count-1
for i = 0 to c do
array_indexedFromString("x", ListBox1.item(i))
_a[x[0]] = x[1]
_b[i] = x[0]
ComboBox10.insertItem(_a[_b[i]], i)
end
</screen>
<para>
There is more going on, like checking for duplicate keys, but this is the core. You can right click on the ListBox and try menu items. The net result is that it is using keyed index by proxy and returning both the key and the value. Use this code if you want to be 100% certain your key/value relationship is accurate.
</para>
</sect2>
<sect2 id="kpart-demo">
<title>Kpart demo</title>
<para>
As of Kommander 1.3 Kommander automatically makes KParts using the libkommander_part.la. In addition to this there is a KPart plugin which allows Kommander to load plugins. Being curious developers we tried loading a Kommander part into Kommander. Why do that? Why not? The results were interesting and are demonstrated here. One interesting thing is the parent part can directly access all of the child part. While this is handy it has a down side. Any child widget being called with the same name as a parent widget will cause a lock up! In addition to that the DCOP interface is generated all over again for the part which wipes out the parent interface and disables most of the old parser functionality as well as Kommander specific DCOP to the parent. This is too difficult to fix for the remaining life of the KDE3 version. Even with these limitations and cautions this can be useful, if used carefully. The example files to look at this are in the current examples as kpartmwframe.kmdr and kpartpart.kmdr. Remember you will need the KPart plugin to fully run this example.
</para>
<para>
You can also load KMail, KOrganizer and many other KDE applications right into Kommander, of course without the problems. KHTML and KDE's file manager widgets seem not to have some functionality but there is a special KHTML plugin if you really want to incorporate a browser.
</para>
</sect2>
<sect2 id="example-passed-params">
<title>passvariables.kmdr</title>
<para>
As of &kommander; 1.3 you can pass and return variables with scripts. This dialog demonstrates that. Look carefully at the content of the buttons. You will see that neither button directly writes to any of the LineEdit boxes receiving text from the script. While one is written directly from the script another is written with the content passed from the button. The third is not written at all but passed back in a return() function where it is received by the button and written. This is also shown on the right side using PHP so you can see how this might work with Python, Ruby, Perl or even a less commonly used language like Rexx. Languages that Speak DCOP can do a lot more in &kommander; too. The point of this demo is the freedom provided. &kommander; does not have functions, yet it does. Create a script, declare some globals if you like, pass some parameters to another script and return a value. For an intentionally simplified GUI scripting tool that is capable behavior. This behavior is only in the new parser and is documented <link linkend="passargs">here</link>.
</para>
</sect2>
<sect2 id="tableselect">
<title>tableselect.kmdr</title>
<para>
This example demonstrates how to use the new select function in the table widget. It is now possible to get four coordinates to enable a block selection. This also shows how it would have had to be done prior to this function. and how to use the parameters passed to a script. In addition this demonstrates a simple block copy and paste function for a table as well as summation of a block.