Previous Book Contents Book Index Next

Inside Macintosh: Programmer's Guide to MacApp / Part 2 - Working With MacApp
Chapter 14 - Working With Scripting


Recipes--Scripting

The recipes and sample code in this section describe how to support Apple events in your application, how to define a recordable command class, how to set object properties with Apple events, how to support a custom Apple event, how to write a simple script that can be attached to window objects in your application, how to initialize MacApp's scripting support to use a custom subclass of TOSADispatcher, and how to override the GetContainedObject method to look for contained objects matching a type you are interested in.

Supporting Apple Events in Your Application--A General Outline

A MacApp application is scriptable by default, since it automatically supports the four required Apple events plus a number of events from the Core suite. MacApp's scripting support is initialized automatically from the IApplication method, so it requires no special initialization by your application.

This outline describes the steps most MacApp applications take to add support for additional Apple events or to modify MacApp's default behavior. To provide additional scripting support in your application, you perform these steps:

  1. Factor your application. Factoring consists of

    • separating code that controls the user interface from code that responds to user actions
    • breaking functions into discrete operations that can be implemented as separate tasks

      For more information, see "Factoring," beginning on page 143.

  2. Establish an event suite by identifying the additional Apple events your application will support, or the ones it will modify (see page 142).
  3. Define an 'aete' resource for your new or modified events. The easiest way to do this is to copy and modify MacApp's default 'aete' resource. The 'aete' resource provides information to a scripting component about the Apple events an application supports and about the human-language terminology associated with those events. (See "Define an 'aete' Resource," beginning on page 356.)
  4. Define one or more 'aedt' resources for your custom Apple events. An 'aedt' resource maps a received Apple event (by class ID and descriptor type) to a MacApp command number. (See "Define an 'aedt' Resource for the Custom Event," beginning on page 362.)
  5. Identify the classes you will use to handle your custom events. If those classes don't descend from classes that already use the mixin class MScriptableObject, add it to their definition.

    When you mix in MScriptableObject to a class, the constructor for that class should initialize MScriptableObject with a unique object model class ID. For example, MacApp's TFile class implements its constructor method as follows:

    TFile::TFile()
    : MScriptableObject(cFile)
    {
    .
    .
    .
    }

    This code sets the fOMClassID field of the TFile class (inherited from the MScriptableObject class) to cFile. This field is used by methods such as CountContainedObjects, GetObjectProperty, and MakeObjectSpecifier.

  6. Determine which properties of your objects can be set by Apple events. Override the GetObjectProperty and SetObjectProperty methods of MScriptableObject to get and set those properties. You may also have to override the GetSetPropertyInfo method. (See "Recipe--Setting Object Properties With Apple Events," beginning on page 355.)
  7. Optionally override other methods of MScriptableObject so your scriptable classes can describe themselves to the Object Support Library (OSL). This can include overriding the GetContainedObject, GetIndContainedObject, and CountContainedObjects methods. (See "Recipe--Overriding the GetContainedObject Method," beginning on page 368.)
  8. Override the MScriptableObject::DoScriptCommand method to add support for your custom events. In the DoScriptCommand method you typically create a command to perform the operation specified by an Apple event. (See "Override DoScriptCommand to Handle the Custom Event," beginning on page 364.)
  9. To handle core events, override additional methods in MScriptableObject, such as DoAEMove, DoAEOpen, DoAEClose, and so on. (Some of these methods are overridden in MacApp classes. For example, the TWindow class provides a DoAEMove method.)
  10. To perform a recordable operation, define a command class that descends from TCommand (or one of MacApp's many predefined subclasses). Override the MakeAppleEvent method to create an Apple event that describes the command operation.

Recipe--Defining a Recordable Command Class

MacApp's TCommand class contains support for sending an Apple event that describes the command operation. Sending an Apple event makes the operation recordable and allows attached scripts to respond to the command. You can read more about this topic in "Command Objects and Apple Events," beginning on page 120. This recipe adds scripting-related information to the recipe for implementing an undoable Zoom In menu command, which begins on page 334.

To define a recordable command class, you perform these steps:

  1. Follow all five steps shown in "Recipe--Implementing an Undoable Zoom In Menu Command," beginning on page 334:

    • Define a command-number constant for the Zoom In menu item.
    • Add the Zoom In menu item to a 'CMNU' resource in your resource file.
    • Implement a command class that handles Zoom In and override the DoIt, UndoIt, and RedoIt methods.
    • Override the DoSetupMenus method in the view class to enable the Zoom In menu item when appropriate.
    • Override the DoMenuCommand method in the document class to create and post a command object to perform the zoom operation.

      Each of these steps is described in the recipe for an undoable Zoom In menu command.

You also perform this additional step:

  1. Override the MakeAppleEvent method in the TZoomInCommand class.

The sample code in this recipe is from the IconEdit application.

Override MakeAppleEvent in the TZoomInCommand Class

The TCommand::MakeAppleEvent method creates an Apple event that describes the command operation. For the TZoomInCommand class, the operation is zooming in on an icon. The TZoomInCommand class is shown in "Implement a Command Class That Handles Zoom In," beginning on page 335.

For the TZoomInCommand class, the MakeAppleEvent method is defined as follows:

TAppleEvent * TZoomInCommand::MakeAppleEvent() // Override.
{
   CTempDescdirectObjectDesc;
   TAppleEvent * theZoomInAppleEvent = new TAppleEvent;

   theZoomInAppleEvent->IAppleEvent(kAEIconEditClass, kAEZoomInID,
                              gServerAddress, kAENoReply);
   fIconDocument->MakeObjectSpecifier(directObjectDesc,
                           fIconDocument->GetSpecifierForm());
   theZoomInAppleEvent->WriteParameter(keyDirectObject,
                              directObjectDesc);
   return theZoomInAppleEvent;
}
This method first creates a new TAppleEvent object and initializes it for the Zoom In command. The constant kAENoReply indicates that no reply to the Apple event is expected. The constants kAEIconEditClass and kAEZoomInID are defined as follows:

const OSType kAEIconEditClass = 'ICED'; // Event class.
const OSType kAEZoomInID = 'ZmIn';// Event ID.
For more information on how event class and ID constants are used, see "Define an 'aedt' Resource for the Custom Event," beginning on page 362.

The MakeAppleEvent method next asks its document to create an object specifier (see page 350), then writes the specifier to the Apple event. The result is a Zoom In Apple event that specifies an icon document object to be zoomed.

Note
The TDocument::GetSpecifierForm method returns formName, so the object specifier identifies the document by name.

Recipe--Setting Object Properties With Apple Events

This recipe depends on MacApp's built-in support for handling set property Apple events. To understand how that support works, you should read about the TSetPropertyCommand and TPropertyAccessor classes, beginning on page 155.

To add support to a class to set object properties based on received Apple events, you perform the following steps:

  1. Identify the property or properties the class will support.
  2. Define an 'aete' resource with information on the class and the properties that can be set by Apple events.
  3. Mix in the MScriptableObject class (if it isn't already mixed in).
  4. Initialize MScriptableObject with an object model class ID for the class.
  5. Override the GetObjectProperty and SetObjectProperty methods.
  6. If necessary, override the GetSetPropertyInfo method.

The sample code shown in this recipe is from the IconEdit application.

Identify the Property or Properties the Class Will Support

Apple event object classes may have one or more properties. A property is identified by a four-character property ID, which can also be represented by a constant. Constants for properties always begin with the letter "p". Many are defined in the header file AERegistry.h. Table 14-1 lists the constant names and property IDs for some common properties. You can read more about properties in Inside Macintosh: Interapplication Communication.

The IconEdit application supports pColor as a property that specifies the current icon color of an object based on the TIconDocument class.

Table 14-1
PropertyProperty IDDescription
pBounds'pbnd'Coordinates of a window
pClass'pcls'Class ID of an Apple event object
pColor'colr'Text color
pFillColor'flcl'Fill color
pFont'font'Font
pIsModal'pmod'Indicates whether a window is modal
pName'pnam'Name of an Apple event object
pScriptTag'psct'Script system identifier
pTextPointSize'ptps'Point size
pTextStyle'txst'Text style
pVisible'pvis'Indicates whether a window is visible
Common object properties

MacApp classes that mix in MScriptableObject override the GetObjectProperty and SetObjectProperty methods to get and set the object properties they support. For example, the TWindow class returns the pClass, pBounds, pName, pHasCloseBox, pHasTitleBar, pIsModal, pIsResizable, pIsZoomable, pIsZoomed, and pSelection properties in its GetObjectProperty method. In its SetObjectProperty method, it can handle pBounds, pName, and pIsZoomed (the other properties are read only). As a result, you can use a script to read or set many window properties without writing any additional application code.

Define an 'aete' Resource

An 'aete' resource provides information to a scripting component about the Apple events an application supports and about the human-language terminology to associate with those events.

The best way to supply information about your custom events is to copy MacApp's default 'aete' resource, located in the file Defaults.r, add it to your application's resource definition file, and modify it to include your custom events.

The IconEdit application modifies MacApp's default 'aete' resource to add an icon suite of supported Apple events. The following code, from the file IconEdit.r, shows the part of IconEdit's 'aete' resource that allows an icon document to handle the color property:

{  /* array Classes: 1 elements */
   /* [1] */
   "document", cDocument, "IconEdit document",
   {  /* array Properties: 1 elements */
      /* [1] */
      "icon_color",
      pColor,
      cRGBColor,
      "color in which the icon is drawn",
      reserved,
      singleItem,
      notEnumerated,
      readWrite,
      Reserved8,
      noApostrophe,
      notFeminine,
      notMasculine,
      singular
   },
   {  /* array Elements: 0 elements */
   }
},
For more information about the format of an 'aete' resource, see the "Apple Event Terminology Resources" chapter of Inside Macintosh: Interapplication Communication.

Mix in the MScriptableObject Class

Your class that gets and sets object properties must mix in MScriptableObject unless it descends from a class that already mixes in MScriptableObject. The TIconDocument class is a descendant of the TDocument class, which mixes in MScriptableObject. The TDocument class is declared as follows to mix in MScriptableObject:

class TDocument : public TCommandHandler, public MScriptableObject

Initialize MScriptableObject With an Object Model Class ID

If your class that gets and sets object properties doesn't already mix in MScriptableObject, the constructor for your class should initialize MScriptableObject with a unique object model ID. For example, the constructor method for the TDocument class is implemented as follows:

TDocument::TDocument()
   : MScriptableObject(cDocument),
   fTitle(gEmptyString),
   fWindowList(NULL),
      .
      .
      .
{
}
This implementation demonstrates a C++ mechanism for supplying a method with a list of default values. The line

: MScriptableObject(cDocument),

invokes a constructor for MScriptableObject and initializes the fOMClassID field to cDocument. The subsequent lines initialize fields of the TDocument class.

Override GetObjectProperty and SetObjectProperty

Your class that supports modifying object properties with Apple events overrides the GetObjectProperty and SetObjectProperty methods to get and set the properties it works with. For the TIconDocument class, these methods look for the pColor property. For any other property, they call Inherited.

Boolean TIconDocument::GetObjectProperty(CAEDesc& thePropertyValue,
                                 DescType whichProperty,
                           const CAEDesc& desiredType)
{
   Boolean hasProperty = TRUE;
   
   switch (whichProperty)
   {
      case pColor:
         thePropertyValue.PutRGBColor(fColor); // Set color.
         break;
         
      default:
         hasProperty = Inherited::GetObjectProperty(
                  thePropertyValue, whichProperty, desiredType);
         break;
   }
   return hasProperty;
}
The GetObjectProperty method gets the document's icon color from the fColor field and writes it to the passed descriptor object, thePropertyValue.

void TIconDocument::SetObjectProperty(
                     const CAEDesc& thePropertyValue,
                           DescType whichProperty)
{
   switch(whichProperty)
   {
      case pColor:
         thePropertyValue.GetRGBColor(fColor);
         this->RedrawViews();
         break;

      default:
         Inherited::SetObjectProperty(thePropertyValue,
                                 whichProperty);
         break;
   }
}
The SetObjectProperty method writes the color from the passed descriptor object, thePropertyValue, to the document's fColor field. It then calls the RedrawViews method to force the icon to be redrawn with the new color.

If Necessary, Override GetSetPropertyInfo

The GetSetPropertyInfo method is described in "The TSetPropertyCommand Class," beginning on page 155. Your class overrides GetSetPropertyInfo only if it needs to change the default values supplied by the MScriptableObject class. The TIconDocument class overrides GetSetPropertyInfo to supply a command number:

void TIconDocument::GetSetPropertyInfo(DescTypewhichProperty,
                              CommandNumber&cmdNum,
                              Boolean&    canUndo,
                              Boolean&    causesChange,
                              TCommandHandler* &theContext)
{
   switch(whichProperty)
   {
      case pColor:
         cmdNum = cSetColor;
         canUndo = TRUE;
         causesChange = TRUE;
         theContext = this;
         break;
      
      default:
         Inherited::GetSetPropertyInfo(whichProperty, cmdNum,
                        canUndo, causesChange, theContext);
         break;
   }
}
The icon document sets only the pColor property, so for any other property this method just calls Inherited.

Recipe--Supporting a Custom Apple Event

To support a custom Apple event (or any number of them), your application performs many of the steps shown in the general outline beginning on page 351. This recipe shows how the IconEdit application supports a Zoom In event.

To use a custom Apple event in your application, you perform these steps:

  1. Identify the custom event to be supported.
  2. Describe the custom event in your application's 'aete' resource.
  3. Define an 'aedt' resource for the custom event.
  4. Make sure the class that handles the custom event mixes in the MScriptableObject class.
  5. If necessary, override methods of MScriptableObject so that your scriptable class can describe itself to the OSL.
  6. Override the MScriptableObject::DoScriptCommand method to handle the custom event.

The sample code shown in this recipe is from the IconEdit application.

Identify the Custom Apple Event

The IconEdit application defines custom events to invert an icon, zoom in and zoom out on an icon, and draw or erase the points in an icon. This recipe examines the Zoom In event.

Define an 'aete' Resource That Includes the Custom Event

An 'aete' resource provides information to a scripting component about the Apple events an application supports, and about the human-language terminology to associate with those events. You can copy MacApp's default 'aete' resource, located in the file Defaults.r, add it to your application's resource definition file, and modify it to include your custom events.

The IconEdit application modifies MacApp's default 'aete' resource to add an Icon suite of supported Apple events. The following code, from the file IconEdit.r, shows the part of IconEdit's 'aete' resource that allows an icon document to handle the Zoom In event:

/* [2] */
"zoom_in",
"increases the magnification of the target document",
'ICED',
'ZmIn',
noReply, "", replyOptional, singleItem, notEnumerated,
notTightBindingFunction, Reserved8, verbEvent, Reserved3,
typeObjectSpecifier,
"the document to zoom into",
directParamRequired, singleItem, notEnumerated,
doesntChangeState, Reserved12,
{  /* array OtherParams: 0 elements */
}
For more information about the format of an 'aete' resource, see the "Apple Event Terminology Resources" chapter of Inside Macintosh: Interapplication Communication.

Define an 'aedt' Resource for the Custom Event

MacApp uses resources of type 'aedt' to install Apple event callback routines for an application's custom events (see "InstallDispatchHandlers," beginning on page 151). An 'aedt' resource is an array of entries, each of which maps an Apple event class and ID pair to a MacApp command number.

To handle a custom Apple event in your application, you define an Apple event class and ID for the event, as well as a command number to associate with them. Then you add an 'aedt' resource to your resource definition file and include an entry for the event. You can store as many entries as you want in one 'aedt' resource, and you can have multiple 'aedt' resources.

The IconEdit application defines the following 'aedt' resource in the file IconEdit.r to support Apple events specifying the operations to invert, zoom in, zoom out, and draw points:

resource 'aedt' (kAEIconEditDispatchTable, 
#if qNames
   "IconEdit Events",
#endif
   purgeable) {
   {  /* array: 4 elements */
      /* [1] */
      'ICED', 'INVT', 1002,
      /* [2] */
      'ICED', 'ZmIn', 1000,
      /* [3] */
      'ICED', 'ZmOt', 1001,
      /* [4] */
      'ICED', 'DrPt', 1003
   }
};
The IconEdit application defines the following constants for working with its custom Apple events (the IconEdit.r resource file ought to define similar constants and use them in the 'aedt' resource shown above):

const OSType kSignature ='ICED'; // Application signature.

const OSType kAEInvertID = 'INVT';// Custom Apple event IDs.
const OSType kAEZoomInID = 'ZmIn';
const OSType kAEZoomOutID = 'ZmOt';
const OSType kAEDrawPoints = 'DrPt';

const CommandNumber cZoomIn=1000;// Zoom In menu command.
const CommandNumber cZoomOut=1001;// Zoom Out menu command.
const CommandNumber cInvert=1002;// Invert menu command.
const CommandNumber cDrawCommand =1003;// Drawing in the icon view.
const CommandNumber cDrawPointsCommand = 1004;// Set point Apple event.

Add the Mixin Class MScriptableObject

MacApp dispatches Apple events through a global Apple event dispatcher object, described in "Dispatching Apple Events," beginning on page 150. The event dispatcher expects the specified objects to be descendants of MScriptableObject, a MacApp mixin class with fields and methods for working with Apple events.

Several MacApp classes, including TDocument and TWindow, already use MScriptableObject. If you define a class that handles Apple events and doesn't descend from a class that already uses MScriptableObject, you should add MScriptableObject to the class definition.

The TIconDocument class is a descendant of the TDocument class, which is declared as follows:

class TDocument : public TCommandHandler, public MScriptableObject

If Necessary, Override Certain Methods of MScriptableObject

MacApp's global Apple event dispatcher object calls routines of the Object Support Library to help resolve the object specified by the event. The OSL uses callback routines in the event dispatcher object to ask objects to describe themselves.

To aid in this process, your classes that handle Apple events may need to override methods of MScriptableObject (such as GetContainedObject, GetIndContainedObject, and CountContainedObjects) to describe their elements. This information can help determine if the document matches the one specified by an Apple event. For an example of how to override the GetContainedObject method, see "Recipe--Overriding the GetContainedObject Method," beginning on page 368.

Override DoScriptCommand to Handle the Custom Event

When MacApp identifies the object specified by an Apple event, it calls the DoScriptCommand method of that object. The class that handles your custom Apple event overrides DoScriptCommand to handle events it knows about.

The TIconDocument class overrides DoScriptCommand and supplies the following code to create a command to zoom in on an icon:

case cZoomIn:
      TZoomInCommand * theZoomInCommand = new TZoomInCommand();
      theZoomInCommand->IZoomInCommand(this);
      theZoomInCommand->Process();
   break;
Note that this code does not set the command's fUseAppleEvent field to TRUE. Because the Zoom In command is being created in response to an Apple event, there is no need to send an Apple event to show that the operation was performed. The TZoomInCommand class is described in "Recipe--Defining a Recordable Command Class," beginning on page 353.

Recipe--Attaching a Script to Objects in Your Application

"Attaching Scripts," beginning on page 158, describes MacApp's mechanism for attaching scripts to objects in your application. MacApp provides true attachability through its Apple-event-dispatching mechanism and its MScriptableObject class--that is, a script can be attached to an object, and any Apple events specifying that object will first be dispatched to the attached script.

You attach a script to an object that mixes in MScriptableObject by calling the SetObjectProperty method and passing two values: a CAEDesc value that describes the script and a DescType value that specifies the pScript property. Since many MacApp classes already mix in MScriptableObject, you can attach scripts to objects based on these classes (or on subclasses you define) without writing any additional application code.

When a script is attached to any object in the application, MacApp's global Apple event dispatcher object installs a callback routine to predispatch Apple events. The predispatch routine gives attached scripts a chance to handle Apple events dispatched by the application, whether they are generated internally or received from an outside source.

The following is a simple script that you can run from the Script Editor application. It attaches a script to each open window in the DemoText sample application. When you close a window with the script attached, the script intercepts the close operation and forces the document to be saved.

script forceSaveOnClose
   
   on close of theCloseObj saving savingValue
      display dialog "Entering Script"
      display dialog "The original saving value:"
      display dialog savingValue
      set savingValue to yes
      display dialog "The new saving value:"
      display dialog savingValue
      set savingFile to a reference to file "YourHardDisk:YourSaveFolder:SavedFile"
      continue close of theCloseObj saving savingValue saving in savingFile
      display dialog "Finished  - Exiting Script"
   end close
   
end script

on run
   set the script of every window of application "DemoText" to forceSaveOnClose
end run
To test this script, you perform the following steps:

  1. Build a version of the DemoText application that includes MacApp's attachability support.

    To enable attachability in your application, you must build the application with the qAttachable flag set to TRUE. "Common Command-Line Options," beginning on page 678, describes how to build your application with attachability or without it, using MPW's MABuild system.

  2. Run the DemoText application. Open one or more windows.
  3. Run the Script Editor application.
  4. Open a new script window.
  5. Copy the script shown above into the script window.
  6. Change "DemoText" to match the current name of the application on your computer (for example, "DemoTextPPC_nd").
  7. Change "YourHardDisk:YourSaveFolder:" to specify a disk and folder location on your current machine. If desired, change "SavedFile" to a different filename.
  8. Click the Run button to run the script.

This script attaches the forceSaveOnClose script to each open window in the DemoText application (actually, to each window's document).

How MacApp Attaches the Script

When you run the script with Script Editor, the line

set the script of every window of application "DemoText"
   to forceSaveOnClose
sends an Apple event to the DemoText application, telling it to set the pScript property of each window to the forceSaveOnClose script. The mechanism for setting object properties is described in Chapter 6, "Scripting," beginning on page 155 (in the sections describing the TSetPropertyCommand and TPropertyAccessor classes) and in "Recipe--Setting Object Properties With Apple Events," beginning on page 355.

When MacApp receives the Apple event, it creates a list containing a TPropertyAccessor object for each open window and uses the list to initialize a TSetPropertyCommand object. The TSetPropertyCommand object uses MacApp's attachability mechanism (page 158) to attach the script to each window.

Note
When you attach a script to a window object by setting the pScript property, the window defers to its document, so the script is actually attached to the document.
MacApp even automates saving a script when you close the document it is attached to. When you save a DemoText document with the forceSaveOnClose script attached, the script is automatically saved in the document's resource fork (unless you change the value of the document's fSaveAttachedScript field to FALSE). When you open the document, it automatically reads the script, creates a script object, and attaches it to the document object.

What Happens When the Script Is Executed

When you close a window in the DemoText application, MacApp creates and posts a TCloseFileDocCommand. When the command is processed, it sends a kAEClose Apple event that specifies the document to be closed.

If a script is attached to any object in the application, MacApp's global Apple event dispatcher object attempts to predispatch each Apple event for handling by an attached script. In this case, the predispatch handler method dispatches the Apple event to the document's attached script.

The forceSaveOnClose script gains control after the user has been asked whether to save the document. The forceSaveOnClose script then performs the following actions (assuming you don't cancel the script and no errors are encountered):

Where You Go From Here

This recipe presents a simple script that hard-codes the name and location of the saved file and contains no error checking. Yet it demonstrates how attached scripts can greatly alter the behavior of a MacApp application. For example, a user can attach a similar script to a document representing an office form, so that every time the document is saved, the default behavior is overridden and the document is backed up to a server.

Other uses for attached scripts are limited only by your imagination and the diabolical cunning of your end users.

Recipe--Overriding the GetContainedObject Method

When your application receives an Apple event, MacApp attempts to dispatch the event to the specified object. (Object specifiers are described beginning on page 350.) During the dispatching process, the OSL makes callbacks to methods of MacApp's global Apple event dispatcher object, attempting to identify the Apple event object with the specified properties.

As part of this process, the TOSADispatcher::ObjectAccessor method makes the following call:

resultObject = containerObject->GetContainedObject(
                           desiredClass, form, selectionData);
GetContainedObject is a method of MScriptableObject, so it can be overridden by any class that mixes in MScriptableObject. The ultimate container (the first object queried by the OSL when resolving an object specifier) is the application object. The TApplication class overrides GetContainedObject to look for contained files. If the desired object is not a file, it calls Inherited, which results in a call to MScriptableObject::GetContainedObject. That method looks for contained objects matching the desired name, relative position, range, unique ID, or absolute position.

To override the GetContainedObject method to return contained objects that match a form you are interested in, you perform the following steps:

  1. Define a class that mixes in the MScriptableObject class.
  2. Provide an override version of the GetContainedObject method.

The sample code shown in this recipe is taken from the MacApp TWindow class.

Define a Class That Mixes In the MScriptableObject Class

To override the GetContainedObject method, your class must descend from the MScriptableObject class or the MDefaultScriptableObject class, or from a class that mixes in one of those classes. Many MacApp classes (including TApplication, TDocument, and TWindow) mix in one of these classes, so you don't have to write any additional code for your application, document, or window classes to mix in the MScriptableObject class.

Provide an Override Version of the GetContainedObject Method

Your version of GetContainedObject should check for a contained object matching the form or forms it is interested in. If it doesn't find one, it should call MScriptableObject::GetContainedObject. The following is the GetContainedObject method from MacApp's TWindow class:

MScriptableObject* TWindow::GetContainedObject(
                              DescType    desiredType,
                              DescType    selectionForm,
                              const CAEDesc&selectionData)
{
   MScriptableObject * result = NULL;
   if (this->IsShown() && !fFloats)
   {
      if (gApplication->IsDocumentClass(desiredType))
         result = fDocument;
      else if (fDocument && (desiredType != cProperty)
               && (desiredType != this->GetOMClass()))
         result = fDocument->GetContainedObject(desiredType,
                              selectionForm, selectionData);
   }
   
   if (!result)
      result = MScriptableObject::GetContainedObject(desiredType,
                              selectionForm, selectionData);
      
   return result;
}
This code checks whether the desired type is a document or a property. If the desired type is a document (determined by calling the application object's IsDocumentClass method), this method returns the window's fDocument reference as the contained object. If the desired type is a property, it gives its document a chance to return the contained object. If the desired type is neither a document or a property, it calls the MScriptableObject::GetContainedObject method to look for other types.

Recipe--Installing a Custom Subclass of TOSADispatcher

By default, MacApp's scripting support creates a global Apple event dispatcher object (accessed through TOSADispatcher::fgDispatcher) of type TOSADispatcher. However, you can define a custom subclass of TOSADispatcher and cause MacApp to use your type instead. When you create a custom Apple event dispatcher, you still access it through TOSADispatcher::fgDispatcher.

To install a custom subclass of TOSADispatcher, you perform the following steps:

  1. Define your custom subclass of TOSADispatcher (not shown).
  2. Register your custom subclass.
  3. Call the InitUScripting method of your custom subclass.

The sample code shown in this recipe is for a generic application.

Define a Custom Subclass of TOSADispatcher

Several other recipes describe how to define a class, including "Recipe--Defining a Class," beginning on page 277, and "Recipe--Defining a Subclass of TApplication," beginning on page 289. This recipe assumes that you have defined a custom subclass of TOSADispatcher named TYourOSADispatcher.

Register Your Custom Subclass

You must register your custom subclass of TOSADispatcher so that the InitUScripting method will be able to create an instance of your class. You register your custom class with the following line:

MA_REGISTER_CLASS(TYourOSADispatcher);

Call the InitUScripting Method of Your Custom Subclass

You need to call the InitUScripting method of your custom subclass before calling IApplication. A reasonable place to do so is in your main function or in the initialization method of your application class, using code like the following:

void TYourApplication::IYourApplication()
{
   // Init your custom dispatcher BEFORE calling IApplication.
   TYourOSADispatcher::InitUScripting(&TYourOSADispatcher::fgClassDesc);

   this->IApplication(kFileType, kSignature);

   // Additional application initialization code, if necessary.
}
When IYourApplication calls TYourOSADispatcher::InitUScripting, the InitUScripting method creates an instance of TYourOSADispatcher and stores a reference to it in the static global variable TYourOSADispatcher::fgDispatcher.

Note
If you skip this step, InitUScripting will create an instance of TOSADispatcher rather than an instance of your custom class, TYourOSADispatcher.

Previous Book Contents Book Index Next

© Apple Computer, Inc.
25 JUL 1996