September 96 - Working With OpenDoc Part Kinds
Working With OpenDoc Part Kinds
Tantek Çelik and Dave Curbow
If you're ready to create your first full-featured OpenDoc part
editor but have some questions about part kinds and how to work
with them, you'll find the answers here. We explain how your
choice of part kinds will affect whether users will be able to read
your content with different part editors and even across different
platforms. We also discuss some human interface principles and
describe how to handle the most common user actions having to do
with part kinds.
We imagine that every computer user on earth has had the experience of trying to open
a document created by someone else but not being able to because the application it was
created with is missing. In the context of OpenDoc, users can run into this when the
part editor that created a part is missing. OpenDoc provides several ways to mitigate
this "missing editor" problem. One way is for developers to create and freely
distribute part viewers for all the kinds of parts that they support; a part viewer is a
subset of its corresponding editor's code that displays and prints a part's contents but
can't be used to create or edit a part.
But suppose a user doesn't have either an editor or a viewer for a particular part.
That's where part kinds come in. A part kind is a data format in which a part's
intrinsic content is stored, analogous to a file type in a traditional application.
OpenDoc allows a part editor to support multiple part kinds -- that is, to store the
same content in multiple data formats -- to increase the probability that a user will
be able to see and copy the contents of a part. A user who doesn't have the same part
editor that created a part may have a different part editor that can read at least one of
the data formats in which that part is stored. Alternatively, one or more of the data
formats can perhaps be translated into a part kind for which the user has an editor or
viewer.
What this means to you is that your choice of part kinds to support is a crucial step in
developing a part editor. This article discusses how to choose which part kinds to
support -- standard (to Macintosh or across platforms) or proprietary -- and
whether to support one or multiple part kinds. We also discuss how to decide which
category your part kinds fit into, some human interface principles having to do with
part kinds, and what to do in a few key situations in which user actions cause your
editor to have to deal with part kinds.
If you're not already familiar with the OpenDoc human interface, you should first read
"The OpenDoc User Experience" in develop Issue 22 to get up to speed. This article also
requires you to know something about OpenDoc storage and how to use the
ODStorageUnit class. "Getting Started With OpenDoc Storage" in develop Issue 24 is a
good introduction; further details can be found in the OpenDoc Programmer's Guide for
the Mac OS and its accompanying OpenDoc Class Reference CD.
CHOOSING YOUR PART KINDS AND CATEGORY
In developing your part editor, you first need to decide which part kind or kinds to
support. This choice is worthy of careful consideration. The decision you make about
whether to support standard vs. proprietary part kinds and how many part kinds to
support will affect the number of users able to read your content across documents and
platforms. We'll look at the tradeoffs here. We'll also give you the information you
need in order to decide which category or categories your part kinds fit into.
STANDARD VS. PROPRIETARY PART KINDS
First, you need to decide whether to support standard or proprietary part kinds, or
some combination of each. Standard part kinds are those data formats that, either
through an official decree or by some de facto means, have become widely used and
accepted. There are industry-standard part kinds, which are standard across more
than one platform, and standard Macintosh part kinds.
Because new data formats are being created all the time, we can't give you a complete
list, but here's a sample:
• industry standards -- ASCII, TIFF, GIF, JPEG, MPEG
• Macintosh standards -- TEXT, PICT, stxt, MOOV, 3DMF
Part kinds are usually specified as ISO strings (null-terminated ASCII strings using
7-bit characters) for manipulation by OpenDoc. As you can see from our list, standard
Macintosh part kinds are actually today's standard Macintosh file types, except that
instead of being file-type signatures they're ISO strings, which can be derived by
using methods of the class ODTranslation. (See the Data Interchange recipes on the
OpenDoc Class Reference CD for more details on how to properly support a standard
Macintosh part kind based on a standard Macintosh file type.) Your part editor needs to
provide user-readable names for part kinds in a name-mapping resource; more on
this later.
The ASCII standard is actually pretty loosely defined. It doesn't specify
whether you should use 7- or 8-bit encoding, nor does it say whether you
should use LF, CR, or CRLF for line separators. In the near future, Unicode,
which OpenDoc uses internally, is likely to become the standard. In the
meantime, your part may need to be prepared to handle several variants on the
ASCII standard without failure.
If the part kind you choose to support is an industry standard, users will benefit
because they'll be more likely to avoid the missing editor problem mentioned earlier.
Furthermore, supporting standard part kinds enables your part editor to support
more of the content that's already out there. Let's face it -- data formats don't live
forever, but the standard ones have a much better chance of being long-lived than any
proprietary kinds you create.
On the other hand, if there's no standard for the content your part editor creates, or if
the standard won't suffice to capture the functionality your part editor offers, you'll
need to create a proprietary part kind. You must weigh the advantages of using a
proprietary part kind against the disadvantage of users possibly not being able to read
your part's content.
In any case, don't redefine an existing standard. For example, the TEXT part kind
should be used only for plain text, not for some data format that uses text as part of its
definition, such as PostScript, HTML, or BinHex. These data formats should be part
kinds in their own right. Otherwise, there will be confusion when OpenDoc needs to
find a substitute part editor for a part that claims to be TEXT but is in fact another
kind such as HTML. The user won't be happy with the result.
If you decide to use an industry-standard part kind, the Bento container suite (part of
the storage system in OpenDoc 1.0) can help you solve internal byte-ordering
problems and ensure that a document written on any OpenDoc platform can be read and
written on any other OpenDoc platform. However, your part editor is responsible for
proper byte ordering of the values in the content property of your storage unit. (Data
formats typically specify byte ordering, so OpenDoc stays out of your way here.) The
Standard Type I/O utilities (see the file StdTypIO.h and the functions declared there)
solve the byte-ordering problem for a variety of simple data formats. These utilities
can be used in combination to build up more complex data formats.
SUPPORTING MULTIPLE PART KINDS
As we've said, your editor can support one or more part kinds. If it supports more than
one part kind, one of these will be the preferred kind. Users implicitly indicate the
preferred kind when they choose a stationery pad or cut and paste content. They can
also change the preferred kind in the Part Info dialog if they desire; more on this later.
Supporting multiple part kinds increases the probability that other users can see the
contents of a part created with your editor, even if they don't have your part editor
(see "Editor Substitution Explained" for why this is so). Your choice of part kinds to
support comes into play both when the user saves a document with parts created by
your editor and when the user transfers data with a paste or drop operation.
______________________________
EDITOR SUBSTITUTION EXPLAINED
When a user tries to open a document or edit a part and the editor that created
it is missing, OpenDoc searches for a substitute. This occurs as part of
OpenDoc's binding process -- the process of assigning the correct part editor
to a given part. When a document is opened, the OpenDoc binding subsystem
binds editors to all parts that need to be displayed. During execution, OpenDoc
binds editors to part data when a part is read in or when its editor is
explicitly changed.
Let's look at a simplified example of editor substitution. Suppose we've created
a text editor named SurfWriter that stores its content in three formats: a
proprietary part kind (SurfWriter Text) and two standard part kinds (RTF
and TEXT). And suppose that SurfWriter Text is the preferred kind. When
OpenDoc tries to display the part, its binding subsystem looks first for
SurfWriter -- the last editor that was used. If that isn't found, the binding
subsystem looks for an editor that can read SurfWriter Text -- the preferred
kind. If that can't be found, it looks for one that can read RTF or TEXT. Thus,
storing multiple part kinds increases the probability that users will be able
to read your content with different part editors and across different platforms.
Now let's look at editor substitution in a little more detail. When attempting to
find an editor to bind to a part, OpenDoc looks first for the editor that last
edited the part, specified in the kODPropPreferredEditor property in the
part's storage unit. If this editor isn't present on the user's system, the
binding subsystem examines each of the part kinds in the stored part and the
list of kinds supported by the editor or editors installed on the user's system,
looking for a match. For each supported kind, there's a default editor. The user
can inspect and modify the list of default editors in the Editor Setup control
panel (Figure 1).
Figure 1. The Editor Setup control panel
During the matching process, the binding subsystem looks first for the default
editor for the preferred kind. If this editor isn't present, it looks for the
default editor for the preferred kind's category, and finally for any editor that
can read the preferred kind. If such an editor can't be found, the binding
subsystem repeats the whole process for each of the remaining part kinds in
the part, from highest fidelity to lowest.
______________________________
If no editor for any of the part kinds is installed on the user's machine, the part
remains unviewable and uneditable. But OpenDoc still binds an editor to the part --
the "editor of last resort." This editor is always available and represents the part as an
icon within the document, so that there's never a blank spot in the document where a
part can't be displayed. The user can examine the part's kind in the Part Info dialog,
which gives a clue as to which editor or viewer should be installed, although if there's
no editor for the part, there's probably no user string for the preferred kind. The user
can also decide to translate the part to another part kind.
When deciding how many part kinds to support when your editor is saving its parts of
a document, you'll want to consider the tradeoff between portability and the space
required to store your part as multiple kinds. The most transportable part kind (that
is, the standard one) may not be the most compact or the one that will represent the
underlying contents with the greatest fidelity. Typically, you'll want to store only the
one preferred part kind, or the preferred kind and one standard part kind. If there
isn't a standard kind that's roughly equivalent to your preferred kind, consider also
storing a TEXT or PICT representation, simply to maximize the chances that the user
will be able to see something for your part. For example, if your part's preferred kind
is 3DMF, there isn't an equivalent standard kind, so you should also store a PICT
representation. You might want to present the user with a Settings or Preferences
dialog giving a choice of part kinds to store in addition to the preferred kind. See pages
476 and 479 of the OpenDoc Programmer's Guide for implementation details.
When your editor is providing data for a data transfer operation (such as a copy to the
Clipboard), you may want to write out a greater number of standard part kinds than
during a save operation. This is because during data transfer it's more likely that the
user is trying to move content to a different editor or application. Providing standard
part kinds in this situation is therefore even more important. On the other hand,
remember that the user can use the Paste As command to get more options, including
translation, so you needn't go overboard in supporting lots of kinds.
CATEGORY CONSIDERATIONS
After you've chosen the part kinds to support, you need to determine which category or
categories these belong to. A part category is a set of part kinds that are conceptually
similar. You might think of it as a generic term for several "brand name" variants.
For example, the kODCategoryStyledText category might include the part kinds
SurfWriter Text 3.0, SurfWriter Text 2.0, and others.
OpenDoc looks at a part's category to decide which part editors or part viewers can be
substituted if an editor is missing and whether to merge or embed data when content is
copied from one part into another. Categories are specified by your editor in a
name-mapping resource and can't be changed by the user.
Categories for existing part kinds have already been determined and should be adhered
to; this set of categories is broad enough to include most new part kinds as well. A list
of the predefined categories is given in Table 1. This list can be found in the OpenDoc
Programmer's Guide on pages 477-478, but note that a new category has been added
since the publication of the book: kODCategoryArchive.
Table 1. Predefined part categories
Part category Explanation
kODCategoryPlainText Plain ASCII text
kODCategoryStyledText Styled text
kODCategoryDrawing Object-based graphics
kODCategory3DGraphic 3D object-based graphics
kODCategoryPainting Pixel-based graphics