Adding WhatsThis Help To KDE Applications

A Non-Programmer's Guide to Participating in KDE, Part 1

En Español

This is the first installment of the Non-Programmer's Guide to Participating in KDE series. It is designed to aide those who would like to participate in the KDE project, but for one reason or another can't do so by contributing source code. Fortunately, there are many tasks in KDE that don't involved writing code, and many of them don't require much investment in the way of time, either.

Writing WhatsThis help is one quick and easy way to get involved with KDE development. Since no coding skills are required and it takes just minutes to do, it is an effective and simple way for anyone who wishes to help KDE become the best desktop available.

Table of Contents

  1. What is "WhatsThis"?
  2. Preparing For WhatsThis Spelunking
  3. Target Alpha: KGpg
  4. Getting Your Changes Accepted Into KDE
  5. Using The Source, or... Going Where No UI File Has Gone Before
  6. And They WhatsThis'd Happily Ever After
  7. Footnotes

What is "WhatsThis"?

Example of WhatsThis Help
A dialog showing WhatsThis help for one of its widgets

WhatsThis help is essentially an on-demand, extended tooltip associated with a specific widget1. It tends to be more verbose than a tooltip, but more succinct and specific than a full-blown help manual. To access WhatsThis help, the user clicks on the WhatsThis button in the window's title bar (usually a question mark) or presses the WhatsThis keyboard shortcut (usually Shift-F1) and then clicks on a widget to display it's associated WhatsThis help.

Such a convenient way to get a explanations of specifics part of an interface can be quite a boon to users trying to understand how to use it. Unfortunately, if you go looking for WhatsThis help in KDE, you'll notice that many widgets lack WhatsThis help. This is because developers often tend to overlook the need for documentation due to time constraints, interest and other factors. WhatsThis help is best added when an interface is deemed "finished" since the context-sensitive WhatsThis entries need to change as the interface changes. The good news is that it's fairly trivial to add WhatsThis help, even if you aren't a programmer.

Preparing For WhatsThis Spelunking

Before we can get started added WhatsThis help to an interface, we first need to do some prep work. In particular, we need the newest, most up-to-date version of the interface in question available. For KDE applications, this means getting the code from SVN2. We won't need a special account, nor do we need to compile the code. We don't even need all of the KDE source just to work on one particular interface. This means we don't need to worry about compilers, dependencies, configuration or using lots of disk space. Huzzah!

Looking through the various utilities that come with KDE, you may notice that the KDE archiving and compression tool ark is almost entirely devoid of WhatsThis help. The KDE GnuPG tool, creatively named kgpg, is also in need of some WhatsThis help. These two applications look like a good place to start our exploration of WhatsThis help. So let's start by checking out the kdeutils SVN module, which is where both of these applications live:

user@locahost:~> svn co svn://anonsvn.kde.org/home/kde/trunk/KDE/kdeutils
A  kdeutils/kdessh
A  kdeutils/kdessh/kdessh.cpp
A  kdeutils/kdessh/sshdlg.cpp
A  kdeutils/kdessh/Makefile.am

To find where other applications exist in KDE's SVN repository, you can visit the KDE SVN web interface or use the svn ls command locally. For more detailed information on working with SVN and KDE, visit the KDE anonymous SVN documentation.

Target Alpha: KGpg

KGpg is a new application in the KDE distribution as of version 3.2 and it does have WhatsThis entries for some of its widgets. But unless the WhatsThis support is comprehensive, users won't trust it to be there when they need it and so won't bother trying to use it. For the purpose of this tutorial, we're going to focus on one particular part of the interface: the General tab of the KGpg configuration dialog.

KGpg Config UI
kdeutils/kgpg/conf_ui.ui as displayed in Qt Designer

Having already checked out the kdeutils module, a quick directory listing will show that there is a kgpg directory within it. In that directory are several files ending with the .ui extension. These are XML files that contain the layouts of various parts of KGpg's interface. They can be editted by hand if necessary, but it is usually preferred to use Qt Designer.

Designer is a WYSIWIG user interface designer, sort of like Photoshop for programmers. Designer is often packaged with the Qt development packages since it isn't necessary to compile or run Qt or KDE applications. Opening a UI file in Qt Designer will show what that interface looks like. When we open up the kdeutils/kgpg/conf_ui.ui file we see one of the configuration pages in a small window. We can now edit it directly from here.

KGpg Config UI
Widget properties tool window in Designer
We'll start by clicking on the "Start KGpg automatically at login" checkbox widget. Familiar resize handles will appear around the widget, showing that it is selected. Looking at the toolbox windows, we'll see one labelled "Property Editor/Signal Handlers". This box contains alls sorts of details on the selected widget, including the WhatsThis help. Scrolling to the bottom of the list will show an entry clearly labelled "whatsThis". Click on the right-hand column will bring up a line edit along with two little buttons. The button with an elipsis in it brings up a nice editor window when clicked; the button with a left-turning arrow will revert to the default WhatsThis (which is nothing). While we can enter text directly into the supplied text box, it's usually more convenient to use the editor window, and so we click on the elipsis button.

From here, it's pretty straightforward. We simply type in a message and we're done! We can spruce up the text a bit by using basic HTML tags for bold, italic, unerline, and more. The menus and toolbar in the WhatsThis Edit Text window makes using these tags a breeze.

Tip When using HTML tags in WhatsThis text, wrap the entire thing between <qt> and </qt> tags. This will ensure that when Qt shows the WhatsThis help to the user, it will show it properly as HTML text.

Remember to keep the text as clear and succinct as possible. The aim is to help the user rather than confuse them. Don't include references to other widgets in the interface unless they are absolutely linked to each other. To ensure accuracy, try the application out to see exactly what that element of the interface does. Double checking the spelling and grammar is often a good idea, as well. Nobody's perfect, but a little due dilligence can go a long way.

Tip When adding WhatsThis help to a widget that also has a descriptive text label next to it, remember to add the exact same WhatsThis help to it. The user may click on the label or the widget, and Qt doesn't automatically sync the WhatsThis help for us.

Once we've added WhatsThis help to all the items in the interface, we select Save from the File menu to save our changes. We then repeat the process for each UI file in the application's directory and we're done! Easy as pie!

Getting Your Changes Accepted Into KDE

Once we are finished adding WhatsThis help in Designer, it's time to generate a patch. First we make sure that our version of the files are synced with the main SVN repository. This is accomplished by doing a SVN update from the application's directory:

user@localhost:~/kdeutils/kgpg> svn up
? dcopiface.kidl
? dcopiface_skel.cpp
? groupedit.cpp
? groupedit.h
P ChangeLog
M conf_ui.ui
P kgpgview.cpp
We can ignore the files with question marks in front of them: they aren't in SVN. The files with a 'P' (or a 'U') in front of them had changed on the SVN server since we last updated, and SVN has now merged those changes into our local copy. Files with an 'M' in front of them have been changed locally. We want to separate those changes into a "diff" (which is short for "difference") file that can then be used as a patch. We accomplish this by doing:
user@localhost:~/kdeutils/kgpg> svn diff > kgpg.diff

Tip In the kdesdk (or KDE Software Developers Kit) package there is a program called cervisia which is a graphical SVN client. Instead of using the command line SVN client, you can use cervisia to do updates, patches and more. Cervisia can be run as a stand-alone application or directly from Konqueror. Consult the cervisia manual for further information on using it.

If all went well, we now have a file called kgpg.diff. We can now email this to the maintainer of the application. You can usually find the maintainer in the About box for the application, or in the AUTHORS file included with the source code, or by looking at the license clauses at the top of source files, or by asking on IRC or a mailing list. If the maintainer doesn't respond within a reasonable period of time (usually a 7-10 days), they may be busy or not maintaining the application in SVN anymore. In that case, send the patch to the KDE development email list (kde-devel at kde dot org).

Tip After a certain point in the KDE release cycle, no changes to user visible text (or "strings", as the developers usually call them) are allowed. This is to ensure that translators have enough time to translate all the strings in KDE, which they can't effectively do when they are still changing in SVN. Consult the onlie KDE release schedule to find out when the string freeze goes into effect.

Using The Source, or... Going Where No UI File Has Gone Before

Having accomplished our mission with KGpg, we now turn our eyes to Ark. But when we look in the kdeutils/ark/ directory, to our horror we discover that there are no UI files in sight! This means we'll have to delve into the source code itself. But don't worry just yet. While this takes a bit more effort than using Designer, it's still relatively easy and doesn't require much in the way of special knowledge. However, if you really don't want to get your hands too dirty or wish to first master adding WhatsThis via Designer you can skip right to the end. You can always come back later. Otherwise, onward into the belly of the beast...

The Ark Extract Dialog
The Ark Extract Dialog

The first step is to run the program and check through it's various dialogs and windows for WhatsThis coverage. It's usually easiest to do one dialog or window at a time. Of course, this means we need a relatively recent version of the application to work from. If the application hasn't changed much, we may be able to get away with running the version that shipped with the last stable KDE release. If it's undergoing development, however, we'll most likely need to compile it from the source code we've checked out of SVN3.

Looking through Ark's interface, we come across it's Extract dialog. There is no WhatsThis help at all in this dialog! That simply won't do. But where to begin? Our first clues are the bits of text that are visible: "Extract to:", "Files to be Extracted", etc. We'll use those strings to find where in the code this interface is defined. From the kdeutils/ark/ directory, we'll do this4:

user@localhost:~/kdeutils/ark> grep -in "Files to be Extracted" *cpp
arkwidget.cpp:1500 // list of files to be extracted
arkwidgetpart.cpp:370 // list of files to be extracted
extractdlg.cpp:110 bg->setTitle( i18n( "Files to Be Extracted" ) );
A-ha! The last file that our grep command listed looks to be the winner!

Tip To find text that has a keyboard shortuct such as "Extract here (where the letter "x" is the keyboard shortcut), place an ampersand in front of the underlined letter like this: "E&xtract here". If there is an ampersand in the text, substitute it with two ampersands.

Opening up kdeutils/ark/extractdlg.cpp in our text editor and going to line 110 we see this:

bg->setTitle( i18n( "Files to Be Extracted" ) );
and if we go down a few lines we'll see the radio buttons:
m_radioCurrent = new QRadioButton( bg, "m_radioCurrent" );
m_radioCurrent->setText( i18n( "Current" ) );
Layout2->addWidget( m_radioCurrent );

m_radioAll = new QRadioButton( bg, "m_radioAll" );
m_radioAll->setText( i18n( "All" ) );
Layout2->addWidget( m_radioAll );

m_radioSelected = new QRadioButton( bg, "m_radioSelected" );
m_radioSelected->setText( i18n( "Selected files" ) );
Layout2->addWidget( m_radioSelected );

Now that we have found the code, adding our WhatsThis help is pretty simple. But first we have to take care of some C++ bookkeeping. Near the top of the file we'll likely see a bunch of lines starting with #include. In kdeutils/ark/extractdlg.cpp we find several such lines, including this series:

#include <qbuttongroup.h>
#include <qlabel.h>
#include <qapplication.h>
#include <qlayout.h>
We need to look for one that references qwhatsthis.h. If we don't find such a line (and in this case we don't), we'll need to add it something like this:
#include <qbuttongroup.h>
#include <qlabel.h>
#include <qapplication.h>
#include <qlayout.h>

#include <qwhatsthis.h>
Try and keep the new #include near other similar lines, preferably with other Qt headers. You can spot the Qt headers since they all begin with a 'q'.

Back to the code starting on line 110 (now line 111 due to our #include addition), note the lines that contain new QRadioButton. Each of those lines is making a radio button and assigning it to a "variable". In this case, the variable name of the radio button that says "Current" is "m_radioCurrent". Not too hard so far. Now to add some WhatsThis:

m_radioCurrent = new QRadioButton( bg, "m_radioCurrent" );
m_radioCurrent->setText( i18n( "Current" ) );
Layout2->addWidget( m_radioCurrent );

QWhatsThis::add( m_radioCurrent,
i18n( "Selecting this option will cause only the last "
"selected file to be extracted." ) );
m_radioCurrent = new QRadioButton( bg, "m_radioCurrent" );
m_radioCurrent->setText( i18n( "Current" ) );
m_radioAll = new QRadioButton( bg, "m_radioAll" );
m_radioAll->setText( i18n( "All" ) );
Layout2->addWidget( m_radioAll );

QWhatsThis::add( m_radioAll,
i18n( "Selecting this option will cause all files in the "
" archive to be extracted." ) );
m_radioCurrent = new QRadioButton( bg, "m_radioCurrent" );
m_radioCurrent->setText( i18n( "Current" ) );
m_radioSelected = new QRadioButton( bg, "m_radioSelected" );
m_radioSelected->setText( i18n( "Selected files" ) );
Layout2->addWidget( m_radioSelected );

QWhatsThis::add( m_radioSelected,
i18n( "Selecting this option will cause all the files "
"you selected in the archive to be extracted." ) );

As you can see, all we added were a few lines of very simple code. To add a WhatsThis item we use the QWhatsThis::add method, which has the following syntax:

QWhatsThis::add( widget, i18n( "WhatsThis text") );
The widget is the widget variable such as m_radioCurrent. The WhatsThis text is, as you may have already guessed, the text of the WhatsThis help to be shown for the corresponding widget. Don't forget the i18n part as that marks the string for translation. So far, so simple, but there are a few wrinkles yet ahead.

In the Extract dialog, there is an "Extract to:" label that is in front of a file location widget. When we search kdeutils/ark/extractdlg.cpp for "Extract to:" we find the following code:

extractToLabel->setText( i18n( "Extract to:" ) );
Layout3->addWidget( extractToLabel );

m_extractDirCB = new KHistoryCombo( true, mainFrame, "m_extractDirCB" );
Even if we aren't familiar with C++ or KDE syntax, using a bit of best-guess-ology we can probably deduce that extractToLabel is the visible text and m_extractDirCB is the text edit. And we'd be right. Our WhatsThis code might end up looking something like this:
extractToLabel->setText( i18n( "Extract to:" ) );
Layout3->addWidget( extractToLabel );

QString whatsThis = i18n( "<qt>Enter the location you wish to extract the "
"files to in the provided text area. You can click on "
"the file button to bring up a file dialog.<p>"
"<Tip:> In addition to local file paths, you may "
"use any URL that allows saving of files, such as "
"ftp and fish (ssh file transfer) URLs.</qt>" );
QWhatsThis::add( extractToLabel, whatsThis );
m_extractDirCB = new KHistoryCombo( true, mainFrame, "m_extractDirCB" );
QWhatsThis::add( m_extractDirCB, whatsThis );
Note that we added the WhatsThis help to both the text label as well as the file location widget. We also used a bit of a trick to make it so that we didn't have to enter the WhatsThis twice in the code: we created a QString. A QString is simply a way to store text in a KDE application. Note we simply said QString whatsThis and then assigned to it (using the equals sign) the familiar-looking i18n-wrapped text. We could reuse the whatsThis QString again later on in the same block of source code if we want. If we do this, we don't need to say QString whatsThis = again, just whatsThis =. A "block" of code is any section of code that is enclosed in "curly braces": { and }. Also note that all variables must have unique names, so we couldn't use the name "whatsThis" if it was already used. We don't need to worry too much about it here, since the name "whatsThis" is probably unique if the code doesn't use WhatsThis help, and if it is a problem the compiler will tell us about it soon enough.

Besides the details of actually inserting new WhatsThis into the code, it's important to remember the wants and needs of the person(s) who maintain this code. Most developers don't like overly long lines, with many even preferring the lines to be kept to under 80 characters long. So make sure to keep your lines short, wrapping long WhatsThis text on several lines. However, in C and C++ string can't span multiple lines. For instance this is illegal:

QWhatsThis::add(m_radioCurrent,
i18n( "Selecting this option will cause only the last
selected file to be extracted." ) );
while this is perfectly fine:
QWhatsThis::add(m_radioCurrent,
i18n( "Selecting this option will cause only the last "
"selected file to be extracted." ) );
Notice how the there is an opening and closing quotation mark on each line. It is also required that you use double quotes (") rather than single quotes (') or tick marks (`). Don't forget to end the statement with a semicolon (;). If the use of a quotation mark within the WhatsThis help is desired, preface it with a backslash like this: i18n( "Here we will use a \"quotation mark or two\"" )

Also pay attention to the formatting style used in the source code. Most developers are very picky about this, but there is no single agreed upon standard formatting style. Some use tabs, some use space; some indent 2 spaces, some 4, some 8. The permutations are nearly endless. Just try and make the lines you add look as similar as the surrounding code as possible.

The last step is to try and compile the application to ensure we haven't introduced any compile errors. Once we've confirmed it compiles and have run it to see our new WhatsThis in action, we can create a diff to email to the maintainer just as we did when editting UI files.

Tip When compiling, you may get errors about i18n being undefined. If you do get this error, add the following line with the other #include lines at the top of the file:
#include <klocale.h>

And They WhatsThis'd Happily Ever After

Congratulations! You've made it all the way through to the end! If you have questions, please join us on IRC on the freenode.net network (#kde-devel on irc.kde.org:6667 or irc.freenode.net:6667) or email a development list or (as a last resort only, please) the author. If you have any comments on the tutorial itself (e.g. you find an error, or if you feel it could be made clearer in some specific way) please email the author without delay.

Have a great time adding WhatsThis support all over KDE, and we'll meet up again in the next tutorial on the exciting topic of Bug Triage!

Footnotes

(1) Widget: A "widget" is an individual control or display in the user interface. Examples of widgets include text labels, scrollbars, menubars, menus, pushbuttons, radio buttons, checkboxes, listboxes, etc.
Back to the article...
(2) SVN: SVN stands for Subversion.  It is similiar to the concurrent versioning system. It provides a way for multiple people to work on a common set of documents. The KDE project uses SVN extensively to coordinate development efforts, and is available for all major operating systems. On UNIX-like systems, the SVN software package is usually found grouped with other developer's tools. If you don't have the svn command on your system, consult your operating system manuals on how to install new software.
Back to the article...
(3) Compiling SVN: Details on building KDE from SVN can be found at http://developer.kde.org/build/compile_cvs.html
Back to the article...
(4) grep: In the command used to search through ark's source code, we employed a few tricks. grep is the UNIX utility that is used to search for text in files. We passed in the flags -i to make the search case insensitive, limiting the odds of missing a match due to a simple typing error, and -n, which shows the line number in the file that matched. We also only search in files matching the pattern *cpp as files ending in cpp are C++ source files. Sometimes the source files will end in .cc instead, so watch out for that. Usually we don't need or want to search through header files (*.h) or binary files such as object code, libraries, READMEs and icons so just searching the source files is usually good enough.
Back to the article...

Aaron J. Seigo

About the Author...

Aaron J. Seigo is a KDE developer located in Calgary, Alberta, Canada. In addition to hacking on KDE, he works as a contact software developer and leads a relatively active life (for a hacker, anyways) with his family and friends. He welcomes Qt/KDE development work as well as chocolate, beer and other signs of appreciation. But no chocolate beer, please, as that stuff's just plain wrong. Or greeting cards; he's allergic to them.