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 thesom_SamplePartclass, which is a subclass ofODPart. At that time, the SOM runtime system calls the part object'ssomInitmethod.The
SamplePartobject'ssomInitmethod, belonging tosom_SamplePart, does nothing. The SOM runtime system automatically calls the inheritedsomInitmethods, 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 thesomInitmethod.Next, OpenDoc calls one of the part object's initialization methods. If the part is creating stationery, OpenDoc calls the
InitPartmethod of the part object; if the part was previously created, either as the root part or embedded in a document, OpenDoc calls the part'sInitPartFromStoragemethod. In SamplePart, these methods instantiate theSamplePartC++ class, call their inherited methods, and call theSamplePartobject's methods of the same name. When theSamplePartclass 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
SamplePartconstructor, theInitPartmethod, theInitPartFromStoragemethod, and the internalInitializemethod. TheInitializemethod contains the code that is common to both initialization situations: initializing a part when creating stationery (when OpenDoc callsInitPart) and initializing a part previously created and written to persistent storage (when OpenDoc callsInitPartFromStorage). Both of those methods callInitialize. The following sections discuss the implementation of these methods.The Constructor
In SamplePart, the constructor performs only one action: it sets initial values for theSamplePartobject's private data fields. You should not do anything in the constructor that can fail, such as allocating memory. TheSOM_Tracemacro call indicates the name of the method currently executing for debugging purposes.Listing 2-3 shows the
SamplePartobject's constructor.Listing 2-3
SamplePartconstructor
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 theInitPartmethod 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
InitPartmethod belonging to theODPartsubclass, which in turn calls theInitPartmethod of theSamplePartobject, which contains the method's implementation. For more information, refer to "SamplePart System Object Model Interface".The implementation of the
InitPartmethod is contained within an exception handler, a block of code delimited by the macro callsTRYandENDTRY. When the body of the method executes, the statements following theTRYmacro execute; if any of them causes an exception to be thrown, the statements following theCATCH_ALLmacro execute. TheRERAISEmacro causes the exception to be thrown again to the caller ofInitPart. If no exception is thrown, control passes to the statement following theENDTRYmacro 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
SamplePartimplementation of theInitPartmethod performs the following actions:
If any of the called methods throws an exception, the
- Initializes the part-wrapper field.
OpenDoc passes a pointer to its internal representation for the part editor, its part wrapper, when it calls theInitPartmethod, and theSamplePartobject stores the pointer in itsfSelfdata 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 theSamplePartC++ object) orsomSelf(from thesom_SamplePartobject).
- 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.
- Calls the common initialization code.
Initialization code common toInitPartandInitPartFromStorageresides in the internalInitializemethod. TheInitializemethod is described in "The Initialize Method".
- Sets the dirty flag.
Setting the dirty flag tokODTrueenables SamplePart to write out its state and content information at the next opportunity.
CATCH_ALLmethod puts the error code in SOM'sEnvironmentstructure. Cleanup occurs in theSamplePartdestructor.Listing 2-4 shows the implementation of the
InitPartmethod.
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 theInitPartFromStoragemethod, instead ofInitPart, 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 asInitPart, 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
SamplePartobject's implementation of theInitPartFromStoragemethod performs the following actions:
Listing 2-5 shows the implementation of the
- Initializes the part-wrapper field.
The method puts the part-wrapper pointer passed in from OpenDoc into the privatefSelfdata member.
- 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 privatefReadOnlyStorageBoolean flag accordingly, to be checked before writing data in theExternalizemethod.
- Calls the common initialization code.
Initialization code common toInitPartandInitPartFromStorageresides in the internalInitializemethod. TheInitializemethod is described in "The Initialize Method".
- Reads the part's status information.
Because the part was previously written to its storage unit,InitPartFromStoragereads in the part's status information by calling the internalInternalizeStateInfomethod, which is described in "The InternalizeStateInfo Method".
- 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".
InitPartFromStoragemethod.Listing 2-5
InitPartFromStoragemethod
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
TheInitializemethod is internal to theSamplePartclass. OpenDoc doesn't callInitialize; bothInitPartandInitPartFromStoragecall it. TheInitializemethod 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
Initializemethod performs the following actions:
The final logic of the
- 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.
- 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.
- 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 theODGetSessioncall is the part-wrapper object passed in by OpenDoc toInitPartorInitPartFromStorage.
- Creates the global variables structure.
The global variables structure is described in "Shared Global Variables".
- 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
SamplePartin this document by virtue of its declaration in the shared global variables structure shown in Listing 2-2.
- 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.
- 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.
- Determines the script and language to which the part is localized.
TheGetEditorScriptLanguageutility function is defined in the SamplePart utilities file SamplePartUtils.cpp.
Initializemethod 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
Initializemethod.
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.