Title Banner

Previous Book Contents Book Index Next

Inside Macintosh: OpenDoc Cookbook /
Chapter 2 - SamplePart Tutorial


Initialization

The first responsibility of a part editor is initialization. When the user launches a document, either preexisting or newly created from stationery, OpenDoc instantiates the part object belonging to each currently visible part in the document. In SamplePart, the part object is an instance of the som_SamplePart class, which is a subclass of ODPart. At that time, the SOM runtime system calls the part object's somInit method.

The SamplePart object's somInit method, belonging to som_SamplePart, does nothing. The SOM runtime system automatically calls the inherited somInit methods, in the manner of a C++ constructor. SOM automatically zeroes the instance variables of a newly constructed SOM object, so there is no need to do so in the somInit method.

Next, OpenDoc calls one of the part object's initialization methods. If the part is creating stationery, OpenDoc calls the InitPart method of the part object; if the part was previously created, either as the root part or embedded in a document, OpenDoc calls the part's InitPartFromStorage method. In SamplePart, these methods instantiate the SamplePart C++ class, call their inherited methods, and call the SamplePart object's methods of the same name. When the SamplePart class is instantiated, the C++ runtime system calls its constructor, which does set instance variables to zero, as shown in Listing 2-3.

In SamplePart, initialization code resides in four methods: the SamplePart constructor, the InitPart method, the InitPartFromStorage method, and the internal Initialize method. The Initialize method contains the code that is common to both initialization situations: initializing a part when creating stationery (when OpenDoc calls InitPart) and initializing a part previously created and written to persistent storage (when OpenDoc calls InitPartFromStorage). Both of those methods call Initialize. The following sections discuss the implementation of these methods.

The Constructor

In SamplePart, the constructor performs only one action: it sets initial values for the SamplePart object's private data fields. You should not do anything in the constructor that can fail, such as allocating memory. The SOM_Trace macro call indicates the name of the method currently executing for debugging purposes.

Listing 2-3 shows the SamplePart object's constructor.

Listing 2-3 SamplePart constructor

SamplePart::SamplePart()
{
    SOM_Trace("SamplePart","Constructor");
   
   fDisplayFrames  = kODNULL;
   fDirty      = kODFalse;
   fSelf       = kODNULL;
   fReadOnlyStorage = kODFalse;
}

The InitPart Method

If the part has no stored data, OpenDoc calls the InitPart method after it instantiates the part object. Every part must implement this method. You can do things that might fail in this method, such as allocating extra storage, setting up your storage unit, and getting resources if you need them.

As with all methods in SamplePart, the implementation is delegated. That is, OpenDoc calls the InitPart method belonging to the ODPart subclass, which in turn calls the InitPart method of the SamplePart object, which contains the method's implementation. For more information, refer to "SamplePart System Object Model Interface".

The implementation of the InitPart method is contained within an exception handler, a block of code delimited by the macro calls TRY and ENDTRY. When the body of the method executes, the statements following the TRY macro execute; if any of them causes an exception to be thrown, the statements following the CATCH_ALL macro execute. The RERAISE macro causes the exception to be thrown again to the caller of InitPart. If no exception is thrown, control passes to the statement following the ENDTRY macro call (the end of the method body in this case). For more information about the OpenDoc exception-handling utility, see Appendix A, "OpenDoc Utilities."

The SamplePart implementation of the InitPart method performs the following actions:

  1. Initializes the part-wrapper field.
    OpenDoc passes a pointer to its internal representation for the part editor, its part wrapper, when it calls the InitPart method, and the SamplePart object stores the pointer in its fSelf data member.

    OpenDoc uses the part wrapper in place of a pointer to the actual part object to enable swapping part editors at runtime for part translation. Wherever OpenDoc requires a reference to the part editor, such as when registering for idle time, you must pass the part wrapper pointer, rather than passing this (from the SamplePart C++ object) or somSelf (from the som_SamplePart object).

  2. Ensures that the part's destination storage is writable.
    OpenDoc calls the method when a part is first instantiated, so we must be able to write part status and content information to its storage unit.

  3. Calls the common initialization code.
    Initialization code common to InitPart and InitPartFromStorage resides in the internal Initialize method. The Initialize method is described in "The Initialize Method".

  4. Sets the dirty flag.
    Setting the dirty flag to kODTrue enables SamplePart to write out its state and content information at the next opportunity.

If any of the called methods throws an exception, the CATCH_ALL method puts the error code in SOM's Environment structure. Cleanup occurs in the SamplePart destructor.

Listing 2-4 shows the implementation of the InitPart method.

Listing 2-4 InitPart method

void SamplePart::InitPart( Environment*ev,
                     ODStorageUnit*storageUnit,
                     ODPart*     partWrapper )
{
    SOM_Trace("SamplePart","InitPart");

   TRY
      fSelf = partWrapper;
      fReadOnlyStorage = kODFalse;
      this->Initialize(ev);
      this->SetDirty(ev);
   CATCH_ALL
      RERAISE;
   ENDTRY
}

The InitPartFromStorage Method

If a part has previously been stored persistently, OpenDoc calls the InitPartFromStorage method, instead of InitPart, after it instantiates the part object. This situation occurs when a document or stationery is opened or when the part is embedded and its containing part reads it into memory. So, every part must also implement this method, which should do many of the same things as InitPart, but which must also handle reading content and status information from the storage unit into memory.

The part must not alter its storage unit in this method; if it does so, the document's Save menu item becomes enabled without the user having changed the document.

The SamplePart object's implementation of the InitPartFromStorage method performs the following actions:

  1. Initializes the part-wrapper field.
    The method puts the part-wrapper pointer passed in from OpenDoc into the private fSelf data member.

  2. Determines if the draft from which the part is being opened is read only.
    If the draft permissions are read only, the part must not write any data back to its storage unit. The method sets the part's private fReadOnlyStorage Boolean flag accordingly, to be checked before writing data in the Externalize method.

  3. Calls the common initialization code.
    Initialization code common to InitPart and InitPartFromStorage resides in the internal Initialize method. The Initialize method is described in "The Initialize Method".

  4. Reads the part's status information.
    Because the part was previously written to its storage unit, InitPartFromStorage reads in the part's status information by calling the internal InternalizeStateInfo method, which is described in "The InternalizeStateInfo Method".

  5. Reads the part's content value from the storage unit.
    In SamplePart, the internal method that would read in the part's content value, InternalizeContent, does nothing, because SamplePart has no intrinsic content. A brief discussion of the method appears in "The InternalizeContent Method".

Listing 2-5 shows the implementation of the InitPartFromStorage method.

Listing 2-5 InitPartFromStorage method

void SamplePart::InitPartFromStorage( Environment*ev,
                             ODStorageUnit*storageUnit,
                             ODPart*      partWrapper )
{
    SOM_Trace("SamplePart","InitPartFromStorage");

   TRY
      fSelf = partWrapper;
      fReadOnlyStorage = ( ODGetDraft(ev,storageUnit)->                        GetPermissions(ev) < kODDPSharedWrite );
      this->Initialize(ev);
      this->InternalizeStateInfo(ev, storageUnit);
      this->InternalizeContent(ev, storageUnit);

   CATCH_ALL
      RERAISE;
   ENDTRY
}

The Initialize Method

The Initialize method is internal to the SamplePart class. OpenDoc doesn't call Initialize; both InitPart and InitPartFromStorage call it. The Initialize method contains the initialization code that is common to both situations, whether the part is newly created or is to be read in from persistent storage.

The Initialize method performs the following actions:

  1. Creates a frame list collection object.
    The frame list collection object (CList) is necessary to keep track of the multiple display frames in which the part displays its content. The class is defined in the SamplePart utilities file SampleCollections.h.

  2. Checks the usage count of the SamplePart global variables.
    If the usage count is not equal to zero, another instance of this part object is running. In that case, the following initialization steps have already been done and can be skipped. Otherwise, the method performs the following steps and sets the global variables usage count to 1.

  3. Stores a reference to the OpenDoc session object.
    This is a convenience, because the session object provides access to session-wide global objects and services such as the window-state object and unique name tokenization. Note that the self-reference passed with the ODGetSession call is the part-wrapper object passed in by OpenDoc to InitPart or InitPartFromStorage.

  4. Creates the global variables structure.
    The global variables structure is described in "Shared Global Variables".

  5. Instantiates the part's menu bar.
    The part editor instantiates its menu bar by copying OpenDoc's session-wide menu bar, a base menu bar object maintained by the window-state object. That action maintains consistency in the arrangement of default menu items. Also, because its menu bar is a copy, this part editor can add and subtract menus and items without affecting the menu bars of other parts.

    Note that the menu bar object is shared among all the currently running instances of SamplePart in this document by virtue of its declaration in the shared global variables structure shown in Listing 2-2.

  6. Tokenizes and stores values for the foci the part needs.
    The tokens are used for equivalence tests in the part activation methods and for requesting foci from the arbitrator. The method also packages into a set the three user-interface foci required by the part editor when it is activated, so it can request them all at once. The tokenized foci values are stored in the part's global variables.

  7. Tokenizes view types and presentation type.
    The method tokenizes the four view types that all part editors must support and the part editor's main presentation type. The method tokenizes these strings for convenience, because tokens are faster to handle than strings.

  8. Determines the script and language to which the part is localized.
    The GetEditorScriptLanguage utility function is defined in the SamplePart utilities file SamplePartUtils.cpp.

The final logic of the Initialize method manages SamplePart's global variables usage count, which was mentioned in step 2. If the globals usage count was not equal to zero at that step, then another instance of the part is already running, and this instance can use the same tokens, focus set, and menu bar object. In that case, the method merely increments the global variables usage count.

Listing 2-6 shows the implementation of the Initialize method.

Listing 2-6 Initialize method

void SamplePart::Initialize( Environment* ev )
{
    SOM_Trace("SamplePart","Initialize");

   fDisplayFrames = new CList;

   if ( gGlobalsUsageCount == 0 )
   {
      ODSession* session = ODGetSession(ev,fSelf);
      gGlobals = new SamplePartGlobals;
      gGlobals->fMenuBar = session->GetWindowState(ev)->CopyBaseMenuBar(ev);

      gGlobals->fSelectionFocus = session->Tokenize(ev, kODSelectionFocus);
      gGlobals->fMenuFocus = session->Tokenize(ev, kODMenuFocus);
      gGlobals->fModalFocus = session->Tokenize(ev, kODModalFocus);
   
      gGlobals->fMainPresentation = session->Tokenize(ev, kMainPresentation);
   
      gGlobals->fFrameView = session->Tokenize(ev, kODViewAsFrame);
      gGlobals->fLargeIconView = session->Tokenize(ev, kODViewAsLargeIcon);
      gGlobals->fSmallIconView = session->Tokenize(ev, kODViewAsSmallIcon);
      gGlobals->fThumbnailView = session->Tokenize(ev, kODViewAsThumbnail);
   
      gGlobals->fUIFocusSet = session->GetArbitrator(ev)->CreateFocusSet(ev);
      gGlobals->fUIFocusSet->Add(ev, gGlobals->fMenuFocus);
      gGlobals->fUIFocusSet->Add(ev, gGlobals->fSelectionFocus);
         
      GetEditorScriptLanguage(ev, &gGlobals->fEditorsScript, 
                                    &gGlobals->fEditorsLanguage);
      gGlobalsUsageCount = 1;
   }
   else
   {
      gGlobalsUsageCount++;
   }
}
After these initialization methods have executed, the SamplePart part editor is in a consistent state, ready to become active.


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