ViewKit Preference Dialog Class

The base preference dialog class, VkPrefDialog, is a subclass of VkGenericDialog, which is in turn a subclass of VkDialogManager. Thus, the VkPrefDialog class inherits all of the functions and data members provided by these base classes. For example, you post preference dialogs using the various post() variants, you set a preference dialog's title using the setTitle() function, and you set its button labels using the setButtonLabels() function.

Creating a Preference Dialog

Unlike the other dialog classes, VkPrefDialog does not create a global instance of a preference dialog. Instead, you must create a separate instance of VkPrefDialog for each preference dialog that you want to display in your program. For very simple preference dialogs (for example, just a few toggle buttons), you might be able to directly instantiate a VkPrefDialog object; however, in most cases you should create a separate subclass of VkPrefDialog for each preference dialog in your application. This is described in "Creating Preference Dialog Subclasses" .

The form of the VkPrefDialog constructor is:

VkPrefDialog(const char *name, VkPrefItem *item = NULL)

The VkPrefDialog constructor expects as its first argument the name of the preference dialog. The second argument is an optional pointer to a preference item that the dialog should use as the top-level preference item. See "Setting the Preference Items for a Preference Dialog" for more information on setting the top-level preference item.

For example, the following line creates a preference dialog named "simplePref":

VkPrefDialog *simplePref = new VkPrefDialog("simplePref");

Setting the Preference Items for a Preference Dialog

A preference dialog can have only one top-level preference item. In most cases, you use a group item such as VkPrefList as the top-level item.

As described in "Creating a Preference Dialog" , you can set the top-level preference item in the VkPrefDialog constructor. You can also set the top-level item with the setItem() function:

void setItem(VkPrefItem *item)


Note: If the preference dialog already has a top-level preference item associated with it, setItem() replaces that item with the new item, but does not delete the old item. This allows you to reuse the old preference item later.


For example, the following line sets the item docList as the top-level item of the preference dialog simplePref:

simplePref->setItem(docList);

The item() function returns a pointer to the top-level item associated with a preference dialog:

VkPrefItem *item()

Posting and Dismissing Preference Dialogs

You post preference dialogs using any of the various post() variants provided by the base ViewKit ObjectPak dialog classes. You should not pass a message string argument to the post() function when posting a preference dialog.

For example, the following line posts the simplePref dialog as a non-modal, non-blocking dialog:

simplePref->post();

You should rarely have to unpost a preference dialog programmatically. ObjectPak automatically dismisses a preference dialog when the user clicks on either the OK or Cancel button. If for some reason you do need to unpost a preference dialog from your program, use the unpost() function.

Responding to a User Click on a Preference Dialog Button

When the user clicks on the OK or Apply button on a preference dialog, the dialog automatically applies any change of values to the preference dialog's items by setting the items's internally-stored values so that they match whatever is currently displayed on the screen. If the user clicks on the OK button, the preference dialog calls its hide() function to remove itself from the screen. If the user clicks on the Apply button, the preference dialog remains visible on the screen.

When the user clicks on the Cancel button on a preference dialog, the dialog automatically resets all of the dialog's preference items's on-screen values so that they match the items's internally-stored values. Additionally, the preference dialog calls its hide() function to remove itself from the screen.

The VkPrefDialog class also supplies an ObjectPak member function callback named prefCallback. The preference dialog activates this callback whenever the user clicks on the dialog's Apply, OK, or Cancel button. The callback passes as call data an enumerated value of type VkDialogReason, which is defined in VkDialogManager. The value can be any of VkDialogManager::OK, VkDialogManager::APPLY, or VkDialogManager::CANCEL, corresponding to the button that the user clicked on. To notify components in your application when the user changes preferences associated with a preference dialog, register member functions with this ObjectPak callback.


Note: When the user clicks on the OK button, ObjectPak first updates the preference items's internally stored values and activates the prefCallback callback with VkDialogManager::APPLY as the call data. Then, ObjectPak activates the prefCallback callback with VkDialogManager::OK as the call data. This is somewhat analogous to a Motif pushButton performing an activate() action followed by a disarm() action when a user clicks on it. Use this feature to perform certain actions whenever the user updates preference values by clicking on either the Apply or OK button, and a separate set of actions when the user dismisses the preference dialog by clicking on the OK button.


For example, consider a window, myWindow, that is a member of the subclass MyWindow, derived from VkWindow. In this example, assume that there is a preference dialog, displayPrefs, that is a member of the subclass DisplayPrefDialog, derived from VkPrefDialog, that allows the user to specify certain display parameters such as the font. myWindow could register its member function MyWindow::fontChanged() to be called whenever the user clicks a button in the preference dialog displayPrefs, by using the following line of code:

displayPrefs->addCallback(VkPrefDialog::prefCallback,
this,
(VkCallbackMethod)&MyWindow::fontChanged);

When MyWindow::fontChanged() is called, it checks to see if any of the parameters in which it is interested have changed and, if so, performs whatever processing is needed. For example:

void MyWindow::fontChanged(VkComponent *obj,
void *clientData,
void *callData)
{
DisplayPrefDialog *dialog = (DisplayPrefDialog*) obj;
MyWindow *win = (MyWindow*) clientdata;
VkDialogManager::VkDialogReason reason =
(VkDialogManager::VkDialogReason) callData;
if (reason == VkDialogManager::CANCEL)
return;
// Now process new preference values as needed ...
}

Using Values Set in a Preference Dialog

To retrieve the value of a preference item, call the item's getValue() function. This implies that preference items must be accessible to all components that need to use preference values. For example, if you create a subclass for a preference dialog, declare as "public" those preference items that you want to access outside that dialog.

Example 39. shows the header for a NamePref subclass in which two preference items, firstName and lastName, are declared "public." These two preference items can be accessed by other components in the applications.

Example 39. Declaring Preference Items as Publicly Accessible

Code

class NamePref: public VkPrefDialog {
protected:
VkPrefGroup *nameGroup;
static String _defaultResources[];
virtual Widget createDialog(Widget parent);
public:
VkPrefText *firstName;
VkPrefText *lastName;
NamePref ( const char *name );
~NamePref();
virtual const char* className();
};

The NamePref subclass also contains a group, nameGroup, which is declared "protected." In most cases, outside components would not need to access a group item. One case in which it could be useful to make a group item publicly accessible is if you want other components to be able to activate and deactivate a group of preference items by calling the activate() and deactivate() functions on that group item.

Creating Preference Dialog Subclasses

The preferred method of handling preference dialogs in ViewKit applications is to create a separate subclass for each preference dialog in the application. Properly designed, a preference dialog can serve as a self-contained component that you can use in multiple applications.

The first step in creating a preference dialog subclass is to decide what preference items to include. List all of the information you want to be able to set with the preference dialog and determine which preference item class is appropriate for each item. For example, an item requiring text input is an obvious candidate for a VkPrefText item. However, an item allowing the user to choose one of several options can be handled by either a single VkPrefOption item or a number of VkPrefToggle items grouped with a VkPrefRadio item. Presumably, you want all of these preference items to be accessible outside of the preference dialog, so you want to declare these items in the "public" section of your class declaration.

Then determine the layout you want for the preference dialog. You should group similar items together so that a user can easily find and set related items. The layout determines what group items you need. Usually, you can define these items in the "private" or "protected" section of your class declaration; however, in some cases, you might want to declare some groups as "public." For example, you might want to be able to activate and deactivate a group of preference items by calling the activate() and deactivate() functions on that group item.

Then determine how you want to "publicize" changes in preference items to other components in your application. In many cases, those components can simply call the getValue() functions for appropriate items as needed. However, some components need to be notified immediately whenever certain preference items change. In most cases, these components can register ViewKit member function callbacks with the preference dialog that are called whenever the user clicks on one of the dialog's buttons. The components can then test for changes in preference item values in their callback functions and react accordingly.

In some cases, you might need to perform special processing when the user clicks on one of the preference dialog's buttons. In that case, you can override the default ok(), apply(), or cancel() function for the dialog. These functions are called whenever the user clicks on the corresponding button. In your override definition, you should perform whatever processing is needed and then call the base VkPrefDialog::ok(), VkPrefDialog::apply(), of VkPrefDialog::cancel() function as appropriate.

Usually you should also provide a set of default resource values to serve as labels for all the dialog's preference items. To do so, you must override the createDialog() function, which creates and manages all of the widgets in a preference dialog.

Required tasks for createDialog() function

Your preference dialog's createDialog() function must perform the following tasks in order:

  1. Call setDefaultResources() to set5 the dialog's default resources.
  2. Create all preference items for the dialog.
  3. Set the dialog's top-level item using the setItem() function.
  4. Call the base VkPrefDialog::createDialog() function to create the dialog.
  5. Pass the dialog's base widget, returned by VkPrefDialog::createDialog(), as the return value of createDialog().

Example 37. shows a complete example of a preference dialog subclass. You could include DocPrefDialog dialogs in any application that needed to set various document parameters.