Search and Replace
Volume Number: 5
Issue Number: 5
Column Tag: Pascal Procedures
Modeless Search and Replace 
By Mark McBride, Oxford, CA
Note: Source code files accompanying article are located on MacTech CD-ROM orsource code disks.
While working on development of a utility to speed integration of toolbox calls in
MacFortran source code, I found myself looking for a search and replace routine.
Perusal of Macintosh Revealed (Vol. 2) quickly led to the toolbox routine Munger
(rhymes with plunger). A search of back issues of MacTutor also revealed the lack of a
general discussion of Munger and doing find/replace (not even the generic
multi-window text editor from the January 1987 issue). Thus, I decided to write a
general purpose find/replace unit from a modeless dialog environment.
Basic Program Design
The find/replace unit and the accompanying example program are written in LS
Pascal. Conversion to TML, Turbo, or MPW should be relatively straightforward. The
find/replace unit is designed as a standalone unit that requires very little modification
to the user’s program to add its capabilities. The modifications required include
changing the main event loop to handle modeless dialog events, adding a new menu, and
inserting calls to the find/replace unit in your program. When calling the
find/replace routines the user passes the current event and a handle for the editText to
be searched. The program contains a simple text edit window, a modeless Find dialog,
and a modeless Replace Dialog. The program supports desk accessories; cut, copy, and
paste within the program (but not with desk accessories); and should be screen and
machine size independent. The program requires a 512Ke or later machine. If run on
an old 512k machine, the program alerts the user and exits back to the Finder.
Simple Text Editor
The demonstration program uses the ROM85 library enhancements for the
textedit window which allowed me to write a barebones editor sufficient for
demonstration purposes. The text window can be resized, zoomed, and automatically
scrolled. However, there are no scroll bars, thus movement to text outside the visible
region must done with the arrow keys. Cut, copy, paste, and clear work properly. The
text window contents cannot be loaded from disk, nor saved to disk. Upon startup
(Figure 1), the text window contains Lincoln’s Gettysburg Address retrieved from the
resource fork.
Figure 1.
Find/Replace Unit
The Find dialog allows the user to enter text characters and does an exact find.
The search process can be initiated by clicking the ‘Find’ button or pressing the return
key. The find routine works from the current selection point and does not wrap past
the end of the textedit record. If found, the current selection is set to the string found
and highlighted. If not found, the machine beeps. The find routine does not support
wildcards nor non-printing characters (e.g., control characters).
The Search dialog allows the user to enter both the search and replace strings.
Initially, the ‘Search’ button is highlighted as the default button. Once the search
string has been found (and selected, the search routine is just the find routine), the
‘Replace’ button is highlighted. If the ‘Replace’ button is selected then the occurrence
of the search string previously found is replaced. The replace string can be null but
the find string must contain at least one character. When the replace operation is
successfully completed, the ‘Search’ button returns to the default button. Although I
have not included a ‘replace all’ button (which could easily be integrated), the user
can continually press the return key searching and replacing. Dialog cut, copy, and
paste from the text edit scrap is supported within both the Find and Replace dialogs.
Handling Modeless Dialogs
To properly handle the modeless find and replace dialogs four major aspects of
modeless dialog event handling must be observed carefully: main event loop changes,
window events, dialog events, and command keys. Each element is relatively
straightforward, but the combination of the four can lead to some confusion and
unnecessary coding.
Main Event Loop
When a program contains modeless dialogs, the toolbox routine IsDialogEvent
should be called after calling GetNextEvent. Inside Mac (page I-416) warns that the
program should call IsDialogEvent even if GetNextEvent returns false. When
IsDialogEvent returns true the program should drop into its routine to handle events
for the modeless dialog. Thus, the program should call GetNextEvent, then
IsDialogEvent, and then start processing on the basis of the booleans returned by the
two routines. If the program does a
{1}
if GetNextEvent(myEvent) then
begin
if IsDialogEvent(MyEvent) then
begin
Do_Modeless(MyEvent);
...
structure then null dialog events will not be passed to its modeless dialog routines. The
alternative used by the program in the listing does the following:
{2}
EventFlag:=GetNextEvent(MyEvent);
if IsDialogEvent(MyEvent)then
Do_Modeless(MyEvent)
else if EventFlag then
begin
...
According to Inside Mac, IsDialogEvent returns true for:
• activate or update events for a dialog window
• mouse-down events in the content region of an active dialog window
• any other event when a dialog window is active.
However, the last statement is misleading.
The structure region of a window is composed of two parts: the content region and
the window frame (see Inside Mac, pages I-271,272). In the standard document
window, the window frame contains the drag, go-away, and zoom regions (if zoom was
desired). These regions do not overlap with the content region in the standard
document window, although they could in a custom window definition. Thus, if your
modeless dialog uses a standard document window (or a noGrowDocument proc) then
you must be careful in handling events. A mouse-down event in the window frame of a
modeless dialog will return false for IsDialogEvent. The main event loop must handle
mouse-downs in the drag, go-away, and zoom boxes of a modeless dialog when using
standard window types. This does not pose a particular problem since handling
multiple windows for growing, dragging, and zooming is a standard Mac programming
task.
Dialog Handler
When IsDialogEvent returns true, the user should pass control to a routine that
handles the modeless dialog event. This routine should call the function
DialogSelect(theEvent, whichDialog,ItemHit):boolean.
DialogSelect will return a result of true with the dialog pointer in whichDialog
and the item number in ItemHit when there is