Persistent Storage
Persistent storage is a way to retain data on a long-term basis, supported by a nonvolatile device such as a hard disk. Persistent data remains stable between computing sessions. All persistent storage in OpenDoc is represented by storage units (ODStorageUnit
), which provide a standard, cross-platform interface for all persistent objects. Every object in OpenDoc that needs to maintain its state between sessions is a persistent object, and each has a storage unit. Part objects must handle their storage units in a particularly disciplined manner because they need to satisfy many more requirements than other persistent objects.Storage units have any number of properties, which are like separate forks of files, and properties have any number of values, which are separate streams of each fork. Each value in the same property holds a different representation of the same data; it should not hold different data. For example, every part has a contents property (
kODPropContents
), and multiple representations of the content can be stored in different values, but only content data should be stored in the contents property.If parts have multiple representations of their content, they must write them to storage in order of fidelity. For example, a part's most faithful representation of text may be styled text, while a lower fidelity representation of the same content would be plain ASCII text, a separate value for which would be added later to the same property. The highest fidelity representation of part content is its native format, specific to and usually proprietary to the part editor that created it. Lower fidelity representations enable the part to be viewed in documents without a full complement of part editors, to maintain portability of documents.
To load your part's content into memory from persistent storage, you should basically reverse the process of writing your part. However, your part must be able to work from an empty storage unit as well as one with stored content. Refer to the section "Initialization" for a description of this process.
SamplePart implements its persistent storage protocol in its
Externalize
,ExternalizeStateInfo
, andExternalizeContent
methods. Other methods dealing with storage areWritePartInfo
,ReadPartInfo
,ClonePartInfo
,CloneInto
, andPurge
. In addition, the utility methodSetDirty
manipulates the dirty flag, which is simply a Boolean value SamplePart uses to avoid redundancy: it writes the part content and notifies the draft only if the part has been altered.The sections that follow show the implementations of these methods, except for the
CloneInto
method, which OpenDoc calls to perform data interchange. TheCloneInto
method also uses the storage unit API.The Externalize Method
OpenDoc calls theExternalize
method whenever it is necessary to write the part to persistent storage. Your part can also call its ownExternalize
method whenever it wants to. Before returning from this method, you must write all data that you need to accurately re-create the content and state of your part.This method must call its parent class behavior (inherited class), because one of its parent class methods contains implementation. This is done in the SOM class implementation, which otherwise delegates all implementation to this method. Refer to the
som_SamplePart__Externalize
method of thesom_SamplePart
class in the file som_SamplePart.cpp.The
SamplePart
object's implementation of theExternalize
method performs the following actions:
Listing 2-40 shows the implementation of the
- Checks the part's dirty flag and storage unit privileges.
If the part's dirty flag is set tokODTrue
, meaning that the part has been changed since it was last written, and if the part's storage unit is not read-only, the method proceeds.
- Retrieves a pointer to the part's storage unit.
The method calls theGetStorageUnit
method inherited from theODPart
superclassODPersistentObject
, using thefSelf
field to refer to the part editor.
- Ensures that the storage unit properties are appropriate.
The method calls SamplePart subroutines, internal methodsCheckAndAddProperties
andCleanseContentProperty
, to verify that the properties and values are correct.
- Writes out the part's status information.
The method accomplishes this step by calling an internal method,ExternalizeStateInfo
.
- Writes out the part's content data.
The method writes out its content data by calling another internal method,ExternalizeContent
.
- Sets the part's dirty flag to false.
Externalize
method. The other methods that theExternalize
method calls are described in the next few sections.Listing 2-40
Externalize
method
void SamplePart::Externalize( Environment* ev ) { SOM_Trace("SamplePart","Externalize"); TRY if ( fDirty && !fReadOnlyStorage ) { ODStorageUnit* storageUnit = fSelf->GetStorageUnit(ev); this->CheckAndAddProperties(ev, storageUnit); this->CleanseContentProperty(ev, storageUnit); this->ExternalizeStateInfo(ev, storageUnit, kODNULLKey, kODNULL); this->ExternalizeContent(ev, storageUnit, kODNULLKey, kODNULL); fDirty = kODFalse; } CATCH_ALL this->DoDialogBox(ev, kODNULL, kErrorBoxID, kErrExternalizeFailed); SetErrorCode(kODErrAlreadyNotified); RERAISE; ENDTRY }The CheckAndAddProperties Method
SamplePart calls its own internalCheckAndAddProperties
method to verify that the part's storage unit has the properties it needs to run. If such properties are not present,CheckAndAddProperties
adds them.The
CheckAndAddProperties
method performs the following actions:
Listing 2-41 shows the implementation of the
- Sets up the contents property if it is not present.
After ensuring that the contents property exists, the method checks for, and if necessary adds, the part's kind value to the contents property. These actions are necessary in case the storage unit is new and the part has not been previously written to storage.
- Sets up the preferred kind property if it is not present.
The method writes out the default part kind for the editor. The user's chosen kind is written out in theExternalizeStateInfo
method.
- Sets up the part's display frame list if it is not present.
The method checks for, and if necessary adds, the display frames property and value.
CheckAndAddProperties
method.Listing 2-41
CheckAndAddProperties
method
void SamplePart::CheckAndAddProperties( Environment* ev, ODStorageUnit* storageUnit ) { SOM_Trace("SamplePart","CheckAndAddProperties"); if ( !storageUnit->Exists(ev, kODPropContents, kODNULL, 0) ) storageUnit->AddProperty(ev, kODPropContents); if ( !storageUnit->Exists(ev, kODPropContents, kSamplePartKind, 0) ) { storageUnit->Focus(ev, kODPropContents, kODPosUndefined, kODNULL, 0, kODPosAll); storageUnit->AddValue(ev, kSamplePartKind); } if ( !storageUnit->Exists(ev, kODPropPreferredKind, kODISOStr, 0) ) { TRY ODSetISOStrProp(ev, storageUnit, kODPropPreferredKind, kODISOStr, kSamplePartKind); CATCH_ALL ODSURemoveProperty(ev, storageUnit, kODPropPreferredKind); ENDTRY } if ( !storageUnit->Exists(ev, kODPropDisplayFrames, kODNULL, 0) ) storageUnit->AddProperty(ev, kODPropDisplayFrames); if ( !storageUnit->Exists(ev, kODPropDisplayFrames, kODWeakStorageUnitRefs, 0) ) { storageUnit->Focus(ev, kODPropDisplayFrames, kODPosUndefined, kODNULL, 0, kODPosAll); storageUnit->AddValue(ev, kODWeakStorageUnitRefs); } }The CleanseContentProperty Method
TheSamplePart
object calls its own internalCleanseContentProperty
method from itsExternalize
method. The purpose of this method is to remove any value in the contents property that the part cannot write out accurately, such as values added to the contents property during drag-and-drop operations.The
CleanseContentProperty
method performs the following actions:
Listing 2-42 shows the implementation of the
- Focuses the storage unit to its contents property.
- Retrieves the type of each value in the contents property.
The method uses the count of the number of values in the contents property to iterate through all of them. It focuses the storage unit on each value and gets its type.
- Removes any unsupported values.
The method uses the OpenDoc utility methodODISOStrCompare
to identify unsupported values by comparing their types to thekSamplePartKind
data type. The method then deletes unsupported values using theODStorageUnit
methodRemove
on the previously focused storage unit.
CleanseContentProperty
method.Listing 2-42
CleanseContentProperty
method
void SamplePart::CleanseContentProperty( Environment* ev, ODStorageUnit* storageUnit ) { SOM_Trace("SamplePart","CleanseContentProperty"); ODULong numValues; ODULong index; storageUnit->Focus(ev, kODPropContents, kODPosUndefined, kODNULL, 0, kODPosAll); numValues = storageUnit->CountValues(ev); for (index = numValues; index >= 1; index--) { storageUnit->Focus(ev, kODPropContents, kODPosUndefined, kODNULL, index, kODPosUndefined); TempODValueType value = storageUnit->GetType(ev); if ( ODISOStrCompare(value, kSamplePartKind) != 0 ) storageUnit->Remove(ev); } }The ExternalizeStateInfo Method
TheSamplePart
object calls its internalExternalizeStateInfo
method from itsExternalize
method when it writes the part to storage. This method writes out state information--any information pertaining to the working of the part editor--rather than the content. Such state information may be lost during data interchange operations, so the part must be able to recover gracefully if the state information is incomplete or missing.The
ExternalizeStateInfo
method performs the following actions:
Listing 2-43 shows the implementation of the
- Deletes weak references to the part's display frames.
First the method focuses on the display frames property of the part's storage unit, then removes and adds back the weak storage unit references associated with that property. This action deletes previously written persistent object references, which are not deleted by simply deleting the content of the value.
- Gets ID numbers for each display frame in the part's display frame list.
The method creates aCListIterator
object to visit each of the part's display frames, retrieving the frame ID number for each.If, however, a draft key is passed in the
key
parameter, it indicates that the part is being cloned to another draft, in which case the method creates a weak clone of the display frame and uses the frame ID of the cloned frame instead. A draft key is a unique number that identifies a cloning operation on a draft; because cloning is a multistep process, the key is needed to preserve the integrity of each operation.
- Writes out weak references for each of the part's display frames.
Still within the iteration loop of theCListIterator
, the method gets the weak reference to the storage unit of each of the part's display frames. Finally, using a macro namedStorageUnitSetValue
, the method writes that value into the display frames property of the part's storage unit.The
StorageUnitSetValue
macro, defined in the file StorUtil.h, simplifies handling of theODByteArray
structure required by theSetValue
method ofODStorageUnit
, which the macro calls.
ExternalizeStateInfo
method.Listing 2-43
ExternalizeStateInfo
method
void SamplePart::ExternalizeStateInfo( Environment* ev, ODStorageUnit* storageUnit, ODDraftKey key, ODFrame* scopeFrame ) { SOM_Trace("SamplePart","ExternalizeStateInfo"); ODStorageUnitRefweakRef; ODID frameID; ODID scopeFrameID = ( scopeFrame ? scopeFrame->GetID(ev) : kODNULLID ); ODDraft* fromDraft = ODGetDraft(ev,fSelf); storageUnit->Focus(ev, kODPropDisplayFrames, kODPosUndefined, kODWeakStorageUnitRefs, 0, kODPosUndefined); storageUnit->Remove(ev); storageUnit->AddValue(ev, kODWeakStorageUnitRefs); CListIterator fiter(fDisplayFrames); for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First(); fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() ) { frameID = proxy->GetID(); if ( key ) frameID = fromDraft->WeakClone(ev, key, frameID, kODNULLID, scopeFrameID); storageUnit->GetWeakStorageUnitRef(ev, frameID, weakRef); TRY StorageUnitSetValue(storageUnit, ev, kODStorageUnitRefSize, (ODPtr)&weakRef); CATCH_ALL // Consume the exception ENDTRY } }The ExternalizeContent Method
TheSamplePart
object'sExternalizeContent
method is empty, although any implementation would contain a statement to focus the part's storage unit on its contents property (kODPropContents
). Every part must have a property of this type in which to store its content data. OpenDoc uses the contents property to match parts to their correct part editors. Finally, the method would also write the part's content data out to its storage unit in an appropriate manner. SamplePart has no intrinsic content soExternalizeContent
does nothing.The CloneInto Method
OpenDoc calls theCloneInto
method during data interchange operations, that is, when a part is copied to the Clipboard, to a drag-and-drop object, or to a link-source object. TheCloneInto
method is inherited from theODPersistentObject
class. Generally, a part should respond to theCloneInto
method call by writing its own data to the specified destination storage unit and cloning any objects to which it has strong persistent references and which are within the scope of the frame passed in theinitiatingFrame
parameter.
The
- Note
- The scope of a frame includes the content of frames embedded within it but excludes other content of the parts belonging to those embedded frames. Scope and other concepts of cloning are explained in the OpenDoc Programmer's Guide for the Mac OS.
![]()
SamplePart
object's implementation of theCloneInto
method writes only its own data, state information, and content to the destination storage unit. Because SamplePart does not support embedding of other parts within itself, it has no need to clone any other objects.SamplePart does the actual work of externalizing its data in the internal methods
CheckAndAddProperties
(Listing 2-41).Listing 2-44 shows the implementation of the
CloneInto
method.
void SamplePart::CloneInto( Environment* ev, ODDraftKey key, ODStorageUnit* destinationSU, ODFrame* initiatingFrame ) { SOM_Trace("SamplePart","CloneInto"); if ( destinationSU->Exists(ev, kODPropContents, kSamplePartKind, 0) == kODFalse ) { this->CheckAndAddProperties(ev, destinationSU); this->ExternalizeStateInfo(ev, destinationSU, key, initiatingFrame); this->ExternalizeContent(ev, destinationSU, key, initiatingFrame); } }The InternalizeContent Method
TheSamplePart
object's internalInternalizeContent
method does nothing, because SamplePart has no intrinsic content.Generally speaking, for parts having content, a method such as this would focus the part's storage unit on the
kODPropContents
property, then read the stored data values. A reference to the storage unit is passed by OpenDoc to the part'sInitPartFromStorage
method (which in turn calls this method).The InternalizeStateInfo Method
TheSamplePart
object calls its own internalInternalizeStateInfo
method from itsInitPartFromStorage
method when it reads the part in from its persistent storage unit. This method reads in state information--any information pertaining to the working of the part editor--rather than the content. Generally, state information enables a part to present the same setup or configuration to the user as it had when last written out to storage.The
InternalizeStateInfo
method reads from storage a list of weak references to its display frames, previously written out by theExternalizeStateInfo
method. The method validates each reference; if the reference is valid, the method adds it to its display frame list using lazy internalization. That is, the method uses a frame proxy object, adding the proxy pointer to its display frame list. The part reads in the actual display frame object only when it is actually needed.Listing 2-45 shows the implementation of the
InternalizeStateInfo
method.Listing 2-45
InternalizeStateInfo
method
void SamplePart::InternalizeStateInfo( Environment* ev, ODStorageUnit* storageUnit ) { SOM_Trace("SamplePart","InternalizeStateInfo"); ODStorageUnitRefweakRef; ODULong size; if ( storageUnit->Exists(ev, kODPropDisplayFrames, kODWeakStorageUnitRefs, 0) ) { storageUnit->Focus(ev, kODPropDisplayFrames, kODPosUndefined, kODWeakStorageUnitRefs, 0, kODPosUndefined); size = storageUnit->GetSize(ev); storageUnit->SetOffset(ev, 0); for ( ODULong offset = 0; offset < size; offset += kODStorageUnitRefSize ) { TRY StorageUnitGetValue(storageUnit, ev, kODStorageUnitRefSize, (ODPtr)&weakRef); if ( storageUnit->IsValidStorageUnitRef(ev, weakRef) ) { ODID frameID = storageUnit->GetIDFromStorageUnitRef(ev, weakRef); CFrameProxy* proxy = new CFrameProxy; proxy->InitFrameProxy(frameID, ODGetDraft(ev,storageUnit)); fDisplayFrames->Add(proxy); } CATCH_ALL // Consume exception ENDTRY } } }The ReadPartInfo Method
Every part is displayed in at least one frame represented by an object of classODFrame
. Frame objects have a part info field in which a part editor can store information describing how it should display its part's data in that frame. When you write your part to storage, OpenDoc calls your part'sWritePartInfo
method, and when you load your part into memory, OpenDoc calls itsReadPartInfo
method. Generally, a part should respond to theWritePartInfo
method call by writing enough information to persistent storage to be able to reconstruct each frame's part info field, and it should perform that reconstruction in itsReadPartInfo
implementation. TheWritePartInfo
method is described in the section following this one.The
SamplePart
object stores a pointer to an object of a C++ helper class namedCFrameInfo
in its part info field.The
ReadPartInfo
method performs the following actions:
If the
- Instantiates a frame info object.
TheCFrameInfo
constructor initializes the object's internal data fields.
- Reads the frame info object into memory.
TheInitFromStorage
method reads theCFrameInfo
object, containing the frame's status information, from its storage unit.
- Returns a pointer to the frame info object.
CFrameInfo
object'sInitFromStorage
method fails, the method deletes the object and propagates the exception to the calling method.Listing 2-46 shows the implementation of the
SamplePart
object'sReadPartInfo
method, theCFrameInfo
constructor (defined inline), and theCFrameInfo
object'sInitFromStorage
method.Listing 2-46
ReadPartInfo
,CFrameInfo
constructor, andCFrameInfo::InitFromStorage
methods
ODInfoType SamplePart::ReadPartInfo( Environment* ev, ODFrame* frame, ODStorageUnitView* storageUnitView ) { SOM_Trace("SamplePart","ReadPartInfo"); CFrameInfo* frameInfo = new CFrameInfo; TRY frameInfo->InitFromStorage(ev, storageUnitView); CATCH_ALL ODDeleteObject(frameInfo); RERAISE; ENDTRY return (ODInfoType)frameInfo; } CFrameInfo::CFrameInfo() { fFrameActive = kODFalse; fFrameReactivate = kODFalse; fShouldDisposeWindow = kODFalse; fActiveFacet = kODNULL; fSourceFrame = kODNULL; fDependentFrame = kODNULL; fPartWindow = kODNULL; } void CFrameInfo::InitFromStorage(Environment* ev, ODStorageUnitView* storageUnitView) { ODStorageUnit* storageUnit = storageUnitView->GetStorageUnit(ev); if ( storageUnit->Exists(ev, kODNULL, kSamplePartInfo, 0) ) { TRY storageUnit->Focus(ev, kODNULL, kODPosSame, kSamplePartInfo, 0 , kODPosUndefined); ODStorageUnitRef weakRef = {0,0,0,0}; StorageUnitGetValue(storageUnit, ev, sizeof(ODStorageUnitRef), (ODPtr)&weakRef); if ( storageUnit->IsValidStorageUnitRef(ev, weakRef) ) { ODID frameID = storageUnit->GetIDFromStorageUnitRef(ev, weakRef); CFrameProxy* proxy = new CFrameProxy; proxy->InitFrameProxy(frameID, ODGetDraft(ev,storageUnit)); fSourceFrame = proxy; } CATCH_ALL ODDeleteObject(fSourceFrame); fSourceFrame = kODNULL; ENDTRY TRY ODStorageUnitRef weakRef = {0,0,0,0}; StorageUnitGetValue(storageUnit, ev, sizeof(ODStorageUnitRef), (ODPtr)&weakRef); if ( storageUnit->IsValidStorageUnitRef(ev, weakRef) ) { ODID frameID = storageUnit->GetIDFromStorageUnitRef(ev, weakRef); CFrameProxy* proxy = new CFrameProxy; proxy->InitFrameProxy(frameID, ODGetDraft(ev,storageUnit)); fDependentFrame = proxy; } CATCH_ALL ODDeleteObject(fDependentFrame); fDependentFrame = kODNULL; ENDTRY } }The WritePartInfo Method
OpenDoc calls a part'sWritePartInfo
method for each of its display frames whenever the document is saved.The
SamplePart
object's implementation of theWritePartInfo
method calls theCFrameInfo
object'sExternalize
method, which first gets a reference to the storage unit of the storage-unit view object passed with the call toWritePartInfo
. TheExternalize
method then calls theCFrameInfo
object'sCleanseFrameInfoProperty
method, which iterates through the value types in the storage unit and removes any that are not supported by SamplePart. Finally,Externalize
calls theCFrameInfo
object'sExternalizeFrameInfo
method to actually write out the frame's part info data.The
CFrameInfo
object'sExternalizeFrameInfo
method works much the same as theSamplePart
object'sExternalizeStateInfo
method. That is, the method removes, then adds back, the value containing weak references in the storage unit. Then, the method writes weak references to its source frame, if any, and its dependent frame, if any. In both cases, if a draft key exists, the method creates a weak clone of the display frame and writes out the weak reference to the storage unit. TheSamplePart
object'sExternalizeStateInfo
method is described in "The ExternalizeStateInfo Method".Listing 2-47 shows the implementation of the
SamplePart
object'sWritePartInfo
method, theCFrameInfo
object'sExternalize
method, and theCFrameInfo
object'sExternalizeFrameInfo
method.Listing 2-47
WritePartInfo
,CFrameInfo::Externalize
, andCFrameInfo::ExternalizeFrameInfo
methods
void SamplePart::WritePartInfo( Environment* ev, ODInfoType partInfo, ODStorageUnitView* storageUnitView ) { SOM_Trace("SamplePart","WritePartInfo"); ((CFrameInfo*) partInfo)->Externalize(ev, storageUnitView); } void CFrameInfo::Externalize(Environment* ev, ODStorageUnitView* storageUnitView) { ODStorageUnit* storageUnit = storageUnitView->GetStorageUnit(ev); this->CleanseFrameInfoProperty(ev, storageUnit); this->ExternalizeFrameInfo(ev, storageUnit, kODNULLKey, kODNULL); } void CFrameInfo::ExternalizeFrameInfo(Environment* ev, ODStorageUnit* storageUnit, ODDraftKey key, ODFrame* scopeFrame) { if ( storageUnit->Exists(ev, kODNULL, kSamplePartInfo, 0) ) { storageUnit->Focus(ev, kODNULL, kODPosSame, kSamplePartInfo, 0, kODPosUndefined); storageUnit->Remove(ev); } storageUnit->AddValue(ev, kSamplePartInfo); { ODStorageUnitRef weakRef = {0,0,0,0}; if ( fSourceFrame ) { ODID frameID = fSourceFrame->GetID(); ODID scopeFrameID = ( scopeFrame ? scopeFrame->GetID(ev) : kODNULLID ); ODDraft* fromDraft = fSourceFrame->GetDraft(); if ( key ) frameID = fromDraft->WeakClone(ev, key, frameID, kODNULLID, scopeFrameID); storageUnit->GetWeakStorageUnitRef(ev, frameID, weakRef); } StorageUnitSetValue(storageUnit, ev, sizeof(ODStorageUnitRef), (ODPtr)&weakRef); } { ODStorageUnitRef weakRef = {0,0,0,0}; if ( fDependentFrame ) { ODID frameID = fDependentFrame->GetID(); ODID scopeFrameID = ( scopeFrame ? scopeFrame->GetID(ev) : kODNULLID ); ODDraft* fromDraft = fDependentFrame->GetDraft(); if ( key ) frameID = fromDraft->WeakClone(ev, key, frameID, kODNULLID, scopeFrameID); storageUnit->GetWeakStorageUnitRef(ev, frameID, weakRef); } StorageUnitSetValue(storageUnit, ev, sizeof(ODStorageUnitRef), (ODPtr)&weakRef); } }The ClonePartInfo Method
OpenDoc calls a part'sClonePartInfo
method when any of its display frames is cloned during data transfer. Generally, a part editor should respond to theClonePartInfo
method call by writing out the frame's part info data, including any additional objects to which the part has strong persistent references and that are within the scope of the specified frame.The
SamplePart
object's implementation ofClonePartInfo
calls theCloneInto
method of theCFrameInfo
helper object holding the specified frame's part info data. TheCFrameInfo
implementation ofCloneInto
gets the storage unit, prefocused to a property but not to a value, and writes out the frame's part info data by calling theCFrameInfo
object'sExternalizeFrameInfo
method, which is shown in Listing 2-47.Listing 2-48 shows the implementation of the
SamplePart
object'sClonePartInfo
method and theCFrameInfo
object'sCloneInto
method.Listing 2-48
ClonePartInfo
andCFrameInfo::CloneInto
methods
void SamplePart::ClonePartInfo( Environment* ev, ODDraftKey key, ODInfoType partInfo, ODStorageUnitView* storageUnitView, ODFrame* scopeFrame ) { SOM_Trace("SamplePart","ClonePartInfo"); ((CFrameInfo*) partInfo)->CloneInto(ev, key, storageUnitView, scopeFrame); } void CFrameInfo::CloneInto(Environment *ev, ODDraftKey key, ODStorageUnitView* storageUnitView, ODFrame* scopeFrame) { ODStorageUnit* storageUnit = storageUnitView->GetStorageUnit(ev); if ( storageUnit->Exists(ev, kODNULL, kSamplePartInfo, 0) == kODFalse ) { this->ExternalizeFrameInfo(ev, storageUnit, key, scopeFrame); } }The Release Method
A part'sRelease
method is called by an object, such as another part editor, whenever it releases a reference to this part. TheRelease
method is inherited from theODRefCntObject
class, and the inherited implementation does the actual reference-count management. Thesom_SamplePart
object'sRelease
method calls the inherited method before it calls theSamplePart
object'sRelease
method described in this section (see also "SamplePart System Object Model Interface").The
SamplePart
object's implementation of theRelease
method releases the part-wrapper object, to which thefSelf
field points, if its reference count falls to 0.Listing 2-49 shows the implementation of the
Release
method.
void SamplePart::Release( Environment* ev ) { SOM_Trace("SamplePart","Release"); if ( fSelf->GetRefCount(ev) == 0 ) ODGetDraft(ev,fSelf)->ReleasePart(ev,fSelf); }The ReleaseAll Method
OpenDoc calls a part'sReleaseAll
method when the part object is about to be deleted by its draft. At this point, the part must release all the references it has acquired to other reference-counted objects. Otherwise, it will cause an invalid reference count error at some later time. This method is inherited from theODPersistentObject
class. Thesom_SamplePart
object'sReleaseAll
method calls the inherited method after it calls theSamplePart
object'sReleaseAll
method described in this section (see also "SamplePart System Object Model Interface").The
SamplePart
object's implementation of theReleaseAll
method performs the following actions:
The ODDeleteObject and
- Cleans up the SamplePart global variables.
TheReleaseAll
method first ensures that the global variables are no longer needed. The global variables are shared among all instances of theSamplePart
class that are currently running, and each instance increments a usage count accordingly. The method decrements the usage count. If the usage count reaches 0, the method releases the menu bar object, deletes the user interface focus set object, and deletes the global variables structure.
- Cleans up the part's display frame list.
TheReleaseAll
method first ensures that the part's display frame list is not null. SamplePart maintains proxy display frame objects in its list to support lazy internalization; the actual frames are not read into memory until they are needed. The method iterates through the display frame list, removing the pointer for each proxy from the list and deleting the proxy object. Then the method deletes the frame list object itself.
ODReleaseObject
utility macros, used in theReleaseAll
method to delete objects and release reference-counted objects, are defined in the ODUtils.h file.Listing 2-50 shows the implementation of the
ReleaseAll
method.Listing 2-50
ReleaseAll
method
void SamplePart::ReleaseAll( Environment* ev ) { SOM_Trace("SamplePart","ReleaseAll"); TRY if ( --gGlobalsUsageCount == 0 ) { ODReleaseObject(ev, gGlobals->fMenuBar); ODDeleteObject(gGlobals->fUIFocusSet); ODDeleteObject(gGlobals); } if ( fDisplayFrames ) { CListIterator fiter(fDisplayFrames); for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First(); fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() ) { fiter.RemoveCurrent(); delete proxy; } ODDeleteObject(fDisplayFrames); } CATCH_ALL RERAISE; ENDTRY }The Purge Method
When OpenDoc detects a possible shortage of memory, it may call a part'sPurge
method. The part should free as much memory as possible. OpenDoc passes in the requested number of bytes to free with the method call. Obviously, parts should not free any resources they need to keep running.The
SamplePart
object's implementation of thePurge
method performs the following actions:
Listing 2-51 shows the implementation of the
- Checks the view type of each of its display frames.
The method checks first to see if its internal list of display frames has been created. If not, there is no storage to free, so the method returns. Otherwise, the method iterates through all the frame proxy objects in its display frames list. If the frame associated with the proxy has not been loaded into memory, the method ignores it.
- Releases the unused thumbnail resource.
The method ensures that no frame has a view type of thumbnail, as determined in its previous iteration of its frame list, and that the thumbnail resource was previously read into memory. If these conditions prevail, the method increments its count of freed bytes by the size of the resource, releases the resource, and sets to null its global variable that points to the resource.
- Returns the cumulative count of the number of bytes freed.
Purge
method.
ODSize SamplePart::Purge( Environment* ev, ODSize /*size*/ ) { SOM_Trace("SamplePart","Purge"); if ( fDisplayFrames == kODNULL ) return 0; ODSize bytesFreed = 0; ODBooleanusingThumbnail= kODFalse; CListIterator fiter(fDisplayFrames); for ( CFrameProxy* proxy = (CFrameProxy*) fiter.First(); fiter.IsNotComplete(); proxy = (CFrameProxy*) fiter.Next() ) { if ( proxy->FrameIsLoaded() ) { ODTypeTokenframeView = proxy->GetFrame(ev)->GetViewType(ev); if ( frameView == gGlobals->fThumbnailView ) usingThumbnail = kODTrue; proxy->Purge(ev); } } if ( !usingThumbnail && (gGlobals->fThumbnail != kODNULL) ) { bytesFreed += (ODSize) ODGetHandleSize(gGlobals->fThumbnail); ReleaseResource(gGlobals->fThumbnail); gGlobals->fThumbnail = kODNULL; } return bytesFreed; }The SetDirty Method
TheSamplePart
object's internalSetDirty
method sets its dirty flag to true, indicating that the part's data has been changed by the user. The part editor calls its ownSetDirty
method whenever it changes its content.The
SetDirty
method performs the following actions:
Listing 2-52 shows the implementation of the
- Checks the dirty flag and write status.
The implementation is protected by its own flag, the internal variablefDirty
. If the flag is already true, or if the part's draft is read-only, the method body doesn't execute. Otherwise the method performs the subsequent steps.
- Sets the dirty flag to true.
- Notifies the draft that its content has changed from its previous version.
The method gets access to the draft through theODGetDraft
utility method and calls itsSetChangedFromPrev
method.
SetDirty
method.
void SamplePart::SetDirty( Environment* ev ) { SOM_Trace("SamplePart","SetDirty"); if ( !fDirty && !fReadOnlyStorage ) { fDirty = kODTrue; ODGetDraft(ev,fSelf)->SetChangedFromPrev(ev); } }
Main | Page One | What's New | Apple Computer, Inc. | Find It | Contact Us | Help