Title Banner

Previous Book Contents Book Index Next

Inside Macintosh: OpenDoc Programmer's Guide / Part 2 - Programming
Chapter 9 - Semantic Events and Scripting


Scripting and OpenDoc

Scripting is a powerful way to automate and customize programs. By adding scripts to a program and executing them, a user can simplify and automate tasks that might otherwise require extensive and repetitive human interaction. If the program allows, a user might even be able to use scripts to change the meaning of existing commands. As a simple example, a user might customize the meaning of a "Save" command so that it updates a logging database every time a document is saved.

OpenDoc allows for scripting of semantic events, distinguished from user events in that they are high-level actions understandable by the user and by the program but independent of individual user actions. Semantic events can be used to open, close, and save documents; embed parts; and manipulate part content and appearance.

OpenDoc supports your part editor's ability to receive and process semantic events through its semantic interface, a set of classes providing methods that you can use or override. The class ODSemanticInterface is a subclass of the extension class (ODExtension), described in Chapter 10, "Extending OpenDoc." You use a subclass of the semantic interface class and possibly one or more utility classes to set up and register semantic-event handlers and callback functions. (OpenDoc also supports your part editor's ability to create and send semantic events through another object, the message interface, an object of the class ODMessageInterface.)

Any entity that understands the semantic interface of a part can send it semantic events. Script editors can convert scripting commands to semantic events and send them to any object in any part of a document. Parts can send semantic events to their containing parts, to embedded parts, to sibling parts, to linked parts--to any parts for which they can find an address. Other types of OpenDoc components can also send semantic events; spelling checkers, for example, can use them to operate on the content of text parts.

Scripting support in OpenDoc can be pervasive; if you take full advantage of it, literally every action a user can take may invoke a script. However, a range of options exists, and you can decide what level of scripting support makes the most sense for your parts.

Your part editor supports scripting through the OpenDoc semantic interface in much the same way as a conventional application supports scripting. Your part editor must provide an interface to its content objects and operations, and it must accept semantic events. The document shell passes semantic events to OpenDoc to deliver to your parts. Event targets are described by object specifiers, which refer to objects in your parts in terms of your published content model. The document shell needs information from your part editor to resolve these specifiers so that it can determine where to deliver the events.

The Open Scripting Architecture

The scripting capability of OpenDoc is based on the Open Scripting Architecture (OSA). OSA is a powerful cross-platform messaging and scripting system that can support multiple scripting languages. OSA has three basic components: the Apple events messaging system, the Apple events object model, and one or more scripting systems. This section gives a brief summary of these components. For complete documentation of OSA, see Inside Macintosh: Interapplication Communication.

Apple Events

The system of semantic events at the base of the OpenDoc implementation of OSA on the Mac OS is Apple events. Apple events are described in the Apple events chapters of Inside Macintosh: Interapplication Communication.

Apple events are messages that applications use to request services and information from each other. The application making the request constructs and sends an Apple event to the application receiving the request. The receiving application uses an Apple event handler to extract pertinent data from the Apple event, perform the requested action, and possibly return a result.

Apple events constitute a standard vocabulary of actions that can be requested. Apple events are grouped into suites of related events. The Apple Event Registry: Standard Suites describes several commonly implemented suites. The most important suite to support for general scriptability is the Core suite, the suite that contains events common to many kinds of application software.

When sending an Apple event, the sending application can specify that the event apply, not to the receiving application as a whole, but to some element of the receiving application's data. For example, an application can request the data of a particular row of a particular table in a particular report. The sender constructs an object specifier, which it sends along with the Apple event, denoting the exact element or elements to which the event applies. The Apple Event Registry includes definitions of the kinds of objects recognized within each suite.

The Apple Event Manager is the component of system software that manages the construction, sending, and processing of Apple events. It handles Apple events in general and dispatches events for conventional applications. With OpenDoc, Apple events and the Apple Event Manager function essentially as described in Inside Macintosh: Interapplication Communication; however, there are some differences caused by the differences between parts and conventional applications.

At run time, OpenDoc handles semantic events by accepting the events and passing them to the appropriate part editor. There is no separate dispatcher object for semantic events; the OpenDoc dispatcher that handles user events also dispatches semantic events.

Apple Event Object Model

OpenDoc relies on the Apple event object model to specify individual elements of a part's content. The object model defines a hierarchical arrangement of content objects, whose nature depends on the content model of the part. Apple events have object specifiers in their direct parameters to access individual content objects within a part. Part editors provide object accessor functions, used by the name resolver's Resolve method to resolve the object specifiers in Apple events that the parts receive.

The Apple event object model used by OpenDoc is slightly different from that used by conventional applications. Here are the differences:

Your part editor should implement object accessors as if your part were a stand-alone conventional application--that is, with your part itself as the context.

Scripting Systems

A scripting system completes the OSA implementation on a platform. It is through a scripting system that the user designs, attaches, and executes code to generate the semantic events that a scriptable part receives.

Any OSA-compliant scripting system can be used with OpenDoc. On the Mac OS platform, AppleScript and UserLand Frontier are two examples. Other platforms may use these or other OSA scripting systems.

OpenDoc allows the user to employ any available scripting system and even to switch among them during execution.

Part Content Model

To fully support scripting of your parts, you must construct a content model for your parts. The model must include a full set of content objects, accessible through semantic events, that allow a complete range of operations on your user-visible content. Your part editor must provide accessor functions to resolve external references to content objects, and it must also provide semantic-
event handlers that implement content operations.

Developing a content model and implementing the functions for resolving object specifiers and handling semantic events give great advantages. You increase flexibility and you provide user control over the basic functions of your part editor. For example, your parts will automatically be able to accept input from currently unavailable or unforeseen user interfaces, such as voice or pen or touch, that generate semantic events.

If you also factor your part editor--that is, if you separate your part editor's core data engine from its user interface--you increase its flexibility even further. Interface elements such as menus and dialog boxes, if reconstructed to invoke scripts or otherwise generate semantic events, will still be able to communicate directly with your parts. Factoring also facilitates making your parts recordable (page 414).

Content Operations

The operations of a content model should be consistent with user actions. They typically include selection, creation, deletion, insertion, setting of properties, and so on. Low-level internal functions, such as piece-table functions for efficient text insertion or matrix inversion for fast graphics processing, are probably not appropriate as content-model operations.

Your content operations correspond to the semantic events you support. You implement a semantic-event handler for each operation.

Content Objects

The objects of a content model should be consistent with the elements that the user sees and manipulates, regardless of your part editor's internal structures. Inside a text part, for example, a user may see lines, words, paragraphs, characters, and embedded parts. Those are typical content objects for such a part. Internally, your part editor might maintain run-length encoding arrays, line-end arrays, and so on. However, because they are not presented to the user, they are not part of the content model. Likewise, a graphics part might have content objects such as circles, rectangles, and lines, regardless of what internal mathematical descriptions it uses.

If a part supports embedding, embedded parts within it constitute a special class of content objects. The containing part can use content operations to manipulate the frames of embedded parts and perhaps some part-wide display properties, but it cannot in general manipulate their contents; only the parts themselves can do that.

The OpenDoc default object accessors already provide this basic ability to access the properties of, and send semantic events to, embedded frames. If your part is a container part and needs capabilities beyond this basic level, your object model can include a named type of content object that represents an embedded part to which you can pass events and from which you can extract properties.

User selections
If you want to make user selections controllable through semantic events, you must describe them with object specifiers appropriate to your part's content model. In most cases, you should allow a selection to be specified both by description ("word 1 to word 5 of 'Gettysburg Address'") and by contents ("Fourscore and seven years ago").

Resolving Object References

Object specifiers in an Apple event can refer to any content objects, including embedded parts. When it receives Apple events, your part must provide accessor functions to allow those specifiers to be resolved. The accessor functions of a part return tokens, descriptors that identify the content objects or properties of those objects.

As an example of object resolution, consider a document whose root part is a text part. The part contains several embedded parts, including a bar chart named "sales chart". Suppose that the user employs a script editor (or possibly a scriptable tool palette) to send a command to change the bar chart to a pie chart. A Set Data event with the part name "sales chart" as the direct parameter goes to the OpenDoc message interface, which must resolve the object specifier in the direct parameter before dispatching the event itself.

The message interface asks the document shell to identify the part named "chart part". The document shell cannot, so the message interface asks the root part. The root part's object accessor recognizes the name of the chart part and passes back a token representing the part's frame. The message interface then asks the root part to identify the "chart type" property. The root part cannot, so it returns a token that causes resolution to be passed onto the embedded part itself. The message interface asks the embedded part's object accessor to identify the "chart type" property. The accessor does and returns a token for it. The message interface inserts the token into the semantic event and dispatches the event to the embedded part's semantic-event handler. The handler then changes the chart to a pie chart.

Object accessor functions and object-specifier resolution are described in more detail in the section "Writing Object Accessors"

Levels of Scripting Support

You can implement different levels of support for scripting in your part editor. Each successive level requires more effort, but each gives the user greater flexibility and control over the functioning of your parts.

Scriptable Parts

If you make your parts scriptable, they will have at least a basic level of scripting support. To do that, you must create a content model for your parts with defined content objects (available through object accessors) and content operations (represented by semantic-event handlers) that are meaningful to the user. Then your part editor publishes a description of its content objects and operations and accepts semantic events.

Even among scriptable parts there are different levels of support. You can allow script access to only a few content objects and operations or to many of them. For your parts to be fully scriptable, semantic events must be able to invoke any action a user might be able to perform.

One advantage of making your part scriptable is that you can allow it to be used by other parts, even parts that you may not have developed yourself. For example, if your part is a text part and you allow script access to all of its text-style settings, the user (or your containing part or a sibling part) can easily format any of your text for any purpose.

Recordable Parts

If you make your parts recordable, the user's actions can be captured as a series of semantic events, converted to scripts, and replayed at a later time to reenact the actions. A recommended way to make your parts recordable is to completely separate the user interface from the core data engine of your part editor.

If your part editor handles every user-interface event by generating, sending to itself, and handling an equivalent semantic event, it can process all semantic events through a standard bottleneck and have the Apple Event Manager record the actions. This use of a bottleneck not only allows recording but also enhances code portability.

The events that pass through the bottleneck should be just the set of actions that match your part's content model. These events need not follow exactly the inner design of your core data engine, but they should reflect the complete range of user actions.

Customizable Parts

If you make your part's interface customizable, the user can not only invoke all actions through scripts but can also change the nature of the actions themselves by attaching additional scripts that are invoked when the actions are executed.

To support customizable parts, you must make your parts scriptable, and you must also define content objects and operations for interface elements such as menus and buttons, or provide other ways to trigger scripts. You must provide persistent storage for any scripts that the user attaches to your part's interface elements.

Making your part fully customizable requires that you allow attachment and invocation of scripts during virtually any user action. For the highest levels of customizability, all menu commands and all editing actions should be scriptable.

Before processing any user event or semantic event, your part editor must check whether a script attached to the part wants to handle the event. If so, you allow the script to run.

If your parts are recordable, they are already almost customizable. Because for recording purposes you typically check for the presence of and invoke scripts in a semantic-event dispatching bottleneck, you can achieve full customizability with little extra effort.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
16 JUL 1996




Navigation graphic, see text links

Main | Page One | What's New | Apple Computer, Inc. | Find It | Contact Us | Help