Posing Dialogs
Volume Number: 7
Issue Number: 11
Column Tag: Pascal Methods
Posing Dialogs in MacApp 
By James Plamondon, San Mateo, CA
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
Posing the Question
So you want to pose a dialog. You’ve done it a million times before: create the
dialog, initialize it, pose it, and see if it was cancelled; if not, get the data from the
dialog and do something with it. It’s all pretty formulaic -- so why not encapsulate the
process in a class?
TPoseDialogCmd does just that. A subclass of TCommand, it handles the display of
a dialog, in the steps described above. Actually, it is an abstract class; it has two
subclasses, TMacAppDialogCmd and TToolboxDialogCmd, that implement the methods
laid out in TPoseDialogCmd. TMacAppDialogCmd displays dialogs that are built of
MacApp views; TToolboxDialogCmd displays dialogs that are built using the Toolbox
Dialog manager. This article will focus on TMacAppDialogCmd.
First, let’s illustrate the use of the TMacAppDialogCmd. I’ve modified the
MacApp sample program DemoText to add a “character” dialog, which allows the user to
specify, for a given text selection, its font, style, size, justification, etc.. This dialog is
described by the class TCharDialogView, in the unit UCharacterDialog.
UCharacterDialog also contains the description of the class TCharacterDialogCmd, a
subclass of TMacAppDialogCmd that knows about the Character dialog.
TCharacterDialogCmd doesn’t know anything about the DemoText application’s data
structures, though, so it is subclassed in UTEDocument to produce TTECharDialogCmd.
TTECharDialogCmd knows about TTEDocuments and TTEViews, so it knows how to access
and change the text style and alignment of the current selection.
When the user selects the “Character” menu item,
TTEDocument.DoMenuCommand() is called. In its local DoCharacter() routine, a
TTECharDialogCmd is created and initialized with the text style and alignment of the
current selection. The command is returned as the function result of
TTEDocument.DoMenuCommand(), and is eventually posted to the application’s
command queue. The command is subsequently picked up by PollEvent(), and its DoIt()
method is called. TPoseDialogCmd’s implementation is executed. Here it is:
{1}
PROCEDURE TPoseDialogCmd.DoIt;
OVERRIDE;
VAR
theCommand: TCommand;
BEGIN
InitTheDialog;
PoseTheDialog;
{ create the resulting command }
IF fCancelled
THEN
theCommand := NIL
ELSE
theCommand := CreateTheCommand;
{ post the resulting command }
IF (theCommand <> NIL)
THEN
gTarget.PostCommand(theCommand);
{ clean up }
DropTheDialog;
END; { DoIt }
Figure 1: Character Dialog
InitTheDialog() is overridden in TCharacterDialogCmd, which knows about the
TCharcterDialogView class (since both are defined in the same unit), as follows:
{2}
PROCEDURE TCharacterDialogCmd.InitTheDialog;
OVERRIDE;
VAR
theTextStyle: TextStyle;
BEGIN
{ localize to avoid unsafe field use }
theTextStyle := fTextStyle;
{ initialize the dialog to act on the command's TextStyle and
alignment }
TCharDialogView(fTheDialog).SetDialogInfo(theTextStyle, fAlignment,
kRedraw);
{ make sure the 'size' field is the current edit text item }
fTheDialog.SelectEditText('size', TRUE); { TRUE = DO select the
text }
END; { InitTheDialog }
The dialog’s class and class of the command that show the dialog must know about
and rely on each other, as the typecast in the second statement shows. The command
class has to assume that the dialog is of the intended class. If it’s not, you’re going to
get a very unpleasant run-time error.
The method PoseTheDialog(), inherited from TMacAppDialogCmd, follows
naturally enough:
{3}
PROCEDURE TMacAppDialogCmd.PoseTheDialog;
{ Actually poses the dialog. }
VAR
dismisser: IDType;
BEGIN
{ pose the dialog }
fTheWindow.Select; { bring the window to the front before
showing it }
dismisser := fTheDialog.PoseModally;
{ take note of the user's response }
SetDismisser(dismisser);
SetCancelled(dismisser = fTheDialog.fCancelItem);
END; { PoseTheDialog }
It just brings the window to the front, poses it with PoseModally(), and sets the
appropriate fields to indicate the manner in which the dialog was dismissed.
The only other routine that needs to be overridden is TPoseDialogCmd’s
CreateTheCommand(), which is overridden in TTECharDialogCmd as follows:
{4}
FUNCTION TTECharDialogCmd.CreateTheCommand
: TCommand;
OVERRIDE;
VAR
oldTextStyle: TextStyle;
newTextStyle: TextStyle;
newAlign: INTEGER;
aCmd: TTEStyleAndAlignCmd;
BEGIN
oldTextStyle := fTextStyle; { localize }
{ get the current TextEdit and alignment states from the Character
Dialog }
TCharDialogView(fTheDialog).GetDialogInfo (newTextStyle, newAlign);
IF SameTextStyle(oldTextStyle, newTextStyle) &
(fAlignment = newAlign)
THEN
CreateTheCommand := NIL { no change }
ELSE IF (fAlignment = newAlign)
THEN
BEGIN
CreateTheCommand := TTEView(fView).DoMakeStyleCommand(
newTextStyle,