Using the ViewKit ObjectPak Dialog Subclasses

This section describes the features of each ViewKit ObjectPak dialog subclass. In addition to specific member functions listed, each class also supports all functions provided by the VkDialogManager class.

Information Dialogs

The VkInfoDialog class supports standard OSF/Motif information dialogs. The global pointer to the information dialog manager, declared in <Vk/VkInfoDialog.h>, is theInfoDialog.

Use information dialogs to display useful information. Do not use information dialogs to display error messages, which should be handled by the VkErrorDialog, VkWarningDialog, or VkFatalErrorDialog class.

Because the message contained in an information dialog should not require any decision to be made by the user, information dialogs display only the OK button by default. If you need the user to make a selection, you should use another dialog class such as VkQuestionDialog.

VkInfoDialog does not provide any additional functions beyond those offered by the VkDialogManager.

Example 33. illustrates a simple example of posting an information dialog. Note that the window subclass that posts the dialog defines the dialog title and message as resource values.

Example 33. Posting an Information Dialog

Code

#include <Vk/VkWindow.h>
#include <Vk/VkInfoDialog.h>
class MailWindow: public VkWindow {
public:
MailWindow(const char*);
void newMail();
// ...
private:
static String _defaultResources[];
// ...
};
String MailWindow::_defaultResource[] = {
"*newMailMsg: You have new mail in your system mailbox.",
"*newMailTitle: New Mail",
NULL
};
MailWindow::MailWindow(const char *name) : VkSimpleWindow (name)
{
setDefaultResources( mainWindowWidget(), _defaultResources );
// ...
}
void MailWindow::newMail()
{
// ...
theInfoDialog->setTitle("newMailTitle");
theInfoDialog->post("newMailMsg");
// ...
}

Figure 27. shows the appearance of the resulting dialog.

Figure 27. Example of an Information Dialog

Warning Dialogs

The VkWarningDialog class supports standard OSF/Motif warning dialogs. The global pointer to the warning dialog manager, declared in <Vk/VkWarningDialog.h>, is theWarningDialog.

Use VkWarningDialog to warn the user of the consequences of an action. For example, VkWarningDialog is appropriate for warning the user that an action will irretrievably delete information.

By default, the dialogs posted by VkWarningDialog contain only an OK button; however, according to Open Software Foundation style guidelines, if you have posted a warning dialog to warn the user about an unrecoverable action, you must allow the user to cancel the destructive action. To add a Cancel button to your warning dialog, simply provide a cancel callback function when you post the dialog.


Hint: If you perform the action in the warning dialog's OK callback, you can simply define an empty function as a cancel callback. If the user clicks on the warning dialog's OK, button, the ok callback performs the action; if the user clicks on the Cancel button, ObjectPak dismisses the dialog without performing any action.



Note: VkWarningDialog does not provide any additional functions beyond those offered by the VkDialogManager.


Error Dialogs

The VkErrorDialog class supports standard OSF/Motif error dialogs. The global pointer to the error dialog manager, declared in <Vk/VkErrorDialog.h>, is theErrorDialog.

Invalid actions

Use VkErrorDialog to inform the user of an invalid action (such as entering out-of-range data) or potentially dangerous condition (for example, the inability to create a backup file).

The messages contained in the error dialogs should not require any decision to be made by the user. Therefore, the error dialogs display only the OK button by default. If you need the user to make a selection, you should use another dialog class such as VkQuestionDialog.

VkErrorDialog does not provide any additional functions beyond those offered by the VkDialogManager.

Fatal Error Dialogs

The VkFatalErrorDialog class supports an error dialog that terminates the application when the user dismisses it. The global pointer to the fatal error dialog manager, declared in <Vk/VkFatalErrorDialog.h>, is theFatalErrorDialog.

Use VkFatalErrorDialog only for those errors from which your program cannot recover. For example, VkFatalErrorDialog is appropriate if an application terminates because it cannot open a necessary data file. When the user acknowledges the dialog posted by VkFatalErrorDialog, the application terminates by calling VkApp::terminate() with an error value of 1. "Exiting ViewKit ObjectPak Applications" describes the terminate() function.

The messages contained in a fatal error dialog should not require any decision to be made by the user. Therefore, the fatal error dialog displays only the OK button by default.

VkFatalErrorDialog does not provide any additional functions beyond those offered by the VkDialogManager.

Busy Dialog

The VkBusyDialog class supports a busy dialog (also called a working dialog in OSF/Motif) that is displayed when the application is busy. The global pointer to the busy dialog manager, declared in <Vk/VkBusyDialog.h>, is theBusyDialog.

Unlike most other dialog classes, you should not directly post and unpost the busy dialog. VkBusyDialog is used by the VkApp object to display a busy dialog when you place the application in a busy state. The busy dialog is displayed automatically when you call VkApp::busy(), and dismissed automatically when you make a corresponding call to VkApp::notBusy(). VkApp also allows you to use the VkApp::setBusyDialog() function to use a busy dialog other than that provided by VkBusyDialog. Consult "Supporting Busy States" for more information about how VkApp handles busy states.

Because the busy dialog is intended to lock out user input during a busy state, by default the busy dialog does not display any buttons. If you want to allow the user to interrupt the busy state, you should use the VkApp::setBusyDialog() function to substitute the VkInterruptDialog class object for the normal busy dialog.

VkBusyDialog does not provide any additional functions beyond those offered by the VkDialogManager.

Interruptible Busy Dialog

The VkInterruptDialog class supports an interruptible busy dialog that you can substitute for the normal busy dialog. The dialog posted by the VkInterruptDialog class includes a Cancel button that the user can click on to cancel the current action. The global pointer to the interruptible busy dialog manager, declared in <Vk/VkInterruptDialog.h>, is theInterruptDialog.

In addition to those functions offered by the VkDialogManager class, VkInterruptDialog provides the wasInterrupted() member function:

Boolean wasInterrupted()

Applications that use VkInterruptDialog must periodically call wasInterrupted() to determine whether the user has clicked on the dialog's Cancel button since the last time the function was called. The period of time between checks is up to the application, which must weigh responsiveness against time spent checking.

Note that wasInterrupted() also calls VkApp::handlePendingEvents() to process any events that have occurred while the application was busy. Because checking for interrupts involves entering a secondary event loop for a short time, you should beware of any problems with re-entrant code in any callbacks that could be invoked.

Also note that you are responsible for performing any cleanup operations required by your application if the user interrupts a process before it is finished (that is, before you would normally call VkApp::notBusy() to end the busy state).

VkInterruptDialog also provides the ObjectPak callback VkInterruptDialog::interruptedCallback. This callback allows objects to register a member function to be called when the user selects the Cancel button of a VkInterruptDialog dialog. This callback can be called only if the application calls VkInterruptDialog::wasInterrupted().

Unlike most other dialog classes, you should not directly post and unpost the interruptible busy dialog. You can use the VkApp::setBusyDialog() function to instruct the VkApp object to use the interruptible busy dialog rather than the normal busy dialog provided by the VkBusyDialog class. The following line shows how you could do this in a program:

theApplication->setBusyDialog(theInterruptDialog);

The following line instructs the VkApp object to revert back to the normal busy dialog:

theApplication->setBusyDialog(NULL);

If you instruct the VkApp object to use the interruptible busy dialog, it is displayed automatically when you call VkApp::busy(), and dismissed automatically when you make a corresponding call to VkApp::notBusy(). Consult "Supporting Busy States" for more information about how VkApp handles busy states.

The code fragment in Example 34. installs the interruptible busy dialog and performs a simulated lengthy task, checking for interrupts periodically. After completing the task, the code reinstalls the normal busy dialog.

Example 34. Using the Interruptible Busy Dialog

Code

int i;
// Install the interruptible dialog as the dialog
// to post when busy
theApplication->setBusyDialog(theInterruptDialog);
// Start being "busy"
theApplication->busy("Very Busy", (BusyWindow *) clientData);
for(i=0; i<10000; i++)
{
// Every so often, see if the task was interrupted
if( theInterruptDialog->wasInterupted() )
{
break; // kick out of current task if user interrupts
}
sleep(1);
}
// Task done, so we"re not busy anymore
theApplication->notBusy();
// Restore the application's busy dialog as the default
theApplication->setBusyDialog(NULL);

Question Dialog

The VkQuestionDialog class supports standard OSF/Motif question dialogs. These allow the user to select among simple choices by clicking on pushbuttons. The global pointer to the question dialog manager, declared in <Vk/VkQuestionDialog.h>, is theQuestionDialog.

As described in "Posting Dialogs" , the post(), postModal(), and postBlocked() functions allow you to specify callback functions to be executed when the user clicks on the OK, Cancel, or Apply button. These callbacks apply only to the dialog posted by the current function call; they do not affect any subsequent dialog postings. You can also provide client data that is passed to all of the callbacks. Following ObjectPak conventions as described in "Using Xt Callbacks with Components" , you should normally pass the this pointer as client data so that the callback functions can retrieve the pointer, cast it to the expected component type, and call a corresponding member function.

For the postAndWait() function, instead of providing callbacks, you simply pass a Boolean value for each button specifying whether or not it is displayed. Unlike the other posting functions, the value returned by postAndWait() is an enumerated constant of type VkDialogReason (defined in VkDialogManager). This value is CANCEL, OK, or APPLY, corresponding to the button the user clicked on.

By default, VkQuestionDialog displays only the OK and Cancel buttons. VkQuestionDialog displays the Apply button only if you provide a callback for that button.

VkQuestionDialog does not provide any additional functions beyond those offered by the VkDialogManager.

Prompt Dialog

The VkPromptDialog supports standard OSF/Motif prompt dialogs that allow the user to enter a text string. The global pointer to the prompt dialog manager, declared in <Vk/VkPromptDialog.h>, is thePromptDialog.

You can use VkPromptDialog any time you need to prompt the user to enter a single piece of information. If you need the user to enter more than one value, you should consider whether it is more appropriate to create a preference dialog as described in Chapter 8--Preference Dialogs. Another option is to create your own custom dialog using VkGenericDialog (refer to "Deriving New Dialog Classes Using the Generic Dialog" .)

By default, VkPromptDialog displays only the OK and Cancel buttons. VkPromptDialog displays the Apply button only if you provide a callback for that button.

One method of obtaining the prompt dialog's text string is to extract it, and use it in the OK callback function (and the apply callback function if you provide one). Example 35. demonstrates this technique.

Example 35. Extracting the Text String from a Prompt Dialog

Code

void MailWindow::okCallback(Widget w, XtPointer, clientData, XtPointer callData)
{
MailWindow *obj = (MailWindow *) clientData;
obj->ok(w, callData);
}
void MailWindow::ok(Widget dialog, XtPointer callData);
{
char *_text;
XmSelectionBoxCallbackStruct *cbs =
(XmSelectionBoxCallbackStruct *) callData;
XmStringGetLtoR(cbs->value,
XmFONTLIST_DEFAULT_TAG,
&_text );
// ...
}

Alternatively, call VkPromptDialog::text() to obtain the text string after the user dismisses the dialog:

const char *text()

If the user clicks on the OK button, the dialog accepts the currently displayed text as input and uses that string as the return value of text(). If the user clicks the Cancel button, the dialog discards the currently displayed value, and any previously-displayed string the dialog might contain is returned as the value of text(). Do not attempt to free the string returned by text(). Typically, you should call text() only if you post the dialog using postAndWait(). postAndWait() returns a value of VkDialogManager::OK.


Note: Do not use text() from within one of the VkPromptDialog callback functions. VkPromptDialog sets the value returned by text() using its own OK callback function. Because OSF/Motif does not guarantee the calling order of callback functions, you cannot be certain that text() will return the correct value from within another callback function.



Caution: Subsequent posting of thePromptDialog can alter the text value. In rare conditions, if you post non-modal, non-blocking dialogs, this could occur even before you retrieved the value using text(). To prevent this, retrieve the text string in the OK callback function as shown in Example 35., or call text() only after posting the dialog using postAndWait() and verifying that postAndWait() returned the value VkDialogManager::OK).


File Selection Dialog

The VkFileSelectionDialog class supports standard OSF/Motif file selection dialogs (as shown in in Figure 28.) that allow the user to browse and select a file or directory. The global pointer to the file selection dialog manager, is theFileSelectionDialog (declared in <Vk/VkFileSelectionDialog.h>):

Figure 28. Example of a File Selection Dialog

Setting the initial directory

To set the initial directory displayed by the dialog, use VkFileSelectionDialog::setDirectory():

void setDirectory(const char *directory)

Unless you explicitly set a directory, the dialog defaults to the current directory.

Setting the inital filter pattern

To set the initial filter pattern used by the dialog (which determines the files displayed in the list box) use VkFileSelectionDialog::setFilterPattern():

void setFilterPattern(const char *pattern)

Unless you explicitly set a selection, the dialog displays all files in a directory.

Setting the initial dialog selection

To set the initial dialog selection, use VkFileSelectionDialog::setSelection():

void setSelection(const char *selection)

One method of obtaining the selection string of the file selection dialog is to extract it and use it in the OK callback function, as shown in Example 36.

Example 36. Extracting the Text String from a File Selection Dialog

Code

void MailWindow::okCallback(Widget w, XtPointer, clientData, XtPointer callData)
{
MailWindow *obj = (MailWindow *) clientData;
obj->ok(w, callData);
}
void MailWindow::ok(Widget dialog, XtPointer callData);
{
char *_text;
XmFileSelectionBoxCallbackStruct *cbs =
(XmFileSelectionBoxCallbackStruct *) callData;
XmStringGetLtoR(cbs->value,
XmFONTLIST_DEFAULT_TAG,
&_text );
// ...
}

Alternatively, call VkFileSelectionDialog::fileName() to obtain the selection string after the user has dismissed the dialog:

const char* fileName()

If the user clicks on the OK button, the dialog accepts the currently displayed text as input and uses that string as the return value of fileName(). If the user clicks the Cancel button, the dialog discards the currently displayed value, and any previously-displayed string the dialog might have contained is returned as the value of fileName(). Do not attempt to free the string returned by fileName(). Typically,you should call fileName() only if you post the dialog using postAndWait() and it returns a value of VkDialogManager::OK.


Note: Do not use fileName() from within a VkFileSelectionDialog callback function. VkFileSelectionDialog sets the value returned by fileName() using its own OK callback function. Because OSF/Motif does not guarantee the calling order of callback functions, you cannot be certain that fileName() will return the correct value from within another callback function.



Caution: Subsequent posting of theFileSelectionDialog can alter the selection value. In rare conditions, if you post non-modal, non-blocking dialogs, this could occur even before you retrieve the value using fileName(). To prevent this, either retrieve the selection string in the OK callback function, or call fileName() only after posting the dialog using postAndWait(), and verifying that postAndWait() returned the value VkDialogManager::OK).


The following code fragment shows a simple example of using the VkFileSelectionDialog class:

#include <iostream.h>
#include <Vk/VkFileSelectionDialog.h>
// ...
theFileSelectionDialog->setDirectory("/usr/tmp");
if(theFileSelectionDialog->postAndWait( ) == VkDialogManager::OK)
cout << "File name: " << theFileSelectionDialog->fileName()
<< '\n' << flush;

Deriving New Dialog Classes Using the Generic Dialog

The VkGenericDialog class is an abstract subclass of VkDialogManager. It provides a convenient interface for creating custom dialogs that use the ObjectPak interface. Custom dialogs that you derive from this class automatically support caching and all the other features supported by VkDialogManager. You can post and manipulate your custom dialogs using the functions provided by VkDialogManager.

Minimally, when you derive a new dialog class, you must override the VkGenericDialog::createDialog() function to create the dialog used by your class:

virtual Widget createDialog(Widget parent)

ViewKit ObjectPak passes to createDialog() the parent widget for the dialog, and createDialog() must return the dialog you create. Your overriding function must first call VkGenericDialog::createDialog(), which creates a MessageBox dialog template. By default, the dialog displays OK and Cancel buttons. Then, you simply add the interface to the MessageBox widget.

Changing default displays

To change the default display buttons and other characteristics for your custom dialog, set the protected data members listed in the following table:

 

 

Data Member

Description

Boolean _showOK

If TRUE (default), forces OK button to always appear in your custom dialog. If set FALSE, OK button appears only if you provide an OK callback function when posting the dialog.

Boolean _showCancel

If TRUE (default), forces Cancel button to always appear in your custom dialog. If set FALSE, Cancel button appears only if you provide a cancel callback function when posting the dialog.

Boolean _showApply

If TRUE, forces Apply button to always appear in your custom dialog. If set FALSE (default), Apply button appears only if you provide an apply callback function when posting the dialog.

Boolean _allowMultipleDialogs

If FALSE, does not create additional dialogs, but reuses an existing dialog in all cases.

Note: Default behavior of VkDialogManager class is to allow multiple dialogs of any given type to be posted at once. VkDialogManager class calls the createDialog() member fuction of the derived classes as needed to create additional widgets. For some types of dialogs, you will want to allow only one instance of a particular dialog type to exist at any one time. For example, multiple nested calls to VkApp::busy() should not normally produce multiple dialogs.

Boolean_minimizeMultipleDialogs

If TRUE, VkDialogManager reuses any existing dialog that is not currently displayed. VkDialogManager creates a new dialog only if all existing instances of the dialog type are currently displayed.

Note: VkDialogManager caches dialogs on a per-top-level window basis. If there are many top-level windows, this could result in having many dialogs of the same type. This may be undesirable for some types of dialogs, particularly if they are expensive to create.

 

 

Also, by default ObjectPak dismisses your dialog whenever the user clicks on either the OK or Cancel button, and keeps the dialog posted whenever the user clicks on the Apply button. You can change this behavior by overriding the functions VkDialogManager::ok(), VkDialogManager::cancel(), and VkDialogManager::apply() respectively:

virtual void ok(Widget dialog, XtPointer callData)
virtual void cancel(Widget dialog, XtPointer callData)
virtual void apply(Widget dialog, XtPointer callData)

ObjectPak calls these functions whenever the user clicks on one of the buttons in the dialog. By default, ok() and cancel() unpost the dialog and apply() is empty. You can override these functions to change the unposting behavior or to perform any other actions you want.