This section briefly summarizes some high-level aspects of the design and implementation of a part editor. It discusses:
OpenDoc is implemented as a shared library consisting of a set of SOM classes. The interfaces to SOM classes must be written in the SOM Interface Definition Language (IDL) and compiled by the SOM compiler, usually separately from the implementations of the classes.
The implementation of OpenDoc objects as SOM objects has several advantages to its use as a shared library:
Because OpenDoc consists of SOM classes, the class ODPart is naturally a SOM class. If you want your part editor, which is a subclass of ODPart plus any other classes that you define, to also consist of SOM classes, then you must write your interfaces in IDL, separately from your implementations, and you must compile them with the SOM compiler. The result of the compilation is a set of header and stub implementation source files, in one of the procedural or object-oriented programming languages supported by the SOM compiler. You complete your development by writing your implementations into the stub implementation files and compiling them, along with the headers, using a standard compiler for your programming language.
If you write your part-editor interfaces in IDL, you will notice that the IDL syntax is very similar to that of C and C++. It includes essentially the same character set, white space rules, comment styles, preprocessing capabilities, identifier-naming rules, and rules for literals. But there are a few differences in source-code appearance to note when declaring or calling methods of SOM-based objects:
Advantages of making all your classes SOM classes include a greater ability to develop portions of your part editor (or set of editors) using different programming languages and compilers, and a lesser need for recompilation of all of your code when you change portions of it. These advantages may be compelling only if your libraries are very large, however, because they must be balanced against the disadvantages of working in both IDL and a separate programming language.
You are not required to make your part-editor classes SOM classes. If you are developing in C++, for example, you can use C++ classes instead. The generally preferred procedure is to create only one SOM class, a subclass of ODPart whose interface contains nothing but your public methods (overrides of the methods of ODPart and its superclasses). That SOM class delegates all of its method calls to a C++ wrapper class, which contains the functionality for the public methods as well as any private fields and methods. Additional classes can be subclasses of your C++ wrapper class.
Advantages of developing in C++ with a single wrapper object include a lesser need to work with interfaces in two languages (IDL and C++), a smaller memory and calling overhead for your objects, and the availability of C++ features (such as templates) that are not supported by SOM.
SOM Class ID and Editor ID
A SOM class ID is an ISO string whose format is "module::className". A part editor's editor ID is a SOM class ID that uniquely defines the editor; you need to specify your editor ID in your editor's IDL interfaces. For example, the editor ID for AcmeGraph 1.0 might be "Acme::AcmeGraph". Editor IDs are used for binding; see "Information Used for Binding" for more information.
For a more detailed description of the Interface Definition Language and instructions on programming with SOM, see, for example, the SOMObjects Developer Toolkit Users Guide and SOMObjects Developer Toolkit Programmers Reference.
OpenDoc imposes very few restrictions on how your part editor does its job. The inner workings of your editor's core data engine are of little concern to OpenDoc. The engine should be able to free storage when requested, it should adequately handle cases where the part can be only partially read into memory, and it should handle any multiprocessing or multithreading issues that arise. Other than that, it simply needs to provide an interface to OpenDoc and use the OpenDoc interface to accomplish OpenDoc-related tasks.
The programming interfaces that your part editor uses (and provides) to perform specific tasks are called protocols. The methods of ODPart, for example, participate in approximately 12 protocols, such as part activation and undo. This section briefly describes the protocols; and Table 2 lists the methods of ODPart that you will have to override to participate in each protocol.
To implement the simplest possible part, you need to participate in only some OpenDoc protocols, and you need to override only some methods of ODPart. As a minimum, your part editor must be able to:
Unless it creates extremely simple parts, your part editor must also provide some sort of command interface to the user. It must then be able to
If you wish your parts to be able to contain other parts, your part editor must be able to
Beyond these capabilities, you may want your parts to have additional capabilities, such as drawing themselves asynchronously, providing data transfer capability, supporting scripting, or others. You can add those capabilities by overriding other methods of ODPart.
Your fundamental programming task in creating an OpenDoc part editor is to subclass the class ODPart and override its methods. The following list summarizes the OpenDoc protocols that your part editor can use, and lists the sections in this book that describe each protocol more fully. To create full-featured container parts, your editor must support all of these protocols.
The methods of ODPart involved in each protocol are shown in the table that follows this list.
All parts that are visible must participate in this protocol. The layout protocol is described, along with the embedding protocol, in "Frame and Facet Hierarchies".
All parts that are visible must participate in this protocol. The imaging protocol is described in "Canvases", "Transforms and Shapes", "Drawing", and "Printing".
Your part must participate in this protocol if it ever needs to be active or if it needs any of the other focus types. The activation protocol is described in "Focus Transfer".
Your part must participate in this protocol if it handles events. The user-events protocol is introduced in "User Event Handling" and is described in more detail in other parts of "User Events".
All parts must participate in this protocol. The part-storage protocol is described in "Storage Units, Properties, and Values" and "Documents, Drafts, and Parts".
Your part participates in this protocol if it is a container part (that is, if it is capable of embedding parts within itself). The embedding protocol is described in "Frame and Facet Hierarchies".
Your part must participate in this protocol if it supports clipboard transfer. The clipboard protocol is described in "Clipboard Transfer".
Your part must participate in this protocol if it supports drag and drop of its content elements or embedded parts. The drag-and-drop protocol is described in "Drag and Drop".
Your part must participate in this protocol if it supports linking. The linking protocol is described in "Linking".
Your part must participate in this protocol if it has an undo capability. The undo protocol is described in "Undo".
Your part participates in this protocol if it provides OpenDoc extensions. The extensions protocol is described in "OpenDoc Extension Interface".
In general, your part editor does not need to be concerned with memory management except to make sure that it deletes or releases objects that it has created or obtained. The memory-management protocol and the use of reference counting is further discussed in "Creating and Releasing Objects".
Table 2 lists the methods of ODPart that you must
override to have a functioning part editor, as well as those that you
can optionally override to participate in specific protocols. Note
that some protocols, such as layout, imaging, and activation, are
required of all part editors, and you therefore must override
some or all of the methods associated with them even if you do not
provide any code to implement the method.
Other protocols,
such as embedding or undo, are not required, and you therefore
need not override any of their methods if your parts do not
participate. It is, of course, strongly recommended that your
parts participate in all protocols
that are appropriate to their content model.
Table 2. Required and Optional ODPart Overrides
Protocol | Required overrides | Optional overrides |
---|---|---|
Layout |
AttachSourceFrame ContainingPartPropertiesUpdated DisplayFrameAdded DisplayFrameClosed DisplayFrameConnected DisplayFrameRemoved FacetAdded FacetRemoved FrameShapeChanged GeometryChanged Open SequenceChanged |
AcquireContainingPartProperties* RevealFrame* |
Imaging |
CanvasChanged Draw GetPrintResolution HighlightChanged PresentationChanged ViewTypeChanged |
AdjustBorderShape* CanvasUpdated* |
Activation |
AbortRelinquishFocus BeginRelinquishFocus CommitRelinquishFocus FocusAcquired FocusLost |
|
User events |
AdjustMenus HandleEvent |
CreateRootMenuBar
|
Storage |
CloneInto** ClonePartInfo Externalize** ExternalizeKinds InitPart InitPartFromStorage ReadPartInfo WritePartInfo |
somInit** somUninit** |
Binding | ChangeKind |
|
Memory Management | ReleaseAll** |
Acquire** Purge** Release** |
Linking | LinkStatusChanged |
BreakLink BreakLinkSource CreateLink EditInLinkAttempted* FulfillPromise*** LinkBroken LinkUpdated RevealLink ShowLink UpdateFromLinkSource |
Embedding |
|
CreateEmbeddedFramesIterator* EmbeddedFrameUpdated RemoveEmbeddedFrame* RequestEmbeddedFrame* RequestFrameShape* UsedShapeChanged* |
Clipboard |
| FulfillPromise*** |
Drag and Drop |
|
DragEnter DragLeave DragWithin Drop DropCompleted FulfillPromise*** |
Undo |
|
DisposeActionState ReadActionState*** RedoAction UndoAction WriteActionState*** |
Extensions |
|
AcquireExtension** HasExtension** ReleaseExtension** |
Generally, you must override all of the optional methods listed for a given protocol (other than those marked with *** in Table 2) if you are to participate in that protocol. For example, to participate in the extensions protocol, you must override methods AcquireExtension, HasExtension, and ReleaseExtension. The embedding protocol has even further requirements; to support embedding, you must not only override all the optional methods listed for that protocol, but you must override several methods associated with other protocols (marked with * in Table 2).
This section provides a high-level discussion of several possible OpenDoc development scenarios. Reading the scenarios may help you to decide what kinds of OpenDoc component software you are most interested in developing. Specifically, it discusses
Writing a part editor that does not support embedding is somewhat simpler than writing an editor that does. Furthermore, if you are starting from scratch (not modifying an existing application), you are free to consider all aspects of the design of your part editor before you implement anything.
You ship your product as one or more part editors, plus an install program and accompanying documentation. Users install your part editor into their systems and then, using the stationery part that gets control at part registration time, create new documents of your part kind or insert new parts with your part kind into their documents. See "Stationery" for information about stationery. Rules and conventions for installing part editors and storing documents vary among platforms. For platform rules, see the recipe "Installation of OpenDoc Software".
Users themselves can create additional, customized stationery documents. Users will be able to exchange documents, including stationery, freely.
If your part editor is to support embedding (that is, if its parts are to be container parts) you need to include the following additional steps:
For a summary of the issues to consider in creating a part editor for container parts, see Appendix A. "Embedding Checklist".
Creating a part editor from an existing conventional application involves maintaining its core features but repackaging them for the OpenDoc environment.
If your converted application is to be a container part, you need to follow these additional steps:
This book primarily describes how to create a part editor. However, you are not limited to that alone. Development of container applications is discussed briefly in the previous section. Using the OpenDoc class libraries, you can also create other kinds of OpenDoc component software:
Development issues for part viewers are a subset of those for fully functional part editors. A part viewer is usually much smaller than its corresponding editor, and it can be developed from the same code base.
To encourage data interchange, you should always create a part viewer for every part editor you develop, and you should distribute the viewer widely and without cost or obligation to the user.
You develop an OpenDoc service much as you develop a part editor. Like part editors, services are subclasses of ODPart. However, services commonly use less of the embedding, layout, and imaging protocols of OpenDoc, and they usually communicate with the parts they serve through an extension interface (a subclass of ODExtension). The extension interface is described in "Extending OpenDoc".