Chapter 17. Providing Online Help

Providing Online Help

Most applications provide their users with online help. Some help is short, such as tooltips, status tips, and “What’s This?” help. Naturally, Qt supports all of these. Other help can be much more extensive, involving many pages of text. For this kind of help, you can use QTextBrowser as a simple online help browser, or you can invoke Qt Assistant or an HTML browser from your application.

Tooltips, Status Tips, and “What’s This?” Help

A tooltip is a small piece of text that appears when the mouse hovers over a widget for a certain period of time. Tooltips are presented with black text on a yellow background. Their primary use is to provide textual descriptions of toolbar buttons.

We can add tooltips to arbitrary widgets in code using QWidget::setToolTip(). For example:

findButton->setToolTip(tr("Find next"));

To set the tooltip of a QAction that could be added to a menu or a toolbar, we can simply call setToolTip() on the action. For example:

newAction = new QAction(tr("&New"), this);
newAction->setToolTip(tr("New document"));

If we don’t explicitly set a tooltip, QAction will automatically use the action text.

A status tip is also a short piece of descriptive text, usually a little longer than a tooltip. When the mouse hovers over a toolbar button or a menu option, a status tip appears in the status bar. Call setStatusTip() to add a status tip to an action or to a widget:

newAction->setStatusTip(tr("Create a new document"));

Figure 17.1 shows a tooltip and a status tip in an application.

An application showing a tooltip and a status tip

Figure 17.1. An application showing a tooltip and a status tip

In some situations, it is desirable to provide more information about a widget than tooltips or status tips can give. For example, we might want to provide a complex dialog with explanatory text about each field without forcing the user to invoke a separate help window. “What’s This?” mode is an ideal solution for this. When a window is in “What’s This?” mode, the cursor changes to An application showing a tooltip and a status tip and the user can click on any user interface component to obtain its help text. To enter “What’s This?” mode, the user can either click the ? button in the dialog’s title bar (on Windows and KDE) or press Shift+F1.

Here is an example of “What’s This?” text set on a dialog:

dialog->setWhatsThis(tr("<img src=":/images/icon.png">"
                        "&nbsp;The meaning of the Source field depends "
                        "on the Type field:"
                        "<ul>"
                        "<li><b>Books</b> have a Publisher"
                        "<li><b>Articles</b> have a Journal name with "
                        "volume and issue number"
                        "<li><b>Theses</b> have an Institution name "
                        "and a Department name"
                        "</ul>"));

We can use HTML tags to format “What’s This?” text. In the example shown in Figure 17.2, we include an image (which is listed in the application’s resource file), a bulleted list, and some text in bold. The tags and attributes that Qt supports are specified at http://doc.trolltech.com/4.3/richtext-html-subset.html.

A dialog showing “What’s This?” help text

Figure 17.2. A dialog showing “What’s This?” help text

When we set “What’s This?” text on an action, the text will be shown when the user clicks the menu item or toolbar button or presses the shortcut key while in “What’s This?” mode. When the user interface components of an application’s main window provide “What’s This?” text, it is customary to provide a What’s This? option in the Help menu and a corresponding toolbar button. This can be done by creating a What’s This? action with the static QWhatsThis::createAction() function and adding the action it returns to a Help menu and to a toolbar. The QWhatsThis class also provides static functions to programmatically enter and leave “What’s This?” mode.

Using a Web Browser to Provide Online Help

Large applications may require more online help than tooltips, status tips, and “What’s This?” help can reasonably show. A simple solution to this is to provide the help text in HTML format and launch the user’s web browser at the appropriate page.

Applications that include a help browser typically have a Help entry in the main window’s Help menu and a Help button in every dialog. In this section, we will show how to use the QDesktopServices class to provide the functionality for these buttons.

The application’s main window will typically have a help() slot that is called when the user presses F1 or clicks the Help|Help menu option.

void MainWindow::help()
{
    QUrl url(directoryOf("doc").absoluteFilePath("index.html"));
    url.setScheme("file");
    QDesktopServices::openUrl(url);
}

In this example, we assume that our application’s HTML help files are in a subdirectory called doc. The QDir::absoluteFilePath() function returns a QString with the full path to the given file name. We begin by creating a QUrl object with the path to the help file. Since this is help for the main window, we use our help system’s index.html file from which all the other help files are accessible through hyperlinks. Next, we set the URL’s scheme to “file” so that the file we have set will be looked for in the local file system. Finally, we use the desktop services’ openUrl() static convenience function to launch the user’s web browser.

We do not know which web browser will be used, so we must be careful to make our HTML valid and compatible with the browsers that our users might be using. Most web browsers will set their local working directory to the URL’s path, and will therefore assume that any images and hyperlinks that do not have absolute paths have the working directory as their root. All this means is that we must put all our HTML files and image files in our doc directory (or subdirectories under it) and make all our references relative, except for links to external web sites.

QDir MainWindow::directoryOf(const QString &subdir)
{
    QDir dir(QApplication::applicationDirPath());

#if defined(Q_OS_WIN)
    if (dir.dirName().toLower() == "debug"
            || dir.dirName().toLower() == "release")
        dir.cdUp();
#elif defined(Q_OS_MAC)
    if (dir.dirName() == "MacOS") {
        dir.cdUp();
        dir.cdUp();
        dir.cdUp();
    }
#endif
    dir.cd(subdir);
    return dir;
}

The static directoryOf() function returns a QDir corresponding to the specified subdirectory relative to the application’s directory. On Windows, the application’s executable usually lives in a debug or release subdirectory, in which case we move one directory up; on Mac OS X, we take the bundle directory structure into account.

For dialogs, we will normally want to launch the web browser at a specific page from within our help system’s pages, and perhaps at a specific point within the page. For example:

void EntryDialog::help()
{
    QUrl url(directoryOf("doc").absoluteFilePath("forms.html"));
    url.setScheme("file");
    url.setFragment("editing");
    QDesktopServices::openUrl(url);
}

This slot is called from inside a dialog when the user clicks the dialog’s Help button. It is very similar to the previous example, except that we have chosen a different starting page. This particular page has help text for several different forms, with anchor references (e.g., <a name="editing">) in the HTML to indicate where each form’s help text begins. To access a particular place within a page, we call setFragment() and pass the anchor we want the page scrolled to.

Providing help files in HTML format and making them available to users via their own web browser is simple and convenient. But web browsers cannot access the application’s resources (such as icons), and they cannot easily be customized to suit the application. Also, if we jump to a particular page as we did for the EntryDialog, clicking the browser’s Home or Back button will not have the desired effect.

Using QTextBrowser as a Simple Help Engine

Using the user’s web browser to show online help is easy to do, but as we have noted, the approach does have a few drawbacks. We can eliminate these problems by providing our own help engine based on the QTextBrowser class.

In this section, we present the simple help browser shown in Figure 17.3 and explain how it can be used within an application. The window uses a QTextBrowser to display help pages that are marked up with an HTML-based syntax. QTextBrowser can handle a lot of HTML tags, so it is ideal for this purpose.

The HelpBrowser widget

Figure 17.3. The HelpBrowser widget

We begin with the class definition:

class HelpBrowser : public QWidget
{
    Q_OBJECT

public:
    HelpBrowser(const QString &path, const QString &page,
                QWidget *parent = 0);

    static void showPage(const QString &page);

private slots:
    void updateWindowTitle();

private:
    QTextBrowser *textBrowser;
    QPushButton *homeButton;
    QPushButton *backButton;
    QPushButton *closeButton;
};

The HelpBrowser provides a static function that can be called from anywhere in the application. This function creates a HelpBrowser window and shows the given page.

Here’s the constructor:

HelpBrowser::HelpBrowser(const QString &path, const QString &page,
                         QWidget *parent)
    : QWidget(parent)
{
    setAttribute(Qt::WA_DeleteOnClose);
    setAttribute(Qt::WA_GroupLeader);

    textBrowser = new QTextBrowser;

    homeButton = new QPushButton(tr("&Home"));
    backButton = new QPushButton(tr("&Back"));
    closeButton = new QPushButton(tr("Close"));
    closeButton->setShortcut(tr("Esc"));

    QHBoxLayout *buttonLayout = new QHBoxLayout;
    buttonLayout->addWidget(homeButton);
    buttonLayout->addWidget(backButton);
    buttonLayout->addStretch();
    buttonLayout->addWidget(closeButton);

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addLayout(buttonLayout);
    mainLayout->addWidget(textBrowser);
    setLayout(mainLayout);

    connect(homeButton, SIGNAL(clicked()), textBrowser, SLOT(home()));
    connect(backButton, SIGNAL(clicked()),
            textBrowser, SLOT(backward()));
    connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
    connect(textBrowser, SIGNAL(sourceChanged(const QUrl &)),
            this, SLOT(updateWindowTitle()));

    textBrowser->setSearchPaths(QStringList() << path << ":/images");
    textBrowser->setSource(page);
}

We set the Qt::WA_GroupLeader attribute because we want to pop up HelpBrowser windows from modal dialogs in addition to the main window. Modal dialogs normally prevent the user from interacting with any other window in the application. However, after requesting help, the user must obviously be allowed to interact with both the modal dialog and the help browser. Setting the Qt::WA_GroupLeader attribute makes this interaction possible.

We provide two search paths, the first a path in the file system that contains the application’s documentation, and the second the location of the image resources. The HTML can include references to images in the file system in the normal way and references to image resources by using a path that begins with :/ (colon slash). The page parameter is the name of the documentation file, with an optional HTML anchor.

void HelpBrowser::updateWindowTitle()
{
    setWindowTitle(tr("Help: %1").arg(textBrowser->documentTitle()));
}

Whenever the source page changes, the updateWindowTitle() slot is called. The documentTitle() function returns the text specified in the page’s <title> tag.

void HelpBrowser::showPage(const QString &page)
{
    QString path = directoryOf("doc").absolutePath();
    HelpBrowser *browser = new HelpBrowser(path, page);
    browser->resize(500, 400);
    browser->show();
}

In the showPage() static function, we create the HelpBrowser window and then show it. The window will be destroyed automatically when the user closes it, since we set the Qt::WA_DeleteOnClose attribute in the HelpBrowser constructor. For this example, we assume that the documentation is located in the application’s doc directory. All the pages passed to the showPage() function will be taken from this subdirectory.

Now we are ready to invoke the help browser from the application. In the application’s main window, we would create a Help action and connect it to a help() slot that could look like this:

void MainWindow::help()
{
    HelpBrowser::showPage("index.html");
}

This assumes that the main help file is called index.html. For dialogs, we would connect the Help button to a help() slot that might look like this:

void EntryDialog::help()
{
    HelpBrowser::showPage("forms.html#editing");
}

Here we look in a different help file, forms.html, and scroll the QTextBrowser to the editing anchor.

It is also possible to use Qt’s resource system to embed the help files and their associated images directly into the executable. The only changes required to achieve this are to add entries to the application’s .qrc file for each file we want embedded and to use the resource path (e.g., :/doc/forms.html#editing).

In this example, we used both approaches, embedding the icons (since they are also used by the application itself), but keeping our HTML files in the file system. This has the advantage that the help files can be updated independently of the application, and yet are guaranteed to be able to find the application’s icons.

Using Qt Assistant for Powerful Online Help

Qt Assistant is a redistributable online help application supplied by Trolltech. Its main virtues are that it supports indexing and full text search and that it can handle documentation sets for multiple applications. To make use of Qt Assistant, we must incorporate the necessary code in our application, and we must make Qt Assistant aware of our documentation.[*]

Communication between a Qt application and Qt Assistant is handled by the QAssistantClient class, which is located in a separate library. To link this library with an application, we must add this line to the application’s .pro file:

CONFIG += assistant

We will now review the code of a new HelpBrowser class that uses Qt Assistant.

class HelpBrowser
{
public:
    static void showPage(const QString &page);

private:
    static QDir directoryOf(const QString &subdir);

    static QAssistantClient *assistant;
};

Here’s the new showPage() implementation:

QAssistantClient *HelpBrowser::assistant = 0;

void HelpBrowser::showPage(const QString &page)
{
    QString path = directoryOf("doc").absoluteFilePath(page);
    if (!assistant)
         assistant = new QAssistantClient("");
         assistant->showPage(path);
}

The QAssistantClient constructor accepts a path string as its first argument, which it uses to locate the Qt Assistant executable. By passing an empty path, we signify that QAssistantClient should look for the executable in the PATH environment variable. QAssistantClient has a showPage() function that accepts a page name with an optional HTML anchor.

The next step is to prepare a table of contents and an index for the documentation. This is done by creating a Qt Assistant profile and writing a .dcf file that provides information about the documentation. All this is explained in Qt Assistant’s online documentation, so we will not duplicate that information here.

An alternative to using a web browser, QTextBrowser, or Qt Assistant is to use platform-specific approaches to providing online help. For Windows applications, it might be desirable to create Windows HTML Help files and to provide access to them using Microsoft Internet Explorer. You could use Qt’s QProcess class or the ActiveQt framework for this. On Mac OS X, Apple Help provides similar functionality to Qt Assistant.

We have now reached the end of Part II. The chapters that follow in Part III cover more advanced and specialized features of Qt. The C++ and Qt code they present are no more difficult than the code we have presented in Part II, but some of the concepts and ideas may be more challenging in those areas that are new to you.



[*] Qt 4.4 is expected to feature a revamped help system, which will make it easier to integrate our documentation.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset