Programming Guide: OpenDoc Storage System

# Programming Guide

## OpenDoc Storage System

The OpenDoc storage system is a high-level mechanism for persistent or ephemeral storage that enables multiple part editors to effectively share a single document. The storage system is implemented on top of the native storage facilities of each platform that supports OpenDoc.

The OpenDoc storage system effectively gives each part its own data stream for storage and supports reliable references from one stream to another. The system includes a robust annotation mechanism that allows many pieces of code to access information about a given part without disturbing its format.

The identity of a part is consistent within a session; it is unique within its draft and testable for equality with other part identities. Parts can persistently reference other objects in the same draft, including other parts, thus allowing run-time object structures to be saved and reconstructed in a future session.

Parts have more than just their content to store persistently. Properties are used to store both the content of the part and supplemental information. OpenDoc defines a standard set of properties for all parts, and you can assign additional properties to a given part. The name of the preferred part editor is one example of a standard property that can be stored with a part.

The storage system allows OpenDoc to swap parts out to external storage if memory is required for other parts. When a part is first needed, its part editor reads it from external storage into memory. When it is no longer needed, the draft releases it. If the part is needed again at a later time, the storage system can either return the in-memory part to the part editor or, if the part has been deleted because of low memory, bring the part once again into memory from storage. When it reads or writes its parts, your part editor may not know whether the data is currently being transferred to or from memory, or to or from external physical storage.

### Storage Units, Properties, and Values

The OpenDoc storage system is not an object-oriented database. It is a system of structured storage, in which each unit of storage can contain many streams. This design eases the transition for developers working with existing code bases, which generally assume stream-based I/O.

The controlling storage object is the storage system object, which instantiates and maintains a list of containers. The containers are objects in the container suite, a platform-specific storage implementation. OpenDoc is released with the Bento container suite, a container suite that can be used with or independently of OpenDoc.

Each container object in a container suite can hold one or more document objects, each of which, in turn, contains one or more draft objects. Each draft contains a number of storage unit objects, each of which is much like a directory structure in a typical file system (although multiple storage units might be physically stored in a single file, or perhaps not stored in files at all). Storage units hold the streams of stored data.

The run-time relationships of these storage objects are diagrammed in Figure 76.

#### Storage-Unit Organization

You can visualize a storage unit as a set of properties, or categorized groups of data streams. A property is identified by its property name, an ISO string. Each property consists of a number of streams called values, each of which stores a different representation of the same data, in a format identified by a named type (a value type, also an ISO string). Thus there can be several properties (named categories) in a single storage unit, and several values (typed streams) in a single property.

Figure 57 shows these relationships through a simplified diagram of the organization of a storage unit.

Figure 57. Organization of a Storage Unit

View figure.

Figure 58 is a simplified diagram of a specific storage unit in use. The storage unit contains a figure caption. The part that owns this storage unit has created a contents property, which contains the primary data of this storage unit, as well as a name property, which names the item stored in this storage unit. This particular storage unit has three representations of the contents property (the text of the caption) as three different types of values: its own custom styled text, plain text in a standard (international) text format, and a bitmap. The storage unit has only one representation of the name property.

Figure 58. Example of a Storage Unit with Several Properties and Values

View figure.

A caller that accesses this storage unit can read or write just the data of immediate interest. In the storage unit of Figure 58, for example, a caller could access only the value representing one of the data formats in the contents property without having to read the rest of the storage unit into memory. A caller could learn the part kinds of the data stored in the storage unit without having to read any of the contents into memory, even if the part editor that stored the data is not present.

Fundamental to the OpenDoc storage system is the concept that all values within a property are analogous, or equivalent, representations of the same data. Every value in the contents property in Figure 58, for example, is a complete representation of the item's contents, (the caption text), expressed in the type of data that the value holds.

Values in a storage unit can include references to other storage units, as described in "Persistent References". Thus, storage units can be arranged in ordered structures such as hierarchies; OpenDoc stores the embedding structure of a document in this way.

#### Standard Properties

A basic feature of the OpenDoc storage system is that storage units are inspectable; that is, one can extract the data (values) of the various properties of a storage unit without first having to read the entire file or document that the storage unit is part of, and without having to understand the internal format of the data in any of the values. For example, if the storage unit for an embedded part includes a property that holds the part's name, you can extract that name without having to read in all the data of the part, even if you do not understand how to read or display the part's contents.

To make the inspectability of storage useful across parts, documents, and platforms, OpenDoc publicly specifies certain standard properties, with constant definitions such as kODPropContents and kODPropName, that all part editors can recognize. Documents, windows, frames, and parts all have basic structures, defined by properties, that are accessible from both the stored and in-memory states. This accessibility allows OpenDoc and part editors to read only the information that is needed in a given situation and thus increase performance. Table 7 and Table 8 list many of the common standard properties that might be found in storage units.

Using storage-unit methods, you can access the values of any known property of any storage unit.

##### OpenDoc ISO String Prefix

All public ISO string contants defined by OpenDoc include a prefix that identifies them as OpenDoc ISO strings. This is the prefix:

    +//ISO 9070/ANSI::113722::US::CI LABS::

Following the prefix is a designation that represents either OpenDoc as a whole, a specific platform, or a specific developer (company name). Therefore, the full ISO string definition for the property kODPropContents, for example, is

    +//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Property:Contents

All defined property names and data types should include the OpenDoc ISO string prefix. Value types in a storage unit (such as part kinds) should not.

#### Creating Properties and Values

If you have a reference to a storage unit, you can add a property to it and then add several values to that property. For the example illustrated in Figure 58, for example, you might use statements such as these (in which the storage unit reference is su):

    su->AddProperty(ev, kODPropContents);
    su->AddValue(ev, kODIntlText);
    su->AddValue(ev, kCustomTextKind);
    su->AddValue(ev, kMyBitmapKind);

These statements add the property kODPropContents to the storage unit and give it one standard (kODIntlText) and two custom (kCustomTextKind and kMyBitmapKind) value types. The kODPropContents property is a standard property name; you can add your own custom property and value types to a storage unit, using statements such as this:

    su->AddProperty(ev, kPropAnnotations);
    su->AddValue(ev, kMyAnnotationsType);

These statements only set up the storage unit to receive data of a particular type; you then need to explicitly store the data in the values. To do so, you must first focus the storage unit, setting it up so that the data you write will be written to the desired value of the desired property.

#### Focusing a Storage Unit

Because any storage unit can contain a number of properties, and any property a number of values, finding the exact piece of data in an OpenDoc document can be more complex than finding it in a conventional document. OpenDoc allows you to focus a storage unit, that is, access the desired data stream (defined by property name and value type) within it before reading and writing.

You focus on a particular stream by calling the storage unit's Focus method and providing some combination of the following three types of specification:

- Name: property name or value type

- Index: the position of the property in the storage unit or the value in the property

- Position code: a code that allows you to specify, for example, the next or previous sibling (a sibling is another value in the same property, or another property in the same storage unit)

If you are not focusing by relative position, you specify a position code of kODPosUndefined when you call the Focus method. For example, all of the following calls would focus on the first value of the contents property of the storage unit shown in Figure 58,

- The names of the property and value:

      su->Focus(ev,
                kODPropContents,         // Property name
                kODPosUndefined,
                kODIntlText,             // Value type
                0,
                kODPosUndefined);

- The name of the property and the indexed position (1-based), within its property, of the value:

      su->Focus(ev,
                kODPropContents,         // Property name
                kODPosUndefined,
                kODNULL,
                1,                       // Value index
                kODPosUndefined);

- The relative positions, compared to the current focus, of the property and value:

      su->Focus(ev,
                kODPropContents          // Property type
                kODPosUndefined,
                kODNULL,
                0,
                kODPosFirstSib);         // Position code

- The storage-unit cursor that specifies the property-and-value pair you want:

      su->FocusWithCursor(ev, cursor);   // Storage-unit cursor

A storage-unit cursor is an OpenDoc object that may be convenient if you frequently switch back and forth among specific property-and-value combinations. You can create a number of objects of class ODStorageUnitCursor, initialize them with the storage-unit focuses you need, and pass a storage-unit cursor to the Focus method each time you wish to switch focus. You can set up a storage-unit cursor either by explicitly specifying the property and value of its focus, or by having it adopt the current focus of an existing storage unit.

Once you have focused the storage unit, you can read and write its data, as described next.

#### Manipulating the Data in a Value

To read or write the data of a value, remove data from a value, or insert data into a value, you first focus the storage unit on that particular value.

- To write data at a particular position in a value, call the SetOffset method to set the position of the insertion point in the value's stream, followed by the SetValue method to write the data.

  The SetValue method takes a buffer parameter of type of type ODByteArray; see "Handling Byte Arrays and Other Parameters" for more information on byte arrays. For example, to write information from the buffer pointed to by dataPtr into the value at the position desiredPosition, you could set up the byte array myData as shown and then call two methods:

      ODByteArray myData;

      myData._length = dataSize;
      myData._maximum = dataSize;
      myData._buffer = dataPtr;

      su->SetOffset(ev, desiredPosition);
      su->SetValue(ev, &myData);

  To read the data at a particular position in a value, call the SetOffset method, followed by the GetValue method to read the data. To read information from the position desiredPosition in the value into a buffer specified by the byte array myData, you could make these calls:

      su->SetOffset(ev, desiredPosition);
      su->GetValue(ev, dataSize, &myData);

  You could then extract the data from the buffer pointed to by myData._buffer.

- To read or write data at the current offset in a value, simply call GetValue or SetValue without first calling SetOffset. To insert data at a particular offset, without overwriting any data already in the value, call the InsertValue method (after having called SetOffset, if necessary).

- To append data at the end of a value, call GetSize to get the size of the value, then call SetOffset to set the mark to the end of the stream, and then call SetValue to write the data into the stream.

- To remove data of a particular size from a particular position in a value, call SetOffset to set the mark to the desired point in the stream, and then call DeleteValue to delete data of a specified length (in bytes) from the stream.

Note:

> If you change the data in one value of a property, remember that you must make appropriate changes to all other values of that property. All values must be complete and equivalent representations, each according to its own format, of the information the property represents.

#### Iterating through a Storage Unit

To examine each of the properties of a storage unit in turn, access them in this way:

1. Call the Focus method of the storage unit, passing null values for property name and value type, and kODPosAll for position code. The null values plus kODPosAll "unfocus" the storage unit (that is, focus it on all properties).

2. Get the number of properties in the unfocused storage unit by calling its CountProperties method.

3. Focus on each property in turn, by iterating through them using a relative-position method of focusing:

       su->Focus(ev,
                 kODNULL,
                 kODPosNextSib,           // Position code
                 kODNULL,
                 0,
                 kODPosUndefined);

To examine in turn each of the values in a property of a storage unit, you access them in a similar way:

1. Focus the storage unit on the desired property by calling its Focus method and passing the desired property name and kODPosAll for relative position of value. Using kODPosAll focuses the storage unit on all values of that property.

2. Get the number of values in the property, by calling the CountValues method of the focused storage unit.

3. Focus on each value in turn, by iterating through them using a relative-position method of focusing for the values, while maintaining the same property position:

       su->Focus(ev,
                 kODNULL,
                 kODPosSame,              // Position code
                 kODNULL,
                 0,
                 kODPosNextSib);          // Position code

#### Removing Properties and Values

You can remove a property from a storage unit by:

1. Focusing on the property to be removed; call the Focus method and pass it a specific property name and a value position of kODPosAll.

2. Remove the property, by calling the Remove method on the focused storage unit.

You can remove a value from a property in a storage unit by:

1. Focusing on the value to be removed; call the Focus method and pass it a specific property name and a specific value type.

2. Remove the value; call the Remove method of the focused storage unit.

#### Storage-Unit IDs

At run-time, the draft object assigns an identifier to each of its storage units. A storage-unit ID is a non-persistent designation for a storage unit that is unique within its draft (storage-unit IDs are not unique across drafts and do not persist across sessions). You can use the ID to identify storage units, to compare two storage units for equality at run-time, and to recreate persistent objects from their storage units.

Just as object references are the basic run-time identifiers for OpenDoc objects, storage-unit IDs are the basic run-time identifiers for the storage units of persistent objects (subclasses of ODPersistentObject). Methods that manipulate storage units often take a storage-unit ID as a parameter; ODDraft::AcquireStorageUnit and ODDraft::ReleaseStorageUnit are examples.

For purposes in which the object unit or its storage unit as a whole is passed or copied, an ID is better than a run-time object reference. For example, storage-unit IDs are used when cloning persistent objects (see "Persistent References and Cloning"). Using a storage-unit ID ensures that the copying occurs even if the storage unit's object is not in memory at the time. However, OpenDoc first looks for the object in memory; if it is there, OpenDoc uses it rather than its storage unit.

You generally create a persistent object from storage by passing a storage-unit ID to the object's factory method (such as ODDraft::AcquireFrame and ODDraft::AcquirePart). You can also conveniently retrieve persistent objects that may or may not have been purged (such as frames scrolled out of and then back into view) by retaining the storage-unit ID for the object when you release it, and then supplying that ID when you need it again. Note also that, in discussions that refer to part ID or object ID for any persistent object, the ID being referred to is a storage-unit ID.

Storage-unit IDs are not persistent. Therefore, to get the correct storage-unit ID when creating a stored persistent object, a caller must have access to another, more permanent means of identifying a storage unit. For that purpose, OpenDoc uses persistent references. OpenDoc provides methods (such as ODDraft::GetIDFromStorageUnitRef) for obtaining a storage-unit ID from a persistent reference, and vice versa (such as ODStorageUnit::GetStrongStorageUnitRef).

#### Persistent References

A persistent reference is a number, stored somewhere within a given storage unit, that refers to another storage unit in the same document (see Figure 59). The reference is preserved across sessions; if a document is closed and then reopened at another time or even on another machine, the reference is still valid.

Figure 59. Persistent References in a Storage Unit

View figure.

Persistent references allow data to be placed into multiple storage units. The storage units reflect the run-time objects whose data they store; the persistent references permit the reconstruction of the run-time relationships among those objects in subsequent sessions.

##### Persistent References in OpenDoc

OpenDoc uses persistent references in several situations, including these:

- The stored data in a draft includes a list of persistent references to the root frames of all windows. When a document is opened, the root frames can then be found and their windows reconstructed.

- A stored frame has a persistent reference to its part. When a frame is read into memory, it can then find the part it displays.

- A stored part has persistent references to all of its embedded frames. When a part is read into memory, it can then find all of the embedded frames that it contains. Persistent references to embedded frames are essential to embedding; parts have no access to their embedded parts except through embedded frames.

- A stored part also may have persistent references to all of its display frames. When a part is read into memory, it can then find all of the frames that display it.

- Parts can also use persistent references for hierarchical storage of their own content data.

Figure 60 is a simplified diagram showing the persistent references among stored objects in an OpenDoc Document. (The difference between the strong and weak persistent references referred to in the figure is explained in "Persistent References and Cloning").

Figure 60. Persistent References in a Document

View figure.

##### Creating Persistent References

To create a persistent reference, you first focus the storage unit on the value whose data stream is to hold the reference and then call the storage unit's GetStrongStorageUnitRef or GetWeakStorageUnitRef method, passing the ID of the storage unit that is to be referred to. You then store the returned reference in the focused value in a format consistent with the type of the value. Such a reference is then said to be from the value to the referenced storage unit.

A persistent reference is a 32-bit value of type ODStorageUnitRef. You can create and store a virtually unlimited number of persistent references in a storage unit value; each persistent reference that you create from a particular value is guaranteed to be unique. Do not try to inspect or interpret a persistent reference; the classes ODStorageUnit and ODStorageUnitView provide methods for manipulating them.

Note:

> The scope of a persistent reference is limited to the value in which it was originally created and stored. Do not store it in a different value; it will almost certainly no longer refer to the correct storage unit.

Once a persistent reference is no longer needed, you should remove it from the value in which it was written. Extra persistent references threaten the robustness and efficiency of execution. A storage unit is aware of all persistent references that it holds, even those that a part editor may have stored within its contents property. OpenDoc provides an iterator class, ODStorageUnitRefIterator, through which a caller can retrieve all persistent references in a given value.

##### Persistent References and Cloning

There are two kinds of persistent references: strong persistent references and weak persistent references. They are treated differently in cloning.

To clone an object is to make a deep copy of it: not only is the object itself copied, but also all objects that it references (plus the objects that they reference, and so on). The cloning process is described further in "Cloning".

In a clone operation, copies are made of all storage units referenced with a strong persistent reference in the object being cloned. Storage units referenced with a weak persistent reference are not copied.

The use of weak persistent references allows you to clone only portions of a document or other structure of referenced storage units. Figure 61, which shows the persistent references among a stored frame and part plus their embedded frame and part, illustrates how cloning gives different results, depending on which references are strong and which are weak.

Figure 61. Cloning Objects with Strong and Weak Persistent References

View figure.

For example, if you were to clone the containing frame (A) in Figure 61, all four objects in the figure would be cloned, representing the containing frame and part plus its embedded frame and part. If, however, you were to clone the containing part (B), only the part plus its embedded frame and part (C and D) would be cloned, even though the containing part includes a persistent reference back to its display frame (A). Likewise, if you were to clone the embedded frame (C), only the frame and its part (D) would be cloned.

You define a persistent reference as weak or strong by calling either the GetStrongStorageUnitRef or the GetWeakStorageUnitRef method of the storage unit that is to hold the reference.

###### Stored Display Frames

You should store your part's display frames persistently. This will ensure that the part can be closed and will look the same if it is reopened later. If you do store display frames, however, make sure that your part's persistent references to them are weak references. This will enable you to clone the part without its display frame(s), so that the clone can have its own display frame(s).

#### Main and Auxiliary Storage Units

Every part (or other persistent object) has a single main storage unit, whose kODPropContents property stores the content of that object. In most cases, you can simply write all of your part's data as a stream into that one storage unit. It is possible, however, to create auxiliary storage units that hold additional data related to the data in a main storage unit.

The procedure involves creating a strong persistent reference to the auxiliary storage unit and storing this reference in your main storage unit. You can subsequently retrieve the reference and convert it into an object reference to the auxiliary storage unit. See "Creating Additional Storage Units" for more information.

#### Prefocused Access with Storage-Unit Views

A storage-unit view is an OpenDoc object that represents a prefocused access to a storage unit. The class ODStorageUnitView has most of the functionality of the class ODStorageUnit, except that it has no methods for accessing different properties and values. A storage-unit view does not in itself store data; each storage-unit view is associated with a specific storage unit that actually does the storing. Calls you make to the storage unit view are passed to its associated storage unit.

Several methods of several OpenDoc classes take a storage-unit view as a parameter. The ODPart methods FulFillPromise, ReadPartInfo, WritePartInfo, ReadActionState, and WriteActionState, for example, all make use of storage-unit views. When one of your methods receives a storage-unit view as a parameter, the method can read from the storage-unit view or write to it without first focusing on any property or value or locking the storage unit.

You can, if desired, create storage-unit views to pass prefocused storage units among your software components, or to any OpenDoc objects (such as ODNameSpace) that you might create, and whose methods take storage-unit views.

### Documents, Drafts, and Parts

Compound documents are fundamental to OpenDoc, and each compound document is represented by a document object. Documents are composed of one or more drafts. This section discusses the relationship of documents to drafts and to parts, describes how part data is stored, and discusses the objects that a document comprises.

The document object is responsible for creating and deleting drafts, for storing the identity of the current draft, and for collapsing multiple drafts into one. Your part editor rarely interacts directly with its document object. However, see "Creating a New Document" for information on creating a document object.

#### Drafts

A draft is a specific version of an OpenDoc document. Multiple drafts can be maintained within a single document. There is always at least one draft, the base draft, within a document. An individual draft can be extracted from a document and placed in a new document for editing.

Drafts are created by users with the help of the document shell, and maintained by the container suite. Figure 15. shows an example of the Drafts dialog box, with which the user views and manipulates the drafts of a document. A user can save the current state of the document as a new draft at any time. In general, your part editor can ignore the existence of separate drafts in a document. The data you read or write is always associated with the currently open draft.

Methods of ODDocument allow access to drafts by draft ID or by object reference and relative position in the document. Drafts have a specific set of properties, including creation date, modification date, and user name. Each draft object privately maintains whatever information it needs to distinguish itself from its predecessor draft.

The draft object is responsible for creating and tracking frame objects, part objects, link-related objects, and storage units. It also manages the cloning process and flags changes to the content of any of its parts. Typically, it is to perform these tasks and not to manipulate a draft as a version of a document that your part editor interacts with its draft object. Only one user can edit a draft at a time, and only the most recent draft of a given document can be edited. (Drafts cannot be changed if other drafts are based on them). To enforce this, each open draft has an associated set of draft permissions. They specify the class of read/write access that your part editor has to the draft. Table 6 lists the draft permissions recognized by OpenDoc.

Table 6. Draft Permissions

Constant | Explanation
--- | ---
kDPExclusiveWrite | Read access and exclusive-write access
kDPReadOnly | Read-only access
kDPSharedWrite | Read access and shared-write access
kDPTransient | Navigation-only access
kDPNone | No access

Note:

> The Bento container suite supports only the kODReadOnly and kODExclusiveWrite draft permissions.

When your part initializes itself, or at least before attempting to modify any of its data, it should get the permissions of its draft (by calling the draft's GetPermissions method) and behave accordingly. For example, your part editor should not attempt to make changes to a part when its draft has been opened read-only. Also, certain menu items should be disabled when the user views a read-only draft; see "Document Menu" and "Edit Menu" for descriptions.

#### Storage Model for Parts

Parts, like other persistent objects, have a storage unit in which they can write their state persistently. At the same time, parts are directly involved in many other OpenDoc actions (such as binding, data translation, and data transfer) and thus must satisfy additional storage requirements, so they can share their data with other objects as needed. Here are some of the requirements your parts must meet:

- Your part must be able to store multiple representations of its content. Each representation must be a full representation of the content; it cannot contain just that data that differs from the data in another representation.

- A caller must be able to extract at least one representation from your part's storage unit, without having to understand the format of any of the representations.

- A caller must be able to remove all but one representation from your part's storage unit, without having to understand the format of any of the representations.

- You must store your part's representations in order of fidelity, which is the faithfulness of the representation to that of your part editor's native format. Store them in descending order of fidelity, with your part editor's preferred format first.

- It must be possible to distinguish the fundamental content of your part from any annotations to it or information about it. OpenDoc or any caller with access to your storage unit can delete these annotations and items of information from memory at any time, without writing them to storage, and therefore you cannot use them to store actual content. You can, however, use them to store non-critical optimizations such as caches.

- Because property names are ISO strings, only simple naming conventions, such as prefixes to establish ownership, are possible. For example, "TC corporation" might use the prefix "TC:" to identify all ISO strings for which it controls the format and meaning. OpenDoc-defined strings have the OpenDoc ISO string prefix; see "OpenDoc ISO String Prefix".

To meet these requirements, your part must create a contents property, defined by the property name kODPropContents, in your storage unit. In that property, you need to create for every representation you wish to store, a value whose type is the part kind of the representation. (Part kind is described in "Part Kinds Stored in a Part"). Into each of these values, you must write one and only one representation of your part's contents, using the data format appropriate to that part. Order the values by fidelity.

Do not store any part content outside of the contents property. Make sure that all other properties in your part's storage unit are for annotations or extra information, rather than for content. Your part's contents property, however,can include persistent references to other storage units whose contents properties contain additional content data.

To help you decide which data you should store as content and which you should not, consider that content includes any data that the user should be able to save as well as any data that should persist across different part editors, different machines, and different platforms.

This storage model offers greater flexibility than is available for application storage on many platforms' file systems. If your applications use only a single stream to store all of their contents, your equivalent part can simply store everything in a single value in the contents property of its storage unit. If your applications use resources, multifork files, or some other form of structured storage, then your equivalent part can use multiple storage units referenced from a value in the contents property of your part's main storage unit.

Because you can add more storage units at any time and save references to them in any value, you can construct an arbitrarily complex structure for your stored data. Each additional storage unit can have multiple properties, and each property can have multiple values. (Remember that different values within the same property should only be used for different representations of the same data).

#### What a Draft Contains

Table 7 shows some of the kinds of information that can be stored persistently as properties of the various objects that make up the storage units in a draft of an OpenDoc document. Note that some of the storage units shown in Table 7 reflect the objects and persistent references shown in Figure 60, as well as the run-time object references shown in "Run-Time Object Relationships". Furthermore, some properties should not be accessed by part editors. This list is not complete, nor are all properties shown here required to be present.

Table 7. Data Stored in a Draft

Property | Description
--- | ---
Any Storage Unit: |
kODPropObjectType | Type of object stored in this storage unit (draft, frame, part, and so on)
Draft Storage Unit: |
kODPropRootPartSU | Strong persistent reference to the root part of this draft
Frame Storage Unit: |
kODPropPart | Strong persistent reference to the part displayed in this frame
kODPropContainingFrame | Weak persistent reference to the containing frame of this frame
kODPropFrameShape | Frame shape of this frame
kODPropPartInfo | Part info (part-specific data) associated with this frame
kODPropPresentation | Presentation of the part displayed in this frame
kODPropInternalTransform | Internal transform of this frame
kODPropFrameGroup | Group ID of the frame group this frame belongs to
kODPropSequenceNumber | Sequence number of this frame in its frame group
kODPropLinkStatus | The link status (in-source, in-destination, or not in link) of this frame
kODPropIsRoot | True if this frame is root frame in window
kODPropIsSubframe | True if this frame is a subframe
kODPropIsOverlaid | True if this frame is overlaid
kODPropDoesPropagateEvents | True if this frame's part propagates events
Part Storage Unit: |
kODPropContents | Part content (the actual stored data of this part)
kODPropDisplayFrames | Weak persistent references to the display frames of this part
Clipboard or Drag-and-Drop Storage Unit: |
kODPropContents | The contents of the clipboard (or drag-and-drop object)
kODPropSuggestedFrameShape | Suggested shape for frame, if contents are embedded at destination
kODPropLinkSpec | A link specification
kODPropContentFrame | (Exists if data is a single embedded frame)
kODPropProxyContents | Suggested adornments to apply to frame (if data is a single embedded frame)
Link Storage Unit: |
kODPropLinkSource | Weak persistent reference to the link-source object associated with this link object
Link-Source Storage Unit: |
kODPropLink | Weak persistent reference to a link object associated with this link-source object
kODPropSourcePart | Weak persistent reference to the part that contains (or last contained) the source data for this link
kODPropLinkContentSU | Strong persistent reference to the contents storage unit for the linked data
kODPropChangeTime | The date and time of this link's last update
kODPropUpdateID | The update ID for this link's last update
kODPropAutoUpdate | True if link is to be updated automatically

(Other standard frame and part properties are listed in Table 8.

Your part editor is responsible for reading and writing only the data that is stored persistently by your parts; OpenDoc takes care of persistent storage of the other objects listed in Table 7. Basically, each of the objects can read and write itself.

#### Info Properties

Some of the standard properties associated with a part (or, in some cases, its frame) are made visible to the user, either for information purposes only or to allow the user to modify them. This set of properties, called Info properties, is displayed in the Document Properties notebook. The last-modified date and time (kODPropModDate) is an example of an Info property that the user cannot change; the name of the part (kODPropName) is an example of an Info property that the user can change. Certain items displayed in the dialog box (such as part category and part size) are not storage-unit properties at all, but are calculated at run-time or obtained from other sources of information. Table 8 lists the standard Info properties of parts defined for version 1.0 of OpenDoc.

Table 8. Standard Info properties

Property | Explanation
--- | ---
kODPropName | The user-assigned name of the part
kODPropViewType | The view type of the part in the currently selected frame (a frame property)
kODPropIsFrozen | True if the part is bundled, false if not (a frame property)
kODPropIsStationery | True if the part is stationery, false if not
kODPropIconFamily | The icons that represent this part
kODPropPreferredKind | The user-specified part kind for the data of this part
kODPropPreferredEditor | The user-specified preferred editor for editing this part (the ID of the editor that last wrote this part to persistent storage)
kODPropCreateDate | The date and time at which this part was originally created
kODPropModDate | The date and time at which this part was last modified
kODPropModUser | The name of the user that last modified this part
kODPropComments | Comments entered by the user into this part's Document Properties notebook

Your part editor can define and attach additional user properties and store them in the part's content or attach them as properties to its parts' storage units. You can then display them to the user in a Settings page, accessible from the Document Properties notebook. See "The Settings Extension" for more information.

#### Container Properties

If your part contains embedded parts, you may want the embedded parts to adopt, by default, some of your current display settings or behavior. For example, if your part is a text part, it may be appropriate for other text parts embedded within it to have the same text characteristics (font, size, style, and so on), unless the user overrides them.

You can define such a set of characteristics as properties and attach them to your parts' storage units. These container properties then become available to embedded parts for adoption. See "Adopting Container Properties" and "Transmitting Your Container Properties to Embedded Parts" for more information.

#### Creating a New Document

Under most circumstances, your part editor never creates a document. Other parts of OpenDoc, such as the document shell, handle document creation when the user chooses a menu command such as New or drags a part to the desktop.

[ Top | Previous | Next | Contents | Index | Documentation Homepage ]