home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Storage / Bento / CMDraft.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  139.9 KB  |  4,980 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        CMDraft.cpp
  3.  
  4.     Contains:    Implementation for CMDraft class.
  5.  
  6.     Owned by:    Vincent Lo
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <20>     8/13/96    DM        1362809: in CloseVersion(), close embedded
  13.                                     container before release, fatal error on
  14.                                     failure
  15.         <19>     7/31/96    DH        #1373676:Fixed ConstructRealPart so that
  16.                                     the real part will not be set erroneously.
  17.         <18>     7/25/96    DH        Fixed NewCMxx methods to check the
  18.                                     somClassReference allocation and throw if
  19.                                     null (No bug #, approved by Bern).
  20.         <17>     7/23/96    DH        Bug# 1371089: OD crashes when parts throw
  21.                                     out of InitPartFromStorage: Approved by
  22.                                     Bern.
  23.         <16>     7/11/96    jpa        1364071: Don't pass "NoPart" as preferred
  24.                                     editor name to NoPart. Catch
  25.                                     kODErrOutOfMemory when creating parts.
  26.         <15>     6/27/96    EL        1361735: if no editor user string, use SOM
  27.                                     class name
  28.         <14>     6/27/96    jpa        1361886: ConstructRealPart sets NoPart user
  29.                                     message.
  30.         <13>     6/23/96    EL        1344140: if out of memory when new part is
  31.                                     initialized, tread as cannot load part.
  32.         <12>     6/22/96    EL        1344140: put up alert if we cannot create
  33.                                     part.
  34.         <11>     5/30/96    CC        1332786: Add std prefix to private property
  35.                                     & value type.
  36.         <10>     5/24/96    jpa        1246074: SOM_CATCH --> SOM_TRY..SOM_ENDTRY
  37.          <8>     3/22/96    CC        1330388: Support direct clone between
  38.                                     document drafts.
  39.          <7>     3/15/96    DM        1295410: create list iterators on stack
  40.                                     (avoid mem thrash during purge)
  41.                                     1292140: throw when persistent object has
  42.                                     no storage unit getting draft or session
  43.          <6>     3/15/96    CC        1316917: Don't remove valuable data
  44.                                     interchange properties when cloning with
  45.                                     kODCloneAll.
  46.          <5>     3/13/96    VL        1305064: Removed class purging code as it
  47.                                     is done by SOM now.
  48.          <4>      3/8/96    EL        1308013: If loading of editor fails,
  49.                                     replace by NoPart. Code reviewed by DM.
  50.          <3>     1/16/96    VL        1170098: Emptied out PartDeleted and
  51.                                     PartInstantiated as they are no longer
  52.                                     needed.
  53.          <2>     1/15/96    TJ        Cleaned Up
  54.  
  55.     To Do:
  56.     In Progress:
  57.         
  58. */
  59.  
  60. #define CMDraft_Class_Source
  61. #define VARIABLE_MACROS
  62. #include <CMDraft.xih>
  63.  
  64. #ifndef _DRAFPRIV_
  65. #include "DrafPriv.h"
  66. #endif
  67.  
  68. #ifndef SOM_ODSession_xh
  69. #include <ODSessn.xh>
  70. #endif
  71.  
  72. #ifndef SOM_CMDocument_xh
  73. #include <CMDoc.xh>
  74. #endif
  75.  
  76. #ifndef SOM_CMStorageUnit_xh
  77. #include <CMSU.xh>
  78. #endif
  79.  
  80. #ifndef _DOCPRIV_
  81. #include "DocPriv.h"
  82. #endif
  83.  
  84. #ifndef SOM_ODContainer_xh
  85. #include <ODCtr.xh>
  86. #endif
  87.  
  88. #ifndef SOM_ODStorageSystem_xh
  89. #include <ODStor.xh>
  90. #endif
  91.  
  92. #ifndef SOM_ODStorageUnitCursor_xh
  93. #include <SUCursor.xh>
  94. #endif
  95.  
  96. #ifndef SOM_ODFrame_xh
  97. #include <Frame.xh>
  98. #endif
  99.  
  100. #ifndef SOM_ODLink_xh
  101. #include <Link.xh>
  102. #endif
  103.  
  104. #ifndef SOM_ODLinkSource_xh
  105. #include <LinkSrc.xh>
  106. #endif
  107.  
  108. #ifndef SOM_ODLinkSpec_xh
  109. #include <LinkSpec.xh>
  110. #endif
  111.  
  112. #ifndef SOM_ODLinkManager_xh
  113. #include <LinkMgr.xh>
  114. #endif
  115.  
  116. #ifndef SOM_ODPart_xh
  117. #include <Part.xh>
  118. #endif
  119.  
  120. #ifndef _EXCEPT_
  121. #include "Except.h"
  122. #endif
  123.  
  124. #ifndef SOM_ODBentoContainer_xh
  125. #include "CMCtr.xh"
  126. #endif
  127.  
  128. #ifndef _CMAPI_
  129. #include "CMAPI.h"
  130. #endif
  131.  
  132. #ifndef __CM_API_TYPE_
  133. #include "CMAPITYP.h"
  134. #endif
  135.  
  136. #ifndef SOM_ODEmbeddedContainer_xh
  137. #include <EmbedCtr.xh>
  138. #endif
  139.  
  140. #ifndef _SESSHDR_
  141. #include "SessHdr.h"
  142. #endif
  143.  
  144. #ifndef _ODMEMORY_
  145. #include "ODMemory.h"
  146. #endif
  147.  
  148. #ifndef _ODNEW_
  149. #include "ODNew.h"
  150. #endif
  151.  
  152. #ifndef SOM_Module_OpenDoc_StdProps_defined
  153. #include <StdProps.xh>
  154. #endif
  155.  
  156. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  157. #include <StdTypes.xh>
  158. #endif
  159.  
  160. #ifndef SOM_CMLinkIterator_xh
  161. #include <CMLkItr.xh>
  162. #endif
  163.  
  164. #ifndef SOM_CMLinkSourceIterator_xh
  165. #include <CMLkSItr.xh>
  166. #endif
  167.  
  168. #ifndef _INDHDR_
  169. #include "IndHdr.h"            // for some const ODName
  170. #endif
  171.  
  172. #ifndef _OPENHASH_
  173. #include "OpenHash.h"
  174. #endif
  175.  
  176. #ifndef _ISOSTR_
  177. #include "ISOStr.h"
  178. #endif
  179.  
  180. #ifndef __STRING__
  181. #include <string.h>            // For strlen, strcpy....
  182. #endif
  183.  
  184. #ifndef _ODDEBUG_
  185. #include "ODDebug.h"    // Adkins -- added
  186. #endif
  187.  
  188. #ifndef _STORUTIL_
  189. #include <StorUtil.h>
  190. #endif
  191.  
  192. #ifndef SOM_ODBinding_xh
  193. #include <ODBindng.xh>
  194. #endif
  195.  
  196. #ifndef SOM_ODPartWrapper_xh
  197. #include <PartWrap.xh>
  198. #endif
  199.  
  200. #ifndef _BENTODEF_
  201. #include "BentoDef.h"
  202. #endif
  203.  
  204. #ifndef _BARRAY_
  205. #include <BArray.h>
  206. #endif
  207.  
  208. #ifndef _UTILERRS_
  209. #include "UtilErrs.h"
  210. #endif
  211.  
  212. #ifndef SOM_ODDragAndDrop_xh
  213. #include <DragDrp.xh>
  214. #endif
  215.  
  216. #ifndef SOM_ODArbitrator_xh
  217. #include <Arbitrat.xh>
  218. #endif
  219.  
  220. #ifndef SOM_Module_OpenDoc_Foci_defined
  221. #include <Foci.xh>
  222. #endif
  223.  
  224. #ifndef _ODNEWOBJ_
  225. #include <ODNewObj.h>
  226. #endif
  227.  
  228. #ifndef _STDTYPIO_
  229. #include <StdTypIO.h>
  230. #endif
  231.  
  232. #ifndef _TEMPOBJ_
  233. #include <TempObj.h>
  234. #endif
  235.  
  236. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  237. #include <StdDefs.xh>
  238. #endif
  239.  
  240. #ifndef SOM_SOMClassMgr_xh
  241. #include <somcm.xh>
  242. #endif
  243.  
  244. #ifndef _STORRSRC_
  245. #include <StorRsrc.h>
  246. #endif
  247.  
  248. #ifndef _DLOGUTIL_
  249. #include <DlogUtil.h>
  250. #endif
  251.  
  252. #ifndef _BNDNSUTL_
  253. #include <BndNSUtl.h>
  254. #endif
  255.  
  256. #ifndef SOM_Module_Apple_defined
  257. #include <NoPart.xh>
  258. #endif
  259.  
  260. // remove later
  261.  
  262. #ifndef SOM_ODDispatcher_xh
  263. #include <Disptch.xh>
  264. #endif
  265.  
  266. #ifndef SOM_ODTranslation_xh
  267. #include <Translt.xh>
  268. #endif
  269.  
  270. #ifndef SOM_ODWindowState_xh
  271. #include <WinStat.xh>
  272. #endif
  273.  
  274. // remove to here
  275.  
  276. #pragma segment CMDraft
  277.  
  278. //==============================================================================
  279. // Constants
  280. //==============================================================================
  281.  
  282. const ODType    kODVersionNamePrefix    = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Property:Bento Version Name";
  283. const ODPropertyName kODPropRootSU        = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Property:DraftRootStorageUnit";
  284. const ODType    kODStorageUnitType      = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Type:StorageUnit";
  285. const ODType    kODStorageUnit            = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:ObjectType:StorageUnit";
  286. const ODULong    kODInitialNumEntries = 8;
  287.  
  288. const corbastring kFrameClassName = "ODFrame";
  289.  
  290. #define    kMaxStringSize    32
  291. #define kInitialHashTableEntries 8
  292.  
  293. #define lazyOpen 1
  294.  
  295. // For debugging
  296.  
  297. #if ODDebug
  298. // #define ODDebug_Drafts    1
  299. // #define ODDebug_DebugRefCount 1
  300. // #define ODDebug_CMDraft 1
  301. // #define DebugClone 1
  302. // #define ODDebug_VersionList    1
  303. // #define ODDebug_CloningAnnotations 1
  304. // #define ODDebug_Unloading_Classes 1
  305. #endif
  306.  
  307.  
  308. //==============================================================================
  309. // Local Classes
  310. //==============================================================================
  311.  
  312. class SULink : public Link {
  313.  
  314. public:
  315.     
  316.     SULink(ODStorageUnitID fromID, ODStorageUnitID toID)
  317.     {
  318.         fFromID = fromID;
  319.         fToID = toID;
  320.     }
  321.     ~  SULink() {;};
  322.     
  323.     ODStorageUnitID    GetFromID() {return fFromID;};
  324.     ODStorageUnitID    GetToID() {return fToID;};
  325.  
  326. private:
  327.     
  328.     ODStorageUnitID                fFromID;
  329.     ODStorageUnitID                fToID;
  330. };
  331.  
  332. //==============================================================================
  333. // Function Prototypes
  334. //==============================================================================
  335.  
  336. static CMStorageUnit* NewCMStorageUnit(ODMemoryHeapID heapID);
  337.  
  338. static CMObject AcquireDraftPropertiesObject(CMContainer container);
  339. static ODType GetVersionNameFromVersionID(ODVersionID id, ODMemoryHeapID heapID);
  340.  
  341. static void SetOriginalDraft(Environment* ev, ODDraft* targetDraft, ODDraft* originalDraft);
  342. static ODDraft* GetOriginalDraft(Environment* ev, ODDraft* draft);
  343. static ODBoolean OriginalCloneKindExists(Environment* ev, ODDraft* draft);
  344. static void SetOriginalCloneKind(Environment* ev, ODDraft* targetDraft, ODCloneKind cloneKind);
  345.  
  346. static ODBoolean IsLinkObject(Environment* ev, ODDraft* draft, ODID objectID);
  347. static ODBoolean IsLinkSourceObject(Environment* ev, ODDraft* draft, ODID objectID);
  348. static ODBoolean IsEitherLinkObject(Environment* ev, ODDraft* draft, ODID objectID);
  349. static ODBoolean IsNeitherLinkObject(Environment* ev, ODDraft* draft, ODID objectID);
  350.  
  351. static void itoa(ODULong number, ODSByte* cstring);
  352.  
  353. static ODULong PurgeAllStorageUnits(Environment* ev, OpenHashTable* storageUnits, IDList* idList);
  354.  
  355. static void SetupForUpdatingDraft(Environment* ev,
  356.                                         CMDocument* localDoc,
  357.                                         ODVersionID prevVersionID,
  358.                                         CMValue version);            
  359.  
  360. static ODBoolean CheckPartAction(void* k, void* v, ODULong s, void* r);
  361.  
  362. static void CopyProperty(Environment *ev, ODStorageUnit* fromSU, ODStorageUnit* toSU, ODPropertyName prop);
  363. static void CopyDraftAnnotations(Environment *ev, ODStorageUnit* fromSU, ODStorageUnit* toSU);
  364. static void SetStorageUnitType(Environment* ev, ODDraftPermissions perms, ODStorageUnit* su, ODType suType);
  365. static ODISOStr GetStorageUnitType(Environment* ev, ODDraft* draft, ODID objectID);
  366. static ODID RootPartID(Environment* ev, ODDraft* draft);
  367.  
  368. // For debugging
  369.  
  370. #ifdef DebugStorage
  371.  
  372. #define MyDebugStr(s) do {somPrintf(s);} while (0)
  373. #define MyDebug2Str(f,p1,p2) do {somPrintf(f, p1, p2);} while (0)
  374.  
  375. #else
  376.  
  377. #define MyDebugStr(s)
  378. #define MyDebug2Str(f,p1,p2)
  379.  
  380. #endif
  381.  
  382. //==============================================================================
  383. // Static variables
  384. //==============================================================================
  385.  
  386. // Used by CheckPartAction
  387. static CMDraft*    sInterchangeDraft = kODNULL;
  388. static ODISOStr    sSUTypeBuffer;
  389. static ODID        sRootPartIDToIgnore;
  390.  
  391. //------------------------------------------------------------------------------
  392. // ReadClonedObjectTable
  393. //------------------------------------------------------------------------------
  394.  
  395. // These are private property and value for Bento Container Suite. 
  396. // They are used for data interchange. They enable multiple clones to the clipboard
  397. // and d&d container.
  398. const ODPropertyName    kODPropClonedObjectTable  = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Property:ClonedObjectTable";
  399. const ODValueType        kODTypeClonedObjectTable  = "+//ISO 9070/ANSI::113722::US::CI LABS::OpenDoc:Type:ClonedObjectTable";
  400.  
  401. ODStatic void ReadClonedObjectTable(Environment* ev, OpenHashTable* clonedSUIDs, ODDraft* destDraft)
  402. {
  403. #ifdef DebugClone
  404.     somPrintf("CMDraft: ReadClonedObjectTable\n");
  405. #endif
  406.  
  407.     TempODStorageUnit su = destDraft->AcquireDraftProperties(ev);
  408.     if (ODSUExistsThenFocus(ev, su, kODPropClonedObjectTable, kODTypeClonedObjectTable) )
  409.     {
  410.         su->SetOffset(ev, 0);
  411.         
  412.         ODULong    size = su->GetSize(ev);
  413.         ODID    fromID;
  414.         ODID    toID;
  415.     
  416.         while ( su->GetOffset(ev) < size )
  417.         {
  418.             StorageUnitGetValue(su, ev, sizeof(ODULong), (ODValue) &fromID);
  419.             StorageUnitGetValue(su, ev, sizeof(ODULong), (ODValue) &toID);
  420. #ifdef DebugClone
  421.             somPrintf("    fromID %d, toID %d\n", fromID, toID);
  422. #endif
  423.             clonedSUIDs->ReplaceEntry(&fromID, &toID);
  424.         }
  425.     }
  426. }
  427.  
  428. //------------------------------------------------------------------------------
  429. // WriteClonedObjectTable
  430. //------------------------------------------------------------------------------
  431.  
  432. ODStatic void WriteClonedObjectTable(Environment* ev, OpenHashTable* clonedSUIDs, ODDraft* destDraft)
  433. {
  434. #ifdef DebugClone
  435.     somPrintf("CMDraft: WriteClonedObjectTable\n");
  436. #endif
  437.  
  438.     TempODStorageUnit su = destDraft->AcquireDraftProperties(ev);
  439.         
  440.     ODSUForceFocus(ev, su, kODPropClonedObjectTable, kODTypeClonedObjectTable);
  441.     
  442.     su->SetOffset(ev, 0);
  443.  
  444.     ODULong    oldSize = su->GetSize(ev);
  445.  
  446.     ODID        fromID;
  447.     ODID        toID;
  448.  
  449.     OpenHashTableIterator iter(clonedSUIDs);
  450.     for (iter.First(&fromID, &toID); iter.IsNotComplete(); iter.Next(&fromID, &toID))
  451.     {
  452. #ifdef DebugClone
  453.         somPrintf("    from ID %d to ID %d\n", fromID, toID);
  454. #endif
  455.         StorageUnitSetValue(su, ev, sizeof(ODULong), (ODValue) &fromID);
  456.         StorageUnitSetValue(su, ev, sizeof(ODULong), (ODValue) &toID);
  457.     }
  458.  
  459.     ODULong    newSize = su->GetOffset(ev);
  460.     if ( oldSize > newSize )
  461.         su->DeleteValue(ev, oldSize - newSize);
  462. }
  463.  
  464. //==============================================================================
  465. // CMDraft
  466. //==============================================================================
  467.  
  468. //------------------------------------------------------------------------------
  469. // CMDraft: FailIfNotExclusiveWrite
  470. //------------------------------------------------------------------------------
  471.  
  472. SOM_Scope void  SOMLINK CMDraftFailIfNotExclusiveWrite(CMDraft *somSelf, Environment *ev)
  473. {
  474.     CMDraftData *somThis = CMDraftGetData(somSelf);
  475.     CMDraftMethodDebug("CMDraft","FailIfNotExclusiveWrite");
  476.  
  477.     if (_fPermissions != kODDPExclusiveWrite)
  478.          ODSetSOMException(ev,kODErrInvalidPermissions);
  479. }
  480.  
  481. //------------------------------------------------------------------------------
  482. // CMDraft: GetDocument
  483. //------------------------------------------------------------------------------
  484.  
  485. SOM_Scope ODDocument*  SOMLINK CMDraftGetDocument(CMDraft *somSelf, Environment *ev)
  486. {
  487.     CMDraftData *somThis = CMDraftGetData(somSelf);
  488.     CMDraftMethodDebug("CMDraft","GetDocument");
  489.  
  490.     return _fDocument;
  491. }
  492.  
  493. //------------------------------------------------------------------------------
  494. // CMDraft: GetID
  495. //------------------------------------------------------------------------------
  496.  
  497. SOM_Scope ODDraftID  SOMLINK CMDraftGetID(CMDraft *somSelf, Environment *ev)
  498. {
  499.     CMDraftData *somThis = CMDraftGetData(somSelf);
  500.     CMDraftMethodDebug("CMDraft","GetID");
  501.  
  502.     return _fID;
  503. }
  504.  
  505. //------------------------------------------------------------------------------
  506. // CMDraft: AcquireDraftProperties
  507. //------------------------------------------------------------------------------
  508.  
  509. SOM_Scope ODStorageUnit*  SOMLINK CMDraftAcquireDraftProperties(CMDraft *somSelf, Environment *ev)
  510. {
  511.     CMDraftData *somThis = CMDraftGetData(somSelf);
  512.     CMDraftMethodDebug("CMDraft","AcquireDraftProperties");
  513.  
  514.     SOM_TRY
  515.     
  516.     CMObject            draftPropertiesObject;
  517.     CMStorageUnit*        draftProperties;
  518.     ODStorageUnitID    id;
  519.     
  520.     if (_fDraftProperties != kODNULL) {
  521.         _fDraftProperties->Internalize(ev);
  522.     }
  523.     else {
  524.  
  525.         CMContainer cmContainer = somSelf->GetCMContainer(ev);
  526.         ODSessionMustHaveCMAllocReserve(cmContainer);
  527.         // AcquireDraftPropertiesObject() makes CM calls:
  528.  
  529.         draftPropertiesObject = AcquireDraftPropertiesObject(somSelf->GetCMContainer(ev));
  530.         if (draftPropertiesObject == kODNULL)
  531.             THROW(kODErrNoDraftProperties);
  532.         
  533.         id = _fIDList->Add(draftPropertiesObject);
  534.         draftProperties = NewCMStorageUnit(somSelf->GetHeap(ev));
  535.         draftProperties->InitStorageUnit(ev, somSelf, id);
  536.         _fStorageUnits->ReplaceEntry(&id, &draftProperties);
  537.         _fDraftProperties = draftProperties;
  538.         
  539.         ODSessionRestoreCMAllocReserve(cmContainer);
  540.     }
  541.     
  542.     _fDraftProperties->Acquire(ev);
  543.     return _fDraftProperties;
  544.  
  545.     SOM_CATCH_ALL
  546.     SOM_ENDTRY
  547.     return kODNULL;
  548. }
  549.  
  550. //------------------------------------------------------------------------------
  551. // CMDraft: Acquire
  552. //------------------------------------------------------------------------------
  553.  
  554. SOM_Scope void  SOMLINK CMDraftAcquire(CMDraft *somSelf, Environment *ev)
  555. {
  556. //  CMDraftData *somThis = CMDraftGetData(somSelf);
  557.     CMDraftMethodDebug("CMDraft","Acquire");
  558.  
  559.     SOM_TRY
  560.         parent_Acquire(somSelf, ev);
  561.     SOM_CATCH_ALL
  562.     SOM_ENDTRY
  563. }
  564.  
  565. //------------------------------------------------------------------------------
  566. // CMDraft: Release
  567. //------------------------------------------------------------------------------
  568.  
  569. SOM_Scope void  SOMLINK CMDraftRelease(CMDraft *somSelf, Environment *ev)
  570. {
  571.     CMDraftData *somThis = CMDraftGetData(somSelf);
  572.     CMDraftMethodDebug("CMDraft","Release");
  573.  
  574.     SOM_TRY
  575.     
  576.     parent_Release(somSelf, ev);
  577.     if (somSelf->GetRefCount(ev) == 0) {
  578.         if (_fDraftProperties != kODNULL) {
  579.             _fDraftProperties->Release(ev);
  580.             _fDraftProperties = kODNULL;
  581.         }
  582. //        WASSERTM((somSelf->AreEmptyCollections(ev) != kODFalse), "OutstandingObjects in CMDraft: Release.");
  583.         _fDocument->ReleaseDraft(ev, somSelf);
  584.     }
  585.     
  586.     SOM_CATCH_ALL
  587.     
  588.         ODError err = ErrorCode();
  589.  
  590.         WARN("Error occurred in ODContainer::Release: %d %s", err, ErrorMessage() ?ErrorMessage() :"");
  591.  
  592.         SetErrorCode(kODNoError);
  593.  
  594.     SOM_ENDTRY
  595. }
  596.  
  597. //------------------------------------------------------------------------------
  598. // CMDraft: GetPermissions
  599. //------------------------------------------------------------------------------
  600.  
  601. SOM_Scope ODDraftPermissions  SOMLINK CMDraftGetPermissions(CMDraft *somSelf, Environment *ev)
  602. {
  603.     CMDraftData *somThis = CMDraftGetData(somSelf);
  604.     CMDraftMethodDebug("CMDraft","GetPermissions");
  605.  
  606.     return _fPermissions;
  607. }
  608.  
  609. //------------------------------------------------------------------------------
  610. // CMDraft: CreateStorageUnit
  611. //------------------------------------------------------------------------------
  612.  
  613. SOM_Scope ODStorageUnit*  SOMLINK CMDraftCreateStorageUnit(CMDraft *somSelf, Environment *ev)
  614. {
  615.     CMDraftData *somThis = CMDraftGetData(somSelf);
  616.     CMDraftMethodDebug("CMDraft","CreateStorageUnit");
  617.  
  618.     ODStorageUnit*    su = kODNULL; ODVolatile(su);
  619.  
  620.     SOM_TRY
  621.  
  622.     somSelf->FailIfNotExclusiveWrite(ev);
  623.     
  624.     su = somSelf->CreateSU(ev, kODNULL, kODStorageUnit);
  625.     SetStorageUnitType(ev, _fPermissions, su, kODStorageUnit);
  626.  
  627.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  628.  
  629.     SOM_CATCH_ALL
  630.         if (su != kODNULL) {
  631.             TRY{
  632.                 somSelf->ReleaseStorageUnit(ev, su->GetID(ev));
  633.             }CATCH_ALL{
  634.                 // ignore exception
  635.             }ENDTRY
  636.             su = kODNULL;
  637.         }
  638.     SOM_ENDTRY
  639.     return su;
  640. }
  641.  
  642. //------------------------------------------------------------------------------
  643. // CMDraft: IsValidID
  644. //------------------------------------------------------------------------------
  645.  
  646. SOM_Scope ODBoolean  SOMLINK CMDraftIsValidID(CMDraft *somSelf, Environment *ev,
  647.         ODID id)
  648. {
  649.     CMDraftData *somThis = CMDraftGetData(somSelf);
  650.     CMDraftMethodDebug("CMDraft","IsValidID");
  651.  
  652.     SOM_TRY
  653.     
  654.     if ( id != kODNULLID )
  655.         return _fIDList->Exists(id);
  656.     
  657.     SOM_CATCH_ALL
  658.     SOM_ENDTRY
  659.     return kODFalse;
  660. }
  661.  
  662. //------------------------------------------------------------------------------
  663. // CMDraft: AcquireStorageUnit
  664. //------------------------------------------------------------------------------
  665.  
  666. SOM_Scope ODStorageUnit*  SOMLINK CMDraftAcquireStorageUnit(CMDraft *somSelf, Environment *ev,
  667.         ODStorageUnitID id)
  668. {
  669.     CMDraftData *somThis = CMDraftGetData(somSelf);
  670.     CMDraftMethodDebug("CMDraft","AcquireStorageUnit");
  671.  
  672.     SOM_TRY
  673.  
  674.     if (id == kODNULLID)
  675.         THROW(kODErrIllegalNullIDInput);
  676.  
  677.     ODStorageUnit*    su = kODNULL;
  678.     
  679.     if (_fStorageUnits->GetValue(&id, &su)) {
  680.         su->Acquire(ev);
  681.     }
  682.     else if ((_fIDList->Exists(id) == kODFalse) ||
  683.              (_fIDList->Get(id) != kODNULL)) {
  684.         su = somSelf->CreateSU(ev, id, kODStorageUnit);
  685.     }
  686.     return su;
  687.  
  688.     SOM_CATCH_ALL
  689.     SOM_ENDTRY
  690.     return kODNULL;
  691. }
  692.  
  693. //------------------------------------------------------------------------------
  694. // CMDraft: RemoveStorageUnit
  695. //------------------------------------------------------------------------------
  696.  
  697. SOM_Scope void  SOMLINK CMDraftRemoveStorageUnit(CMDraft *somSelf, Environment *ev,
  698.         ODStorageUnit* su)
  699. {
  700.     CMDraftData *somThis = CMDraftGetData(somSelf);
  701.     CMDraftMethodDebug("CMDraft","RemoveStorageUnit");
  702.  
  703.     SOM_TRY
  704.  
  705.     CMContainer cmContainer = somSelf->GetCMContainer(ev);
  706.     ODSessionMustHaveCMAllocReserve(cmContainer);
  707.     
  708.     ODID            id;
  709.     CMObject        object;
  710.     ODStorageUnit*    draftProperties;
  711.  
  712.     somSelf->FailIfNotExclusiveWrite(ev);
  713.     
  714.     draftProperties = somSelf->AcquireDraftProperties(ev);
  715.     if (su == draftProperties) {
  716.         draftProperties->Release(ev);
  717.         THROW(kODErrIllegalOperationOnSU);
  718.     }
  719.     else
  720.         draftProperties->Release(ev);
  721.         
  722.     // Get Storage Unit ID
  723.     
  724.     id = su->GetID(ev);
  725.     if (id == kODNULL)
  726.         THROW(kODErrInvalidStorageUnit);
  727.         
  728.     // Release the storage unit
  729.     su->Release(ev);
  730.     
  731.     // Remove Storage Unit from outstanding SU collection
  732.     
  733.     _fStorageUnits->RemoveEntry(&id);
  734.     
  735.     // Get and delete the CMObject associated with su.
  736.     
  737.     object = (CMObject) _fIDList->Get(id);
  738.     
  739.     // Remove the entry in the ID-object collection.
  740.     
  741.     _fIDList->Remove(id);
  742.     
  743.     // Delete the object
  744.     
  745.     if (object != kODNULL)
  746.         CMDeleteObject(object);
  747.     
  748.     // Destroy su
  749.     
  750.     delete su;
  751.     
  752.     // Mark this draft dirty
  753.     
  754.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  755.  
  756.     ODSessionRestoreCMAllocReserve(cmContainer);
  757.  
  758.     SOM_CATCH_ALL
  759.     SOM_ENDTRY
  760. }
  761.  
  762. //------------------------------------------------------------------------------
  763. // CMDraft: ChangedFromPrev
  764. //------------------------------------------------------------------------------
  765.  
  766. SOM_Scope ODBoolean  SOMLINK CMDraftChangedFromPrev(CMDraft *somSelf, Environment *ev)
  767. {
  768.     CMDraftData *somThis = CMDraftGetData(somSelf);
  769.     CMDraftMethodDebug("CMDraft","ChangedFromPrev");
  770.     
  771.     SOM_TRY
  772.  
  773.     ODBoolean        changedFromPrev;
  774.     VersionList*    versionList = kODNULL;
  775.     
  776.     versionList = _fDocument->TestAndGetVersionList(ev);
  777.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  778.     
  779.     TRY
  780.         changedFromPrev = somSelf->IsChangedFromPrev(ev, versionList);
  781.         
  782.     CATCH_ALL
  783.     
  784.         _fDocument->ReleaseVersionList(ev);
  785.         RERAISE;
  786.         
  787.     ENDTRY
  788.     
  789.     _fDocument->ReleaseVersionList(ev);
  790.     
  791.     return changedFromPrev;
  792.  
  793.     SOM_CATCH_ALL
  794.     SOM_ENDTRY
  795.     return kODFalse;
  796. }
  797.  
  798. //------------------------------------------------------------------------------
  799. // CMDraft: SetChangedFromPrev
  800. //------------------------------------------------------------------------------
  801.  
  802. SOM_Scope void  SOMLINK CMDraftSetChangedFromPrev(CMDraft *somSelf, Environment *ev)
  803. {
  804.     CMDraftData *somThis = CMDraftGetData(somSelf);
  805.     CMDraftMethodDebug("CMDraft","SetChangedFromPrev");
  806.  
  807.     SOM_TRY
  808.     
  809.     somSelf->FailIfNotExclusiveWrite(ev);
  810.  
  811.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  812.  
  813.     SOM_CATCH_ALL
  814.     SOM_ENDTRY
  815. }
  816.  
  817. //------------------------------------------------------------------------------
  818. // CMDraft: RemoveFromDocument
  819. //------------------------------------------------------------------------------
  820.  
  821. SOM_Scope void  SOMLINK CMDraftRemoveFromDocument(CMDraft *somSelf, Environment *ev)
  822. {
  823.     CMDraftData *somThis = CMDraftGetData(somSelf);
  824.     CMDraftMethodDebug("CMDraft","RemoveFromDocument");
  825.  
  826.     SOM_TRY
  827.     
  828.     _fDocument->CollapseDrafts(ev, somSelf, kODNULL);
  829.  
  830.     SOM_CATCH_ALL
  831.     SOM_ENDTRY
  832. }
  833.  
  834. //------------------------------------------------------------------------------
  835. // CMDraft: RemoveChanges
  836. //------------------------------------------------------------------------------
  837.  
  838. SOM_Scope ODDraft*  SOMLINK CMDraftRemoveChanges(CMDraft *somSelf, Environment *ev)
  839. {
  840.     CMDraftData *somThis = CMDraftGetData(somSelf);
  841.     CMDraftMethodDebug("CMDraft","RemoveChanges");
  842.     
  843.     SOM_TRY
  844.     
  845.     VersionList*    versionList = kODNULL;
  846.     
  847.     somSelf->FailIfNotExclusiveWrite(ev);
  848.     
  849.     if (_fDraftProperties != kODNULL) {
  850.         _fDraftProperties->Release(ev);
  851.         _fDraftProperties = kODNULL;
  852.     }
  853.     
  854. //    WASSERTM((somSelf->AreEmptyCollections(ev) != kODFalse), "OutstandingObjects in CMDraft: RemoveChanges.");
  855.     
  856.     somSelf->DestroyVersion(ev);
  857.     
  858.     versionList = _fDocument->TestAndGetVersionList(ev);
  859.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  860.  
  861. #ifdef ODDebug_VersionList
  862.     _fDocument->GetVersionList(ev)->Print(">>> Entering RemoveChanges");
  863. #endif
  864.  
  865.     TRY
  866.         if (versionList->Exists(_fID) != kODFalse)
  867.             versionList->RemoveChanges(_fID);
  868.         
  869.     CATCH_ALL
  870.     
  871.         _fDocument->ReleaseVersionList(ev);
  872.         RERAISE;
  873.  
  874.     ENDTRY
  875.  
  876. #if !TestFlushContainer
  877.     _fDocument->ExternalizeVersionList(ev, kODFalse);
  878. #endif
  879.     _fDocument->ReleaseVersionList(ev);
  880.         
  881.     somSelf->Open(ev);
  882.     
  883.     somSelf->SetChangedFromPrevFlag(ev, kODFalse);
  884.  
  885. #ifdef ODDebug_VersionList
  886.     _fDocument->GetVersionList(ev)->Print(">>> Exiting RemoveChanges");
  887. #endif
  888.  
  889.     return somSelf;
  890.  
  891.     SOM_CATCH_ALL
  892.     SOM_ENDTRY
  893.     return somSelf;
  894. }
  895.  
  896. //------------------------------------------------------------------------------
  897. // CMDraft: Externalize
  898. //------------------------------------------------------------------------------
  899.  
  900. SOM_Scope ODDraft*  SOMLINK CMDraftExternalize(CMDraft *somSelf, Environment *ev)
  901. {
  902.     CMDraftData *somThis = CMDraftGetData(somSelf);
  903.     CMDraftMethodDebug("CMDraft","Externalize");
  904.  
  905.     SOM_TRY
  906.     
  907.     somSelf->ExternalizeCollections(ev);
  908.     
  909.     _fExternalized = kODTrue;
  910.         
  911.     // DO THE ACTUAL EXTERNALIZATION HERE
  912.     
  913.     somSelf->FlushVersion(ev);
  914.     
  915.     return somSelf;
  916.  
  917.     SOM_CATCH_ALL
  918.     SOM_ENDTRY
  919.     return somSelf;
  920. }
  921.  
  922. //------------------------------------------------------------------------------
  923. // CMDraft: SaveToAPrevious
  924. //------------------------------------------------------------------------------
  925.  
  926. SOM_Scope ODDraft*  SOMLINK CMDraftSaveToAPrevious(CMDraft *somSelf, Environment *ev,
  927.         ODDraft* to)
  928. {
  929.     CMDraftData *somThis = CMDraftGetData(somSelf);
  930.     CMDraftMethodDebug("CMDraft","SaveToAPrevious");
  931.  
  932.     SOM_TRY
  933.  
  934.     _fDocument->SaveToAPrevDraft(ev, somSelf, to);
  935.     return somSelf;
  936.  
  937.     SOM_CATCH_ALL
  938.     SOM_ENDTRY
  939.     return somSelf;
  940. }
  941.  
  942. //------------------------------------------------------------------------------
  943. // CMDraft: CreateFrame
  944. //------------------------------------------------------------------------------
  945.  
  946. SOM_Scope ODFrame*  SOMLINK CMDraftCreateFrame(CMDraft *somSelf, Environment *ev,
  947.         ODObjectType        frameType,
  948.         ODFrame*    containingFrame,
  949.         ODShape*     frameShape,
  950.         ODCanvas*    biasCanvas,
  951.         ODPart*         part,
  952.         ODTypeToken    viewType,
  953.         ODTypeToken    presentation,
  954.         ODBoolean        isSubframe,
  955.         ODBoolean         isOverlaid)
  956. {
  957.     CMDraftData *somThis = CMDraftGetData(somSelf);
  958.     CMDraftMethodDebug("CMDraft","CreateFrame");
  959.  
  960.     ODStorageUnit*        su = kODNULL;
  961.     ODFrame*            frame = kODNULL;
  962.     ODStorageUnitID        id = kODNULLID;
  963.  
  964.     ODVolatile(su);
  965.     ODVolatile(frame);
  966.     ODVolatile(id);
  967.  
  968.     SOM_TRY
  969.  
  970.         if (ODISOStrEqual(frameType, kODFrameObject) != kODFalse)    
  971.             somSelf->FailIfNotExclusiveWrite(ev);
  972.  
  973.         frame = new ODFrame();
  974.         if (frame == kODNULL)
  975.             THROW(kODErrCannotCreateFrame);
  976.         
  977.          if (ODISOStrEqual(frameType, kODFrameObject) != kODFalse) {
  978.             su = somSelf->CreateSU(ev, kODNULL, kODFrameObject);
  979.             SetStorageUnitType(ev, _fPermissions, su, kODFrameObject);
  980.             id = su->GetID(ev);
  981.             _fPersistentObjects->ReplaceEntry(&id, &frame);
  982.             frame->InitFrame(ev, su, containingFrame, frameShape, biasCanvas, part,
  983.                              viewType, presentation, isSubframe, isOverlaid);
  984.             somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  985.         }
  986.         else if (ODISOStrEqual(frameType, kODNonPersistentFrameObject) != kODFalse) {
  987.             id = _fIDList->Add(kODNULL);
  988.             _fPersistentObjects->ReplaceEntry(&id, &frame);
  989.             frame->InitFrameNonPersistent(ev, somSelf, id, containingFrame, frameShape,
  990.                         biasCanvas, part, viewType, presentation, isSubframe, isOverlaid);
  991.         }
  992.         else
  993.             THROW(kODErrInvalidObjectType);
  994.  
  995.     
  996.     SOM_CATCH_ALL
  997.         if (frame != kODNULL) {
  998.             TRY{
  999.                 if (id != kODNULLID)
  1000.                 {
  1001.                     if (su == kODNULL)
  1002.                     {
  1003.                         // This is just for non-persistent frame.
  1004.                         // Every other real persistent object should use RemovePersistentObject.
  1005.                         ODReleaseObject(ev, frame);
  1006.                         _fPersistentObjects->RemoveEntry(&id);
  1007.                     }
  1008.                     else
  1009.                         somSelf->RemovePersistentObject(ev, frame);
  1010.                 }
  1011.                 else {
  1012.                     delete frame;
  1013.                     if (su != kODNULL)
  1014.                         somSelf->RemoveStorageUnit(ev, su);
  1015.                 }
  1016.             }CATCH_ALL{
  1017.                 // ignore exception
  1018.             }ENDTRY
  1019.             frame = kODNULL;
  1020.         }
  1021.     SOM_ENDTRY
  1022.         
  1023.     return frame;
  1024. }
  1025.  
  1026. //------------------------------------------------------------------------------
  1027. // CMDraft: AcquireFrame
  1028. //------------------------------------------------------------------------------
  1029.  
  1030. SOM_Scope ODFrame*  SOMLINK CMDraftAcquireFrame(CMDraft *somSelf, Environment *ev,
  1031.         ODStorageUnitID id)
  1032. {
  1033.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1034.     CMDraftMethodDebug("CMDraft","AcquireFrame");
  1035.  
  1036.     ODStorageUnit*    su = kODNULL; ODVolatile(su);
  1037.     ODFrame*        frame = kODNULL; ODVolatile(frame);
  1038.  
  1039.     SOM_TRY
  1040.  
  1041.     if (id == kODNULLID)
  1042.         THROW(kODErrIllegalNullIDInput);
  1043.         
  1044.     frame = (ODFrame*) somSelf->RetrievePersistentObject(ev, id);
  1045.     
  1046.     if (frame == kODNULL) {    
  1047.         
  1048.         su = somSelf->AcquireStorageUnit(ev, id);
  1049.         frame = new ODFrame();
  1050.         
  1051.         if (frame == kODNULL)
  1052.             THROW(kODErrCannotAcquireFrame);
  1053.  
  1054.         // A better way to do this is to let ODFrame::InitFrameFromStorage or
  1055.         // ODPersistentObject::InitPersistentObjectFromStorage to increment the
  1056.         // refcount. In that way, we can always release su here (or even better
  1057.         // make su into a temp obj. - VL        
  1058.         _fPersistentObjects->ReplaceEntry(&id, &frame);
  1059.         frame->InitFrameFromStorage(ev, su);
  1060.         
  1061.         ODStorageUnit *su2 = su;
  1062.         su = kODNULL;                                    // frame owns reference now
  1063.         
  1064.         SetStorageUnitType(ev, _fPermissions, su2, kODFrameObject);
  1065.     }
  1066.     
  1067.     SOM_CATCH_ALL
  1068.         ODSafeReleaseObject(su);
  1069.         if( frame ) WASSERT(frame->GetRefCount(ev)==1);
  1070.         ODSafeReleaseObject(frame);
  1071.     SOM_ENDTRY
  1072.     
  1073.     return frame;
  1074. }
  1075.  
  1076. //------------------------------------------------------------------------------
  1077. // CMDraft: ReleaseFrame
  1078. //------------------------------------------------------------------------------
  1079.  
  1080. SOM_Scope void  SOMLINK CMDraftReleaseFrame(CMDraft *somSelf, Environment *ev,
  1081.         ODFrame* frame)
  1082. {
  1083.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1084.     CMDraftMethodDebug("CMDraft","ReleaseFrame");
  1085.  
  1086.     SOM_TRY
  1087.  
  1088.     somSelf->ReleasePersistentObject(ev, frame);
  1089.  
  1090.     SOM_CATCH_ALL
  1091.     SOM_ENDTRY
  1092. }
  1093.  
  1094. //------------------------------------------------------------------------------
  1095. // CMDraft: RemoveFrame
  1096. //------------------------------------------------------------------------------
  1097.  
  1098. SOM_Scope void  SOMLINK CMDraftRemoveFrame(CMDraft *somSelf, Environment *ev,
  1099.         ODFrame* frame)
  1100. {
  1101.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1102.     CMDraftMethodDebug("CMDraft","RemoveFrame");
  1103.  
  1104.     SOM_TRY
  1105.  
  1106.     somSelf->FailIfNotExclusiveWrite(ev);
  1107.     
  1108.     if (frame->GetStorageUnit(ev) == kODNULL)
  1109.         frame->Release(ev);
  1110.     else
  1111.         somSelf->RemovePersistentObject(ev, frame);
  1112.  
  1113.     SOM_CATCH_ALL
  1114.     SOM_ENDTRY
  1115. }
  1116.  
  1117. //------------------------------------------------------------------------------
  1118. // CMDraft: ConstructRealPart
  1119. //------------------------------------------------------------------------------
  1120.  
  1121. SOM_Scope ODPart*  SOMLINK CMDraftConstructRealPart(CMDraft *somSelf, Environment *ev,
  1122.         ODStorageUnit* su, ODBoolean isInitPartFromStorage,
  1123.         ODPartWrapper* partWrapper,
  1124.         ODType partType, ODEditor theEditor)
  1125. {
  1126.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1127.     CMDraftMethodDebug("CMDraft","ConstructRealPart");
  1128.  
  1129.     ODPart* part = kODNULL;    ODVolatile(part);
  1130.     ODEditor editorForPart = kODNULL;
  1131.     
  1132.     SOM_TRY
  1133.  
  1134.         ODSession*            session = (ODSession*) _fDocument->GetContainer(ev)->GetStorageSystem(ev)->GetSession(ev);
  1135.         ODBinding*            binding = session->GetBinding(ev);
  1136.         ODBoolean            degradeToNoPart = kODFalse;
  1137.         ODError                partLoadErr = noErr;
  1138.         Str255                partLoadErrStr = "\p";
  1139.         
  1140.         if (theEditor == kODNULL)
  1141.             editorForPart = binding->ChooseEditorForPart(ev, su, partType);
  1142.         else
  1143.         {
  1144.             editorForPart = theEditor;
  1145.             if (_fPermissions != kODDPReadOnly)
  1146.                 ODSetISOStrProp(ev, su, kODPropPreferredEditor, kODEditor, editorForPart);
  1147.         }
  1148.     
  1149.         do {
  1150.         //    if (degradeToNoPart) {    
  1151.         //        partWrapper->SetRealPart(ev, part, kODBlackBoxHandlerOfLastResort);
  1152.                 /* Don't display alert now, set NoPart message instead:
  1153.                 ODIText* editorUserString = kODNULL;
  1154.                 Str255     editorString = "\p";
  1155.                 GetUserEditorFromEditor( session->GetNameSpaceManager(ev), editorForPart, &editorUserString );
  1156.                 TempODIText tempEditorUserString = editorUserString; // ensure it's deleted
  1157.                 GetITextPString( editorUserString, editorString );
  1158.                 ParamText(editorString, "\p", "\p", "\p");
  1159.                 (void) ShowAlert(ev, kODAlertCannotLoadPartError, kODNULL, session);
  1160.                 */
  1161.         //    }
  1162.  
  1163.             ODBoolean editorIsNoPart = ODISOStrEqual(editorForPart, kODBlackBoxHandlerOfLastResort);
  1164.             if (degradeToNoPart || editorIsNoPart) {
  1165.                 part = binding->ConstructNoPart(ev);
  1166.                 // Set message in part to explain to user why it appeared:
  1167.                 ODError err;
  1168.                 ODIText *editorName = kODNULL; 
  1169.                 if( degradeToNoPart ) {                        // Reason 1: Error loading part
  1170.                     err = partLoadErr;
  1171.                     if (!GetUserEditorFromEditor( session->GetNameSpaceManager(ev), editorForPart, &editorName )) 
  1172.                         editorName = CreateIText(smRoman,langEnglish,theEditor);
  1173.                 } else {
  1174.                     err = 0;                                // Reason 2: Couldn't find part editor
  1175.                     ODULong size;
  1176.                     // We *must* use preferred-editor-user-string property here once it exists:
  1177.                     TempODEditor editor = ODGetISOStrProp(ev, su, 
  1178.                                         kODPropPreferredEditor, kODEditor, kODNULL, &size);
  1179.                     if( editor && !ODISOStrEqual(editor,kODBlackBoxHandlerOfLastResort) )
  1180.                         editorName = CreateIText(smRoman,langEnglish,editor);    // SOM classnames are always Roman...
  1181.                 }
  1182.                 CAST(part,Apple_NoPart)->SetUserMessage(ev, err,editorName,p2cstr(partLoadErrStr));
  1183.                 
  1184.             } else {
  1185.                 // try to construct a part, if it fails then construct a NoPart instead
  1186.                 TRY
  1187.                     part = (ODPart*) ODNewObject(editorForPart,partLoadErrStr);
  1188.                 CATCH_ALL
  1189.                     partLoadErr = ErrorCode();
  1190.                     degradeToNoPart = kODTrue;
  1191.                     // note that part is still not valid because the allocation failed
  1192.                     continue;
  1193.                 ENDTRY
  1194.             }
  1195.         
  1196.             if (part == kODNULL)
  1197.                 THROW(kODErrCannotCreatePart);
  1198.             
  1199.             if (degradeToNoPart) {    
  1200.                 partWrapper->SetRealPart(ev, part, kODBlackBoxHandlerOfLastResort);
  1201.             } else
  1202.                 partWrapper->SetRealPart(ev, part, editorForPart);
  1203.         
  1204.             ODID id = su->GetID(ev);
  1205.             _fPersistentObjects->ReplaceEntry(&id, &partWrapper);
  1206.             
  1207.             su->Acquire(ev);                                 //This new reference belongs to the part
  1208.             
  1209.             TRY
  1210.                 if (isInitPartFromStorage)
  1211.                     partWrapper->InitPartFromStorage(ev, su, partWrapper);
  1212.                 else
  1213.                     partWrapper->InitPart(ev, su, partWrapper);
  1214.             CATCH_ALL
  1215. //                if ( ErrorCode() != memFullErr && ErrorCode()!=kODErrOutOfMemory )    
  1216. //                    RERAISE;
  1217.                 // not enough memory to Init, treat as can't load part
  1218.                 if (part) {
  1219.                     part->Release(ev);    // ReleaseRealPart expect ref count 0
  1220.                     somSelf->ReleaseRealPart(ev, part);
  1221.                     part = kODNULL;    
  1222.                 }
  1223.                 if (degradeToNoPart)
  1224.                     RERAISE;
  1225.                 degradeToNoPart = kODTrue;
  1226.                 partLoadErr = ErrorCode();
  1227.             ENDTRY
  1228.         } while (degradeToNoPart && (part == kODNULL));
  1229.     
  1230.     SOM_CATCH_ALL
  1231.     
  1232.         part = kODNULL;
  1233.  
  1234.         if( ErrorCode() == kODErrCantLoadSOMClass )
  1235.             SetErrorCode(kODErrCannotCreatePart);        // Map to more specific error
  1236.  
  1237.     SOM_ENDTRY    
  1238.     
  1239.     if (editorForPart != theEditor)
  1240.         ODDisposePtr(editorForPart);
  1241.     
  1242.     return part;
  1243. }
  1244.  
  1245. //------------------------------------------------------------------------------
  1246. // CMDraft: ReleaseRealPart
  1247. //------------------------------------------------------------------------------
  1248.  
  1249. SOM_Scope void  SOMLINK CMDraftReleaseRealPart(CMDraft *somSelf, Environment *ev,
  1250.                                                 ODPart* realPart)
  1251. {
  1252.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1253.     CMDraftMethodDebug("CMDraft","ReleaseRealPart");
  1254.  
  1255.     SOM_TRY
  1256.     
  1257.     if (realPart == kODNULL)
  1258.         THROW(kODErrIllegalNullPartInput);
  1259.  
  1260.     if (realPart->GetRefCount(ev) != 0)
  1261.         THROW(kODErrRefCountGreaterThanZero);
  1262.     
  1263.     realPart->ReleaseAll(ev);
  1264.         
  1265.     delete realPart;
  1266.  
  1267.     SOM_CATCH_ALL
  1268.     SOM_ENDTRY
  1269. }
  1270.  
  1271. //------------------------------------------------------------------------------
  1272. // CMDraft: DeleteRealPart
  1273. //------------------------------------------------------------------------------
  1274.  
  1275. SOM_Scope void  SOMLINK CMDraftDeleteRealPart(CMDraft *somSelf, Environment *ev,
  1276.                                                 ODPart* realPart)
  1277. {
  1278.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1279.     CMDraftMethodDebug("CMDraft","DeleteRealPart");
  1280.  
  1281.     SOM_TRY
  1282.     
  1283.     if (realPart == kODNULL)
  1284.         THROW(kODErrIllegalNullPartInput);
  1285.  
  1286.     delete realPart;
  1287.  
  1288.     SOM_CATCH_ALL
  1289.     SOM_ENDTRY
  1290. }
  1291.  
  1292. //------------------------------------------------------------------------------
  1293. // CMDraft: CreatePart
  1294. //------------------------------------------------------------------------------
  1295.  
  1296. SOM_Scope ODPart*  SOMLINK CMDraftCreatePart(CMDraft *somSelf, Environment *ev,
  1297.         ODType partType, ODEditor optionalEditor)
  1298. {
  1299.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1300.     CMDraftMethodDebug("CMDraft","CreatePart");
  1301.  
  1302.     
  1303.     ODPartWrapper* partWrapper = kODNULL;
  1304.     
  1305.     ODVolatile(partWrapper);
  1306.     SOM_TRY
  1307.     
  1308.         somSelf->FailIfNotExclusiveWrite(ev);
  1309.     
  1310.         TempODStorageUnit su = somSelf->CreateSU(ev, kODNULL, kODPartObject);
  1311.     
  1312.         SetStorageUnitType(ev, _fPermissions, su, kODPartObject);
  1313.         
  1314.         if ( partType != kODNULL )
  1315.         {
  1316.             ODSetISOStrProp(ev, su, kODPropPreferredKind, kODISOStr, partType);
  1317.         }
  1318.     
  1319.         partWrapper = new ODPartWrapper;
  1320.         THROW_IF_NULL(partWrapper, kODErrOutOfMemory);
  1321.         partWrapper->InitPartWrapper(ev);
  1322.         
  1323.         somSelf->ConstructRealPart(ev, su, kODFalse, partWrapper, partType, optionalEditor);
  1324.     
  1325.         somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1326.         
  1327.     SOM_CATCH_ALL
  1328.     
  1329.         ODSafeReleaseObject(partWrapper);
  1330.         partWrapper = kODNULL;
  1331.         
  1332.     SOM_ENDTRY
  1333.  
  1334.     return partWrapper;
  1335. }
  1336.  
  1337. //------------------------------------------------------------------------------
  1338. // CMDraft: AcquirePart
  1339. //------------------------------------------------------------------------------
  1340.  
  1341. SOM_Scope ODPart*  SOMLINK CMDraftAcquirePart(CMDraft *somSelf, Environment *ev,
  1342.         ODStorageUnitID id)
  1343. {
  1344.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1345.     CMDraftMethodDebug("CMDraft","AcquirePart");
  1346.  
  1347.     ODPart* part = kODNULL;
  1348.     ODPartWrapper* partWrapper = kODNULL;
  1349.     
  1350.     ODVolatile(partWrapper);
  1351.     SOM_TRY
  1352.     
  1353.         if (id == kODNULLID)
  1354.             THROW(kODErrIllegalNullIDInput);
  1355.     
  1356.         part = (ODPart*) somSelf->RetrievePersistentObject(ev, id);
  1357.         if (part == kODNULL) {
  1358.             ODStorageUnit*    su = kODNULL;
  1359.             
  1360.             if (_fStorageUnits->GetValue(&id, &su) != kODFalse)
  1361.                 su->Acquire(ev);
  1362.             else 
  1363.                 su = somSelf->CreateSU(ev, id, kODPartObject);
  1364.             TempODStorageUnit tempSU = su; // ensure it's released
  1365.     
  1366.             partWrapper = new ODPartWrapper;
  1367.             THROW_IF_NULL(partWrapper, kODErrOutOfMemory);
  1368.             partWrapper->InitPartWrapper(ev);
  1369.             
  1370.             somSelf->ConstructRealPart(ev, su, kODTrue, partWrapper, kODNULL,  kODNULL);
  1371.     
  1372.             part = partWrapper;
  1373.     
  1374.             SetStorageUnitType(ev, _fPermissions, su, kODPartObject);
  1375.         }
  1376.     
  1377.     SOM_CATCH_ALL
  1378.         
  1379.         ODSafeReleaseObject(partWrapper);
  1380.         part = kODNULL;
  1381.         
  1382.     SOM_ENDTRY
  1383.     
  1384.     return part;
  1385. }
  1386.  
  1387. //------------------------------------------------------------------------------
  1388. // CMDraft: ReleasePart
  1389. //------------------------------------------------------------------------------
  1390.  
  1391. SOM_Scope void  SOMLINK CMDraftReleasePart(CMDraft *somSelf, Environment *ev,
  1392.         ODPart* part)
  1393. {
  1394.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1395.     CMDraftMethodDebug("CMDraft","ReleasePart");
  1396.  
  1397.     SOM_TRY
  1398.  
  1399.     somSelf->ReleasePersistentObject(ev, part);
  1400.  
  1401.     SOM_CATCH_ALL
  1402.     SOM_ENDTRY
  1403. }
  1404.  
  1405. //------------------------------------------------------------------------------
  1406. // CMDraft: RemovePart
  1407. //------------------------------------------------------------------------------
  1408.  
  1409. SOM_Scope void  SOMLINK CMDraftRemovePart(CMDraft *somSelf, Environment *ev,
  1410.         ODPart* part)
  1411. {
  1412.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1413.     CMDraftMethodDebug("CMDraft","RemovePart");
  1414.  
  1415.     SOM_TRY
  1416.  
  1417.     somSelf->RemovePersistentObject(ev, part);
  1418.  
  1419.     SOM_CATCH_ALL
  1420.     SOM_ENDTRY
  1421. }
  1422.  
  1423. //------------------------------------------------------------------------------
  1424. // CMDraft: CreateLinkSpec
  1425. //------------------------------------------------------------------------------
  1426.  
  1427. SOM_Scope ODLinkSpec*  SOMLINK CMDraftCreateLinkSpec (CMDraft *somSelf, Environment *ev,
  1428.         ODPart* part,
  1429.         ODByteArray* data)
  1430. {
  1431.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1432.     CMDraftMethodDebug("CMDraft","CreateLinkSpec");
  1433.  
  1434.     ODLinkSpec* ls = kODNULL;
  1435.     
  1436.     ODVolatile(ls);
  1437.     SOM_TRY
  1438.         ls = new ODLinkSpec;
  1439.         THROW_IF_NULL(ls, kODErrOutOfMemory);
  1440.         ls->InitLinkSpec(ev, part, data);
  1441.     SOM_CATCH_ALL
  1442.         ODDeleteObject(ls);
  1443.     SOM_ENDTRY
  1444.         
  1445.     return ls;
  1446. }
  1447.  
  1448. //------------------------------------------------------------------------------
  1449. // CMDraft: CreateLinkSource
  1450. //------------------------------------------------------------------------------
  1451.  
  1452. SOM_Scope ODLinkSource*  SOMLINK CMDraftCreateLinkSource(CMDraft *somSelf, Environment *ev,
  1453.         ODPart* part)
  1454. {
  1455.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1456.     CMDraftMethodDebug("CMDraft","CreateLinkSource");
  1457.  
  1458.     SOM_TRY
  1459.  
  1460.     ODStorageUnitID    id;
  1461.     ODLinkSource*    linkSource = kODNULL;
  1462.  
  1463.     somSelf->FailIfNotExclusiveWrite(ev);
  1464.  
  1465.     TempODStorageUnit su = somSelf->CreateSU(ev, kODNULL, kODLinkSource);
  1466.  
  1467.     // The implementation of CMLinkSourceIterator depends on this property being present
  1468.     // in link source storage units and nowhere else.
  1469.     
  1470.     SetStorageUnitType(ev, _fPermissions, su, kODLinkSource);
  1471.     
  1472.     linkSource = new ODLinkSource();
  1473.     THROW_IF_NULL(linkSource,kODErrCannotCreateLink);
  1474.     
  1475.     TempODLink link = kODNULL;
  1476.     TRY
  1477.         link = somSelf->CreateLink(ev);
  1478.     CATCH_ALL
  1479.         linkSource->ReleaseAll(ev);
  1480.         delete linkSource;
  1481.         RERAISE;
  1482.     ENDTRY
  1483.         
  1484.     id = su->GetID(ev);
  1485.     
  1486.     _fPersistentObjects->ReplaceEntry(&id, &linkSource);
  1487.     
  1488.     linkSource->InitLinkSource(ev, su.DontRelease(), part);
  1489.     // ("DontDelete" prevents su from being auto-released by destructor)
  1490.     
  1491.     link->SetLinkSource(ev, linkSource);
  1492.     linkSource->SetLink(ev, link);
  1493.  
  1494.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1495.  
  1496.     return linkSource;
  1497.  
  1498.     SOM_CATCH_ALL
  1499.     SOM_ENDTRY
  1500.     return kODNULL;
  1501. }
  1502.  
  1503. //------------------------------------------------------------------------------
  1504. // CMDraft: AcquireLinkSource
  1505. //------------------------------------------------------------------------------
  1506.  
  1507. SOM_Scope ODLinkSource*  SOMLINK CMDraftAcquireLinkSource(CMDraft *somSelf, Environment *ev,
  1508.         ODStorageUnitID id)
  1509. {
  1510.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1511.     CMDraftMethodDebug("CMDraft","AcquireLinkSource");
  1512.  
  1513.     SOM_TRY
  1514.  
  1515.     if (id == kODNULLID)
  1516.         THROW(kODErrIllegalNullIDInput);
  1517.         
  1518.     ODLinkSource* linkSource = (ODLinkSource*) kODNULL;
  1519.     
  1520.     linkSource = ((ODLinkSource*) somSelf->RetrievePersistentObject(ev, id));
  1521.  
  1522.     if (linkSource == (ODLinkSource*) kODNULL) {    
  1523.         linkSource = new ODLinkSource();
  1524.         if (linkSource == (ODLinkSource*) kODNULL)
  1525.                 THROW(kODErrCannotAcquireLink);
  1526.             
  1527.         ODStorageUnit*    su = (ODStorageUnit*) kODNULL;
  1528.         ODVolatile(su);
  1529.         ODVolatile(id);
  1530.         TRY
  1531.             su = somSelf->AcquireStorageUnit(ev, id);
  1532.             _fPersistentObjects->ReplaceEntry(&id, &linkSource);
  1533.             linkSource->InitLinkSourceFromStorage(ev, su);
  1534.              SetStorageUnitType(ev, _fPermissions, su, kODLinkSource);
  1535.         CATCH_ALL
  1536.             if (su != (ODStorageUnit*) kODNULL) {
  1537.                 _fPersistentObjects->RemoveEntry(&id);
  1538.                 su->Release(ev);
  1539.                 }
  1540.             linkSource->ReleaseAll(ev);
  1541.             delete linkSource;
  1542.             RERAISE;
  1543.         ENDTRY
  1544.         }
  1545.  
  1546.     return linkSource;
  1547.  
  1548.     SOM_CATCH_ALL
  1549.     SOM_ENDTRY
  1550.     return kODNULL;
  1551. }
  1552.  
  1553. //------------------------------------------------------------------------------
  1554. // CMDraft: RemoveLinkSource
  1555. //------------------------------------------------------------------------------
  1556.  
  1557. SOM_Scope void  SOMLINK CMDraftRemoveLinkSource(CMDraft *somSelf, Environment *ev,
  1558.         ODLinkSource* linkSource)
  1559. {
  1560.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1561.     CMDraftMethodDebug("CMDraft","RemoveLinkSource");
  1562.  
  1563.     SOM_TRY
  1564.  
  1565.     somSelf->FailIfNotExclusiveWrite(ev);
  1566.         
  1567.     somSelf->RemovePersistentObject(ev, linkSource);
  1568.  
  1569.     SOM_CATCH_ALL
  1570.     SOM_ENDTRY
  1571. }
  1572.  
  1573. //------------------------------------------------------------------------------
  1574. // CMDraft: CreateLink
  1575. //------------------------------------------------------------------------------
  1576.  
  1577. SOM_Scope ODLink*  SOMLINK CMDraftCreateLink(CMDraft *somSelf, Environment *ev)
  1578. {
  1579.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1580.     CMDraftMethodDebug("CMDraft","CreateLink");
  1581.  
  1582.     SOM_TRY
  1583.  
  1584.     ODStorageUnitID    id;
  1585.     ODLink*            link = kODNULL;
  1586.     ODStorageUnit*     su;
  1587.  
  1588.     su = somSelf->CreateSU(ev, kODNULL, kODLink);
  1589.     
  1590.     // The implementation of CMLinkIterator depends on this property being present
  1591.     // in link storage units and nowhere else.
  1592.     SetStorageUnitType(ev, _fPermissions, su, kODLink);
  1593.     
  1594.     link = new ODLink();
  1595.     if (link == kODNULL) 
  1596.     {
  1597.         delete su;
  1598.         THROW(kODErrCannotCreateLink);
  1599.     }
  1600.  
  1601.     id = su->GetID(ev);
  1602.     _fPersistentObjects->ReplaceEntry(&id, &link);
  1603.     
  1604.     link->InitLink(ev, su);
  1605.  
  1606.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  1607.  
  1608.     return link;
  1609.  
  1610.     SOM_CATCH_ALL
  1611.     SOM_ENDTRY
  1612.     return kODNULL;
  1613. }
  1614.  
  1615. //------------------------------------------------------------------------------
  1616. // CMDraft: AcquireLink
  1617. //------------------------------------------------------------------------------
  1618.  
  1619. SOM_Scope ODLink*  SOMLINK CMDraftAcquireLink(CMDraft *somSelf, Environment *ev,
  1620.         ODStorageUnitID id,ODLinkSpec* linkSpec)
  1621. {
  1622.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1623.     CMDraftMethodDebug("CMDraft","AcquireLink");
  1624.  
  1625.     SOM_TRY
  1626.     
  1627.     ODLink* link = (ODLink*) kODNULL;
  1628.  
  1629.     if (id != (ODStorageUnitID) kODNULL) {
  1630.         link = ((ODLink*) somSelf->RetrievePersistentObject(ev, id));
  1631.         if (link == (ODLink*) kODNULL) {    
  1632.             link = new ODLink();
  1633.             if (link == kODNULL)
  1634.                 THROW(kODErrCannotAcquireLink);
  1635.             
  1636.             ODStorageUnit*    su = (ODStorageUnit*) kODNULL;
  1637.             ODVolatile(su);
  1638.             ODVolatile(id);
  1639.             TRY
  1640.                 su = somSelf->AcquireStorageUnit(ev, id);
  1641.                 _fPersistentObjects->ReplaceEntry(&id, &link);
  1642.                 link->InitLinkFromStorage(ev, su);
  1643.                  SetStorageUnitType(ev, _fPermissions, su, kODLink);
  1644.             CATCH_ALL
  1645.                 if (su != (ODStorageUnit*) kODNULL) {
  1646.                     _fPersistentObjects->RemoveEntry(&id);
  1647.                     su->Release(ev);
  1648.                     }
  1649.                 link->ReleaseAll(ev);
  1650.                 delete link;
  1651.                 RERAISE;
  1652.             ENDTRY
  1653.             }
  1654.         }
  1655.     else if (linkSpec == (ODLinkSpec*) kODNULL) {
  1656.         THROW(kODErrInsufficientInfoInParams);
  1657.         }
  1658.     else if (linkSpec->FromThisDraft(ev)) {
  1659.         ODPart* part = linkSpec->GetPart(ev);
  1660.         ODByteArray partData = linkSpec->GetPartData(ev);
  1661.         ODVolatile(partData);
  1662.         ODLinkSource* linkSource = kODNULL;
  1663.         ODVolatile(linkSource);
  1664.         TRY
  1665.             linkSource = part->CreateLink(ev, &partData);
  1666.             if ( linkSource != (ODLinkSource*) kODNULL ) {
  1667.                 link = linkSource->GetLink(ev);
  1668.                 if ( link != (ODLink*) kODNULL )
  1669.                     link->Acquire(ev);
  1670.                 }
  1671.         CATCH_ALL
  1672.             DisposeByteArrayStruct(partData);
  1673.             ODReleaseObject(ev, linkSource);
  1674.             RERAISE;
  1675.         ENDTRY
  1676.         DisposeByteArrayStruct(partData);
  1677.         ODReleaseObject(ev, linkSource);
  1678.         }
  1679.     else {
  1680.         // This link spec originated in another document; forward the
  1681.         // AcquireLink call to the originating draft.
  1682.         ODSession* session = _fDocument->GetContainer(ev)->GetStorageSystem(ev)->GetSession(ev);
  1683.         if (session != kODNULL) {
  1684.             ODLinkSource* linkSource = kODNULL;
  1685.             ODVolatile(linkSource);
  1686.             TRY
  1687.                 linkSource = session->GetLinkManager(ev)->CreateLink(ev, somSelf, linkSpec);
  1688.                 if ( linkSource != (ODLinkSource*) kODNULL ) {
  1689.                     link = linkSource->GetLink(ev);
  1690.                     if ( link != (ODLink*) kODNULL )
  1691.                         link->Acquire(ev);
  1692.                     }
  1693.             CATCH_ALL
  1694.                 ODReleaseObject(ev, linkSource);
  1695.                 RERAISE;
  1696.             ENDTRY
  1697.             ODReleaseObject(ev, linkSource);
  1698.             }
  1699.         }
  1700.     return link;
  1701.  
  1702.     SOM_CATCH_ALL
  1703.     SOM_ENDTRY
  1704.     return kODNULL;
  1705. }
  1706.  
  1707. //------------------------------------------------------------------------------
  1708. // CMDraft: ReleaseLink
  1709. //------------------------------------------------------------------------------
  1710.  
  1711. SOM_Scope void  SOMLINK CMDraftReleaseLink(CMDraft *somSelf, Environment *ev,
  1712.         ODLink* link)
  1713. {
  1714.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1715.     CMDraftMethodDebug("CMDraft","ReleaseLink");
  1716.  
  1717.     SOM_TRY
  1718.  
  1719.     somSelf->ReleasePersistentObject(ev, link);
  1720.  
  1721.     SOM_CATCH_ALL
  1722.     SOM_ENDTRY
  1723. }
  1724.  
  1725. //------------------------------------------------------------------------------
  1726. // CMDraft: ReleaseLinkSource
  1727. //------------------------------------------------------------------------------
  1728.  
  1729. SOM_Scope void  SOMLINK CMDraftReleaseLinkSource(CMDraft *somSelf, Environment *ev,
  1730.         ODLinkSource* linkSource)
  1731. {
  1732.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1733.     CMDraftMethodDebug("CMDraft","ReleaseLinkSource");
  1734.  
  1735.     SOM_TRY
  1736.  
  1737.     somSelf->ReleasePersistentObject(ev, linkSource);
  1738.  
  1739.     SOM_CATCH_ALL
  1740.     SOM_ENDTRY
  1741. }
  1742.  
  1743. //------------------------------------------------------------------------------
  1744. // CMDraft: RemoveLink
  1745. //------------------------------------------------------------------------------
  1746.  
  1747. SOM_Scope void  SOMLINK CMDraftRemoveLink(CMDraft *somSelf, Environment *ev,
  1748.         ODLink* link)
  1749. {
  1750.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1751.     CMDraftMethodDebug("CMDraft","RemoveLink");
  1752.  
  1753.     SOM_TRY
  1754.  
  1755.     somSelf->FailIfNotExclusiveWrite(ev);
  1756.         
  1757.     somSelf->RemovePersistentObject(ev, link);
  1758.  
  1759.     SOM_CATCH_ALL
  1760.     SOM_ENDTRY
  1761. }
  1762.  
  1763. //------------------------------------------------------------------------------
  1764. // CMDraft: GetPersistentObjectID
  1765. //------------------------------------------------------------------------------
  1766.  
  1767. SOM_Scope ODPersistentObjectID  SOMLINK CMDraftGetPersistentObjectID(CMDraft *somSelf, Environment *ev,
  1768.         ODPersistentObject* object,
  1769.         ODObjectType    objectType)
  1770. {
  1771.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1772.     CMDraftMethodDebug("CMDraft","GetPersistentObjectID");
  1773.  
  1774.     SOM_TRY
  1775.  
  1776.     ASSERT(ODISOStrEqual(objectType, kODPartObject) || ODISOStrEqual(objectType, kODFrameObject),
  1777.             kODErrInvalidObjectType);
  1778.         
  1779.     CMStorageUnit* su = (CMStorageUnit*) object->GetStorageUnit(ev);
  1780.     
  1781.     if (su == kODNULL)
  1782.         THROW(kODErrInvalidPersistentObject);
  1783.  
  1784.     return su->GetObjectID(ev);
  1785.  
  1786.     SOM_CATCH_ALL
  1787.     SOM_ENDTRY
  1788.     return kODNULLID;
  1789. }
  1790.  
  1791. //------------------------------------------------------------------------------
  1792. // CMDraft: AcquirePersistentObject
  1793. //------------------------------------------------------------------------------
  1794.  
  1795. SOM_Scope ODPersistentObject* SOMLINK CMDraftAcquirePersistentObject(CMDraft *somSelf, Environment *ev,
  1796.         ODPersistentObjectID objectID,
  1797.         ODObjectType*    objectType)
  1798. {
  1799.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1800.     CMDraftMethodDebug("CMDraft","AcquirePersistentObject");
  1801.     
  1802.     SOM_TRY
  1803.     
  1804.     *objectType = kODNULL;
  1805.     ODPersistentObject*    object = kODNULL;
  1806.     ODStorageUnitID    id = kODNULLID;
  1807.     
  1808.     if (objectID == 0)
  1809.         THROW(kODErrIllegalNullIDInput);
  1810.  
  1811.     CMContainer cmContainer = somSelf->GetCMContainer(ev);
  1812.     ODSessionMustHaveCMAllocReserve(cmContainer);
  1813.     
  1814.     CMObject cmObject = CMGetObject(cmContainer, objectID);
  1815.     if (cmObject == kODNULL)
  1816.         THROW(kODErrInvalidPersistentObjectID);
  1817.         
  1818.     if (_fIDList->ObjectExists(cmObject) != kODFalse) {
  1819.         id = _fIDList->GetID(cmObject);
  1820.         CMReleaseObject(cmObject);
  1821.     }
  1822.     else
  1823.         id = _fIDList->Add(cmObject);
  1824.  
  1825.     ODSessionRestoreCMAllocReserve(cmContainer);
  1826.     
  1827.     TempODStorageUnit su = somSelf->AcquireStorageUnit(ev, id);
  1828.     if (su == kODNULL)
  1829.         THROW(kODErrInvalidPersistentObjectID);
  1830.  
  1831.     ODPtr buffer;
  1832.     if ((buffer = ODGetISOStrProp(ev, su, kODPropStorageUnitType, kODISOStr, kODNULL, kODNULL)) != kODNULL)
  1833.     {
  1834.         if (ODISOStrEqual((ODISOStr) buffer, kODPartObject) != kODFalse)
  1835.             object = somSelf->AcquirePart(ev, id);
  1836.         else if (ODISOStrEqual((ODISOStr) buffer, kODFrameObject) != kODFalse)
  1837.             object = somSelf->AcquireFrame(ev, id);
  1838.         else
  1839.             THROW(kODErrInvalidPersistentObjectID);
  1840.         
  1841.         if (object != kODNULL)
  1842.             *objectType = (ODType) buffer;
  1843.         else
  1844.             ODDisposePtr(buffer);        
  1845.     }
  1846.  
  1847.     return object;
  1848.  
  1849.     SOM_CATCH_ALL
  1850.     SOM_ENDTRY
  1851.     return kODNULL;
  1852. }
  1853.  
  1854. //------------------------------------------------------------------------------
  1855. // CMDraft: ReleaseStorageUnit
  1856. //------------------------------------------------------------------------------
  1857.  
  1858. SOM_Scope ODDraft*  SOMLINK CMDraftReleaseStorageUnit(CMDraft *somSelf, Environment *ev,
  1859.         ODStorageUnitID id)
  1860. {
  1861.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1862.     CMDraftMethodDebug("CMDraft","ReleaseStorageUnit");
  1863.  
  1864.     SOM_TRY
  1865.  
  1866.     ODStorageUnit*    su = kODNULL;
  1867.     
  1868.     if (! _fStorageUnits->GetValue(&id, &su))
  1869.         THROW(kODErrInvalidStorageUnit);
  1870.     
  1871.     if (su->GetRefCount(ev) != 0)
  1872.         THROW(kODErrRefCountGreaterThanZero);
  1873.         
  1874.     if (_fDraftProperties != kODNULL) {
  1875.         if (id == _fDraftProperties->GetID(ev))
  1876.             _fDraftProperties = kODNULL;
  1877.     }
  1878.     
  1879.     return somSelf;
  1880.  
  1881.     SOM_CATCH_ALL
  1882.     SOM_ENDTRY
  1883.     return somSelf;
  1884. }
  1885.  
  1886. //------------------------------------------------------------------------------
  1887. // CMDraft: ~CMDraft
  1888. //------------------------------------------------------------------------------
  1889.  
  1890. SOM_Scope void  SOMLINK CMDraftsomUninit(CMDraft *somSelf)
  1891. {
  1892.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1893.     CMDraftMethodDebug("CMDraft","somUninit");
  1894.  
  1895.     TRY{
  1896.         Environment*    ev = somGetGlobalEnvironment();
  1897.     
  1898. #if ODDebug_DebugRefCount
  1899.         if (somSelf->GetRefCount(ev) != 0)
  1900.             DebugStr("\pRefCount of Draft is not 0 at uninit.");
  1901.         somPrintf("~CMDraft %x RefCount %d EmbeddedCtr %x CMCtr %x\n", 
  1902.                     somSelf,
  1903.                     somSelf->GetRefCount(ev),
  1904.                     somSelf->GetEmbeddedContainer(ev),
  1905.                     somSelf->GetCMContainer(ev));
  1906. #endif
  1907.  
  1908.         somSelf->DeleteCollections(ev);
  1909.     }CATCH_ALL{
  1910.            // Ignore exception
  1911.     }ENDTRY
  1912. }
  1913.  
  1914. //------------------------------------------------------------------------------
  1915. // CMDraft: InitDraft
  1916. //------------------------------------------------------------------------------
  1917.  
  1918. SOM_Scope void  SOMLINK CMDraftInitDraft(CMDraft *somSelf, Environment *ev,
  1919.         ODDocument* document, ODDraftID id, ODDraftPermissions perms)
  1920. {
  1921.     CMDraftData *somThis = CMDraftGetData(somSelf);
  1922.     CMDraftMethodDebug("CMDraft","InitDraft");
  1923.  
  1924.     SOM_TRY
  1925.     
  1926.     /* Moved from somInit. SOM itself sets fields to zero
  1927.     _fChangedFromPrev = kODFalse;
  1928.     
  1929.     _fDocument = kODNULL;
  1930.     _fID = 0;
  1931.     _fPermissions = kODDPNone;
  1932.     _fEmbeddedContainer = kODNULL;
  1933.     _fVersionID = kODTombstonedVersion;
  1934.     _fIsNewDraft = kODFalse;
  1935.     
  1936.     _fExternalized = kODFalse;
  1937.     _fRemoveChangeOnAbort = kODFalse;
  1938.     
  1939.     _fStorageUnits = kODNULL;
  1940.     _fPersistentObjects = kODNULL;
  1941.     
  1942.     _fIDList = kODNULL;
  1943.     _fDraftProperties = kODNULL;
  1944.     
  1945.     _fDestDraft = kODNULL;
  1946.     _fDestFrame = kODNULL;
  1947.     _fClonedSUIDs = kODNULL;
  1948.     _fWeakClonedSUIDs = kODNULL;
  1949.     _fSavedWeakClonedSUIDs = kODNULL;
  1950.     _fLinksToCloneSUIDs = kODNULL;
  1951.     _fCurrentKey = kODNULL;
  1952.     _fLockCount = 0;
  1953.  
  1954.     _fAnyFrameCloned = kODFalse;
  1955.     _fRootPartReused = kODFalse;
  1956.  
  1957.     _fOrigTopVersionDraftID = 0;
  1958.  
  1959.     _fHeap = kDefaultHeapID;
  1960.     */
  1961.     _fVersionID = kODTombstonedVersion; 
  1962.     
  1963.     somSelf->InitRefCntObject(ev); 
  1964.  
  1965. #ifdef ODDebug_VersionList
  1966.     ((CMDocument*) document)->GetVersionList(ev)->Print(">>>Entering InitDraft");
  1967. #endif
  1968.     
  1969.     _fDocument = (CMDocument*) document;
  1970.     _fID = id;
  1971.     _fPermissions = perms;
  1972.  
  1973.     VersionList*    versionList = kODNULL;
  1974.  
  1975.     if (_fDocument == kODNULL)
  1976.         THROW(kODErrIllegalNullDocumentInput);
  1977.         
  1978.     if (_fID == kODNULL) {
  1979.         versionList = _fDocument->GetVersionList(ev);
  1980.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  1981.             
  1982.         _fID = versionList->CreateDraft();
  1983.         _fIsNewDraft = kODTrue;
  1984.         _fRemoveChangeOnAbort = kODTrue;
  1985.         
  1986. #if !TestFlushContainer
  1987.         _fDocument->ExternalizeVersionList(ev, kODFalse);
  1988. #endif
  1989.     }
  1990.     
  1991.     somSelf->CreateCollections(ev);
  1992.             
  1993. #if lazyOpen
  1994.     _fExternalized = kODFalse;
  1995. #else
  1996.     if (_fPermissions == kODDPReadOnly)
  1997.         somSelf->OpenVersion(ev);
  1998.     else
  1999.         somSelf->CreateVersion(ev);
  2000. #endif
  2001.         
  2002.     _fHeap = _fDocument->GetHeap(ev);
  2003.  
  2004.  
  2005. #ifdef ODDebug_Unloading_Classes
  2006.     SetOutputMode(kWriteToFile);
  2007. #endif
  2008.  
  2009. #ifdef ODDebug_VersionList
  2010.     _fDocument->GetVersionList(ev)->Print(">>>Exiting InitDraft");
  2011. #endif
  2012.  
  2013.     SOM_CATCH_ALL
  2014.     SOM_ENDTRY
  2015. }
  2016.  
  2017. //------------------------------------------------------------------------------
  2018. // CMDraft: Purge
  2019. //------------------------------------------------------------------------------
  2020.  
  2021. SOM_Scope ODSize  SOMLINK CMDraftPurge(CMDraft *somSelf, Environment *ev,
  2022.         ODSize size)
  2023. {
  2024.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2025.     CMDraftMethodDebug("CMDraft","Purge");
  2026.  
  2027.     ODULong    runningTotal = 0; ODVolatile( runningTotal );
  2028.         
  2029.     SOM_TRY
  2030.  
  2031.         OpenHashTableIterator    i(_fPersistentObjects);
  2032.         ODStorageUnitID        id;
  2033.         ODPersistentObject*    object;
  2034.         for (i.First(&id, &object); i.IsNotComplete(); i.Next(&id, &object)) {
  2035.             TRY
  2036.                 runningTotal += object->Purge(ev, size);
  2037.             CATCH_ALL
  2038.             ENDTRY
  2039.  
  2040.             TRY
  2041.                 if (object->GetRefCount(ev) == 0) {
  2042.                     object->ReleaseAll(ev);
  2043.                 }
  2044.             CATCH_ALL
  2045.             ENDTRY
  2046.         }
  2047.         for (i.First(&id, &object); i.IsNotComplete(); i.Next(&id, &object)) {
  2048.             if (object->GetRefCount(ev) == 0) {
  2049.                 i.RemoveCurrent();
  2050.                 delete object;
  2051.             }
  2052.         }
  2053.         // ShrinkToFit() allocates new tables first, and this aggravates
  2054.         // low memory conditions during Purge().
  2055.         // _fPersistentObjects->ShrinkToFit(/*extraSlots*/ 0);
  2056.                 
  2057.         // purge all storage units, but don't release CMObjects 
  2058.         runningTotal += PurgeAllStorageUnits(ev, _fStorageUnits, kODNULL);
  2059.  
  2060.         // dh - call parent Purge method
  2061.         runningTotal += parent_Purge(somSelf, ev, size);
  2062.         
  2063.     SOM_CATCH_ALL
  2064.         WARN("Error %ld trying to purge in CMDraftPurge",ErrorCode());
  2065.         SetErrorCode(kODNoError);        // dh - Eat the exception; Purge should not 
  2066.                                         // propagate it because clients function
  2067.                                         // fine whether memory was purged or not.
  2068.     SOM_ENDTRY
  2069.  
  2070.     return runningTotal;
  2071. }
  2072.  
  2073. //------------------------------------------------------------------------------
  2074. // CMDraft: CreateSU
  2075. //------------------------------------------------------------------------------
  2076.  
  2077. SOM_Scope ODStorageUnit*  SOMLINK CMDraftCreateSU(CMDraft *somSelf, Environment *ev,
  2078.         ODStorageUnitID id, ODType suType)
  2079. {
  2080.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2081.     CMDraftMethodDebug("CMDraft","CreateSU");
  2082.     
  2083.     ODStorageUnit*    su = kODNULL;
  2084.  
  2085.     SOM_TRY
  2086.  
  2087.     CMObject        object = kODNULL;
  2088.     CMContainer        cmContainer = somSelf->GetCMContainer(ev);
  2089.     ODSessionMustHaveCMAllocReserve(cmContainer);
  2090.  
  2091.     ODVolatile(su);
  2092.     ODVolatile(object);
  2093.     TRY    
  2094.         
  2095.         // Create CMObject if necessary
  2096.         
  2097.         if (id == kODNULL) {
  2098.             if ((object = CMNewObject(cmContainer)) == kODNULL)
  2099.                 THROW(kODErrBentoCannotNewObject);
  2100.                 
  2101.             id = _fIDList->Add(object);
  2102.         }        
  2103.  
  2104.         // Create the Storage Unit
  2105.         su = NewCMStorageUnit(somSelf->GetHeap(ev));
  2106.         su->InitStorageUnit(ev, somSelf, id);
  2107.         
  2108.     CATCH_ALL
  2109.         
  2110.         if (object != kODNULL)
  2111.             CMReleaseObject(object);
  2112.             
  2113.         if (su != kODNULL)
  2114.             delete su;
  2115.             
  2116.         if (ErrorCode() == kODErrBentoInvalidObject)
  2117.             THROW(kODErrInvalidID);
  2118.         else
  2119.             RERAISE;
  2120.             
  2121.     ENDTRY
  2122.     ODSessionRestoreCMAllocReserve(cmContainer);
  2123.  
  2124.     // Add Storage Unit to outstanding SU collection
  2125.     
  2126.     _fStorageUnits->ReplaceEntry(&id, &su);
  2127.     
  2128.     SOM_CATCH_ALL
  2129.         su = kODNULL;
  2130.     SOM_ENDTRY
  2131.  
  2132.     return su;
  2133. }
  2134.  
  2135. //------------------------------------------------------------------------------
  2136. // CMDraft: SetChangedFromPrevFlag
  2137. //------------------------------------------------------------------------------
  2138.  
  2139. SOM_Scope void  SOMLINK CMDraftSetChangedFromPrevFlag(CMDraft *somSelf, Environment *ev,
  2140.         ODBoolean changed)
  2141. {
  2142.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2143.     CMDraftMethodDebug("CMDraft","SetChangedFromPrevFlag");
  2144.  
  2145.     if (changed != kODFalse) {
  2146.         SOM_TRY
  2147.             somSelf->FailIfNotExclusiveWrite(ev);
  2148.         SOM_CATCH_ALL
  2149.         SOM_ENDTRY
  2150.     }
  2151.     _fChangedFromPrev = changed;
  2152. }
  2153.  
  2154. static void SetupForUpdatingDraft(Environment* ev,
  2155.                                         CMDocument* localDoc,
  2156.                                         ODVersionID prevVersionID,
  2157.                                         CMValue version)
  2158. {
  2159.     ODBentoContainer*    localContainer = (ODBentoContainer*) localDoc->GetContainer(ev);
  2160.     ODBentoContainer*    container = kODNULL;
  2161.     
  2162.     // check to see whether we need to do a update
  2163.     container = localContainer->GetTargetContainer(ev);
  2164.     
  2165.     if (container != kODNULL) {
  2166.         
  2167.         // get the target document
  2168.         CMDocument*        targetDoc = localContainer->GetTargetDocument(ev);
  2169.         
  2170.         // find its version list
  2171.         VersionList*    versionList = targetDoc->GetVersionList(ev);
  2172.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2173.     
  2174.         // get the latest draft
  2175.         ODDraftID    latestDraftID = versionList->GetLatestDraftID();
  2176.         
  2177.         // get the version id of the latest draft
  2178.         prevVersionID = versionList->GetDraft(latestDraftID);
  2179.     }
  2180.     else {
  2181.         container = localContainer;
  2182.     }
  2183.     // Note: getting/setting refcon's does not allocate memory in Bento:
  2184.     
  2185.     // get the name for indirection
  2186.     ODType prevVersionName = GetVersionNameFromVersionID(prevVersionID, localDoc->GetHeap(ev));
  2187.     
  2188.     // store name so that it can be passed to handler
  2189.     CMSetValueRefCon(version, prevVersionName);
  2190.  
  2191.     // get cmContainer so that we can assess CMSession
  2192.     CMContainer cmContainer = container->GetCMContainer(ev);
  2193.  
  2194.     // Save the outermost container for embedded container creation.
  2195.     ODSessionRefCon* sessionRefCon = (ODSessionRefCon*) CMGetSessionRefCon(cmContainer);
  2196.     sessionRefCon->container = container;
  2197. }
  2198.  
  2199. //------------------------------------------------------------------------------
  2200. // CMDraft: CreateVersion
  2201. //------------------------------------------------------------------------------
  2202.  
  2203. SOM_Scope void  SOMLINK CMDraftCreateVersion(CMDraft *somSelf, Environment *ev)
  2204. {
  2205.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2206.     CMDraftMethodDebug("CMDraft","CreateVersion");
  2207.     
  2208.     SOM_TRY
  2209.  
  2210.     CMContainer                cmContainer = ((ODBentoContainer*) _fDocument->GetContainer(ev))->GetCMContainer(ev);
  2211.     CMObject                versionObject = kODNULL;
  2212.     CMType                    versionNameType = kODNULL;
  2213.     ODType                    versionName = kODNULL;
  2214.     CMProperty                versionNameProperty = kODNULL;
  2215.     CMValue                    versionNameValue = kODNULL;
  2216.     CMType                    versionDataType = kODNULL;
  2217.     CMProperty                versionDataProperty = kODNULL;
  2218.     CMValue                    version = kODNULL;
  2219.     
  2220.     VersionList*            versionList = kODNULL;
  2221.  
  2222.     versionList = _fDocument->GetVersionList(ev);
  2223.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2224.  
  2225.     _fOrigTopVersionDraftID = versionList->GetSameVersionDraftID(_fID);
  2226.     _fPrevVersionID = versionList->GetCurrentVersion(_fID);
  2227.     _fVersionID = versionList->CreateVersion(_fID);
  2228.     
  2229.     ODSessionMustHaveCMAllocReserve(cmContainer);
  2230.  
  2231.     versionObject = CMNewObject(cmContainer);
  2232.     versionNameType = CMRegisterType(cmContainer, kODISOStr);
  2233.  
  2234.     versionName = GetVersionNameFromVersionID(_fVersionID, somSelf->GetHeap(ev));
  2235.     versionNameProperty = CMRegisterProperty(cmContainer, versionName);
  2236.     
  2237.     versionNameValue = CMNewValue(versionObject, versionNameProperty, versionNameType);
  2238.     CMWriteValueData(versionNameValue, "", 0, 1);
  2239.     
  2240.     versionDataType = CMRegisterType(cmContainer, kODEmbeddedContainerType);
  2241.     versionDataProperty = CMRegisterProperty(cmContainer, kODEmbeddedContainerProperty);
  2242.     version = CMNewValue(versionObject, versionDataProperty, versionDataType);
  2243.     if (version == kODNULL)
  2244.         THROW(kODErrCannotCreateDraftVersion);
  2245.     CMWriteValueData(version, "", 0, 0);                /* Make the container manager happy */
  2246.  
  2247.     ODSessionRestoreCMAllocReserve(cmContainer);
  2248.     
  2249.     SetupForUpdatingDraft(ev, _fDocument, _fPrevVersionID, version);
  2250.     
  2251. #ifdef ODDebug_CMDraft
  2252.     ODDocument* tempDoc = somSelf->GetDocument(ev);
  2253.     somPrintf("CreateVersion: CMDocument %x DraftID %d IsNewDraft %d versionID %d prevVersionID %d\n", tempDoc, somSelf->GetID(ev), somSelf->IsNewDraft(ev), _fVersionID, _fPrevVersionID);    
  2254. #endif
  2255.  
  2256.     ODEmbeddedContainerID    containerID;
  2257.     containerID.cmValue = version;
  2258.     containerID.shouldMerge = (somSelf->IsNewDraft(ev) ? kODFalse : kODTrue);
  2259.     ODByteArray*    ba = CreateByteArray(&containerID, sizeof(ODEmbeddedContainerID));
  2260.     _fEmbeddedContainer = (ODEmbeddedContainer*) 
  2261.             _fDocument->GetContainer(ev)->GetStorageSystem(ev)->CreateContainer(ev, kODBentoEmbeddedContainer, ba);
  2262.     DisposeByteArray(ba);
  2263.     
  2264.     if (versionName != kODNULL)
  2265.         ODDisposePtr(versionName);
  2266.  
  2267.     _fExternalized = kODFalse;
  2268.  
  2269.     somSelf->OpenCollections(ev);
  2270.     
  2271.     SOM_CATCH_ALL
  2272.     SOM_ENDTRY
  2273. }
  2274.  
  2275. //------------------------------------------------------------------------------
  2276. // CMDraft: OpenVersion
  2277. //------------------------------------------------------------------------------
  2278.  
  2279. SOM_Scope void  SOMLINK CMDraftOpenVersion(CMDraft *somSelf, Environment *ev)
  2280. {
  2281.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2282.     CMDraftMethodDebug("CMDraft","OpenVersion");
  2283.     
  2284.     SOM_TRY
  2285.  
  2286.     CMContainer                cmContainer = ((ODBentoContainer*) _fDocument->GetContainer(ev))->GetCMContainer(ev);
  2287.     ODType                    versionName = kODNULL;
  2288.     ODType                    oldVersionName = kODNULL;
  2289.     CMType                    versionDataType;
  2290.     CMProperty                versionDataProperty;
  2291.     CMProperty                versionNameProperty;
  2292.     CMObject                versionObject;
  2293.     CMValue                    version;
  2294.  
  2295.     VersionList*            versionList;
  2296.     
  2297.     versionList = _fDocument->GetVersionList(ev);
  2298.     ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2299.         
  2300.     _fVersionID = versionList->GetCurrentVersion(_fID);
  2301.     _fPrevVersionID = _fVersionID;
  2302.     if (_fVersionID == kODTombstonedVersion)
  2303.         THROW(kODErrDraftHasBeenDeleted);
  2304.     
  2305.     if (_fPermissions == kODDPReadOnly) {
  2306.         ODSessionMustHaveCMAllocReserve(cmContainer);
  2307.     
  2308.         MyDebugStr("**** OpenVersion: kODDPReadOnly.\n");
  2309.         versionDataType = CMRegisterType(cmContainer, kODEmbeddedContainerType);
  2310.         versionDataProperty = CMRegisterProperty(cmContainer, kODEmbeddedContainerProperty);
  2311.         
  2312.         versionName = GetVersionNameFromVersionID(_fVersionID, somSelf->GetHeap(ev));
  2313.         versionNameProperty = CMRegisterProperty(cmContainer, versionName);
  2314.         
  2315.         versionObject = CMGetNextObjectWithProperty(cmContainer, kODNULL, versionNameProperty);
  2316.         version = CMUseValue(versionObject, versionDataProperty, versionDataType);
  2317.     
  2318.         CMSetValueRefCon(version, kODNULL);
  2319.         
  2320.         // Save the outermost container for embedded container creation.
  2321.         ODSessionRefCon* sessionRefCon = (ODSessionRefCon*) CMGetSessionRefCon(cmContainer);
  2322.         sessionRefCon->container = _fDocument->GetContainer(ev);
  2323.     
  2324. #ifdef ODDebug_CMDraft
  2325.     ODDocument* tempDoc = somSelf->GetDocument(ev);
  2326.     somPrintf("OpenVersion: CMDocument %x DraftID %d IsNewDraft %d versionID %d prevVersionID %d\n", tempDoc, somSelf->GetID(ev), somSelf->IsNewDraft(ev), _fVersionID, _fPrevVersionID);    
  2327. #endif
  2328.         ODEmbeddedContainerID    containerID;
  2329.         containerID.cmValue = version;
  2330.         containerID.shouldMerge = kODFalse;
  2331.         ODByteArray*    ba = CreateByteArray(&containerID, sizeof(ODEmbeddedContainerID));
  2332.         _fEmbeddedContainer = (ODEmbeddedContainer*)
  2333.             _fDocument->GetContainer(ev)->GetStorageSystem(ev)->AcquireContainer(ev, kODBentoEmbeddedContainer, ba);
  2334.         DisposeByteArray(ba);
  2335.     
  2336.         if (versionName != kODNULL)
  2337.             ODDisposePtr(versionName);
  2338.         if (oldVersionName != kODNULL)
  2339.             ODDisposePtr(oldVersionName);
  2340.             
  2341.         ODSessionRestoreCMAllocReserve(cmContainer);
  2342.  
  2343.         somSelf->OpenCollections(ev);
  2344.     }
  2345.     else
  2346.         THROW(kODErrInvalidPermissions);
  2347.     
  2348.     SOM_CATCH_ALL
  2349.     SOM_ENDTRY
  2350. }
  2351.  
  2352. //------------------------------------------------------------------------------
  2353. // CMDraft: CloseVersion
  2354. //------------------------------------------------------------------------------
  2355.  
  2356. extern void ODBentoFatalError(ODBoolean allowSuppress); // SessHdr.cpp
  2357.  
  2358. SOM_Scope void  SOMLINK CMDraftCloseVersion(CMDraft *somSelf, Environment *ev)
  2359. {
  2360.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2361.     CMDraftMethodDebug("CMDraft","CloseVersion");
  2362.     
  2363.     SOM_TRY
  2364.  
  2365. #ifdef ODDebug_CMDraft
  2366.     ODDocument* tempDoc = somSelf->GetDocument(ev);
  2367.     somPrintf("CloseVersion: CMDocument %x DraftID %d versionID %d Permission %d\n", tempDoc, somSelf->GetID(ev), _fVersionID, _fPermissions);    
  2368. #endif
  2369.  
  2370.     if (_fPermissions == kODDPExclusiveWrite) {
  2371.         VersionList*    versionList = kODNULL;
  2372.  
  2373.         versionList = _fDocument->TestAndGetVersionList(ev);
  2374.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2375.     
  2376.         if (versionList->IsBelow(_fOrigTopVersionDraftID, versionList->GetSameVersionDraftID(_fID)))
  2377.             _fEmbeddedContainer->SetMergeFlag(ev, kODFalse);
  2378.         somSelf->CloseCollections(ev);
  2379.     }
  2380.     else {
  2381.         somSelf->DeleteCollections(ev);
  2382.         somSelf->CreateCollections(ev);
  2383.     }
  2384.     
  2385.     if (_fEmbeddedContainer != kODNULL) {
  2386.         // In order to prevent closing errors from being eaten silently inside
  2387.         // Release(), we are going to close the embedded container first.  This
  2388.         // is necessary so that closing errors will propagate up to
  2389.         // CMDraft::Close() (called from either CMDocument::ReleaseDraft() or
  2390.         // CMDocument::SaveToAPrevDraft()).  Otherwise, the bogus draft (with
  2391.         // an invalid Bento label) will be blessed by externalizing its id
  2392.         // in the new draft version list, which would corrupt the document.
  2393.         // Note that we have made sure that closing the embedded container a
  2394.         // second time in Release() is silently harmless.
  2395.         
  2396.         _fEmbeddedContainer->Close(ev);
  2397.         
  2398.         _fEmbeddedContainer->Release(ev);
  2399.         _fEmbeddedContainer = kODNULL;
  2400.     }
  2401.     
  2402.     _fIsNewDraft = kODFalse;
  2403.     
  2404.     SOM_CATCH_ALL
  2405.         
  2406.     ODBentoFatalError(/*allowSuppress*/ kODTrue);
  2407.         
  2408.     SOM_ENDTRY
  2409. }
  2410.  
  2411. //------------------------------------------------------------------------------
  2412. // CMDraft: DestroyVersion
  2413. //------------------------------------------------------------------------------
  2414.  
  2415. SOM_Scope void  SOMLINK CMDraftDestroyVersion(CMDraft *somSelf, Environment *ev)
  2416. {
  2417.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2418.     CMDraftMethodDebug("CMDraft","DestroyVersion");
  2419.     
  2420. #ifdef ODDebug_CMDraft
  2421.     ODDocument* tempDoc = somSelf->GetDocument(ev);
  2422.     somPrintf("Destroy Version: CMDocument %x DraftID %d versionID %d Permission %d\n", tempDoc, somSelf->GetID(ev), _fVersionID, _fPermissions);    
  2423. #endif
  2424.     
  2425.     if (_fPermissions == kODDPExclusiveWrite) {
  2426.         SOM_TRY
  2427.     
  2428.         somSelf->DeleteCollections(ev);
  2429.         somSelf->CreateCollections(ev);
  2430.     
  2431.         if (_fEmbeddedContainer != kODNULL) {
  2432.             _fEmbeddedContainer->Abort(ev);
  2433.             CMObject        parentObject = kODNULL;
  2434.             ODByteArray     ba = _fEmbeddedContainer->GetID(ev);
  2435.             CMValue parentValue = *((CMValue*) ba._buffer);
  2436.             ODDisposePtr(ba._buffer);
  2437.  
  2438.             CMContainer cmContainer = somSelf->GetCMContainer(ev);
  2439.             ODSessionMustHaveCMAllocReserve(cmContainer);
  2440.             
  2441.             CMGetValueInfo(parentValue, kODNULL, &parentObject,
  2442.                             kODNULL, kODNULL, kODNULL);
  2443.             CMDeleteValue(parentValue);
  2444.             CMDeleteObject(parentObject);
  2445.  
  2446.             ODSessionRestoreCMAllocReserve(cmContainer);
  2447.             
  2448.             _fEmbeddedContainer->Release(ev);
  2449.             _fEmbeddedContainer = kODNULL;
  2450.         }
  2451.         
  2452.         SOM_CATCH_ALL
  2453.         SOM_ENDTRY
  2454.     }
  2455. }
  2456.  
  2457. //------------------------------------------------------------------------------
  2458. // CMDraft: FlushVersion
  2459. //------------------------------------------------------------------------------
  2460.  
  2461. SOM_Scope void  SOMLINK CMDraftFlushVersion(CMDraft *somSelf, Environment *ev)
  2462. {
  2463.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2464.     CMDraftMethodDebug("CMDraft","FlushVersion");
  2465.  
  2466. }
  2467.  
  2468. //------------------------------------------------------------------------------
  2469. // CMDraft: Reinitialize
  2470. //------------------------------------------------------------------------------
  2471.  
  2472. SOM_Scope void  SOMLINK CMDraftReinitialize(CMDraft *somSelf, Environment *ev,
  2473.         ODDraftPermissions perms)
  2474. {
  2475.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2476.     CMDraftMethodDebug("CMDraft","Reinitialize");
  2477.     
  2478.     SOM_TRY
  2479.  
  2480.     if ((perms == kODDPExclusiveWrite) &&
  2481.         (_fEmbeddedContainer != kODNULL) &&
  2482.         (_fEmbeddedContainer->GetUseMode(ev) & kCMReading)) {
  2483.         MyDebugStr("Reinitialize.\n");
  2484.         THROW(kODErrInvalidPermissions);
  2485.     }
  2486.     
  2487.     // Close this version first
  2488.     
  2489.     // somSelf->CloseVersion(ev);
  2490.     
  2491.     // Set the permissions
  2492.     
  2493.     _fPermissions = perms;
  2494.  
  2495.     // Open or create a new version
  2496.  
  2497.     if (_fEmbeddedContainer == kODNULL) {
  2498. #if lazyOpen
  2499.         _fExternalized = kODFalse;
  2500. #else
  2501.         if (_fPermissions == kODDPReadOnly)
  2502.             somSelf->OpenVersion(ev);
  2503.         else
  2504.             somSelf->CreateVersion(ev);
  2505. #endif
  2506.     }
  2507.     
  2508.     //_fDocument->Reopen(ev);
  2509.     
  2510.     SOM_CATCH_ALL
  2511.     SOM_ENDTRY
  2512. }
  2513.  
  2514. //------------------------------------------------------------------------------
  2515. // CMDraft: Open
  2516. //------------------------------------------------------------------------------
  2517.  
  2518. SOM_Scope void  SOMLINK CMDraftOpen(CMDraft *somSelf, Environment *ev)
  2519. {
  2520.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2521.     CMDraftMethodDebug("CMDraft","Open");
  2522.  
  2523.     SOM_TRY
  2524.  
  2525.     if (_fEmbeddedContainer == kODNULL) {
  2526. #if lazyOpen
  2527.         _fExternalized = kODFalse;
  2528. #else
  2529.         if (_fPermissions == kODDPReadOnly)
  2530.             somSelf->OpenVersion(ev);
  2531.         else
  2532.             somSelf->CreateVersion(ev);
  2533. #endif
  2534.     }
  2535.  
  2536.     SOM_CATCH_ALL
  2537.     SOM_ENDTRY
  2538. }
  2539.  
  2540. #pragma segment CMDraft2
  2541.  
  2542. //------------------------------------------------------------------------------
  2543. // CMDraft: Close
  2544. //------------------------------------------------------------------------------
  2545.  
  2546. SOM_Scope void  SOMLINK CMDraftClose(CMDraft *somSelf, Environment *ev)
  2547. {
  2548.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2549.     CMDraftMethodDebug("CMDraft","Close");
  2550.  
  2551.     SOM_TRY
  2552.  
  2553. #if ODDebug_Drafts
  2554.     somPrintf("CMDraftClose: %d\n", somSelf->GetID(ev));
  2555. #endif
  2556.  
  2557. #if lazyOpen
  2558.     if (_fEmbeddedContainer != kODNULL) {
  2559.  
  2560.         CMContainer cmContainer = somSelf->GetCMContainer(ev);
  2561.         ODSessionMustHaveCMAllocReserve(cmContainer);
  2562.         // AcquireDraftPropertiesObject() makes CM calls:
  2563.  
  2564.         CMObject draftPropertiesObject = AcquireDraftPropertiesObject(somSelf->GetCMContainer(ev));
  2565.         if (draftPropertiesObject == kODNULL)
  2566.             THROW(kODErrNoDraftProperties);
  2567.         
  2568.         CMKeepObject(draftPropertiesObject);
  2569.         
  2570.         ODSessionRestoreCMAllocReserve(cmContainer);
  2571.         
  2572.         somSelf->CloseVersion(ev);
  2573.     }
  2574. #else
  2575.     somSelf->CloseVersion(ev);
  2576. #endif
  2577.  
  2578.     SOM_CATCH_ALL
  2579.     SOM_ENDTRY
  2580. }
  2581.  
  2582. //------------------------------------------------------------------------------
  2583. // CMDraft: Abort
  2584. //------------------------------------------------------------------------------
  2585.  
  2586. SOM_Scope void  SOMLINK CMDraftAbort(CMDraft *somSelf, Environment *ev)
  2587. {
  2588.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2589.     CMDraftMethodDebug("CMDraft","Abort");
  2590.  
  2591.     SOM_TRY
  2592.  
  2593.     if (_fPermissions == kODDPReadOnly)
  2594.         THROW(kODErrInvalidPermissions);
  2595.  
  2596.     if (_fDraftProperties != kODNULL) {
  2597.         _fDraftProperties->Release(ev);
  2598.         _fDraftProperties = kODNULL;
  2599.     }
  2600.  
  2601. #if TestFlushContainer
  2602.     if (_fRemoveChangeOnAbort) {
  2603.         VersionList*    versionList = kODNULL;
  2604.         
  2605.         versionList = _fDocument->TestAndGetVersionList(ev);
  2606.         ASSERT((versionList != kODNULL), kODErrDraftDoesNotExist);
  2607.     
  2608.         TRY
  2609.             if (versionList->Exists(_fID) != kODFalse)
  2610.                 versionList->RemoveChanges(_fID);
  2611.             
  2612.         CATCH_ALL
  2613.         
  2614.             _fDocument->ReleaseVersionList(ev);
  2615.             RERAISE;
  2616.     
  2617.         ENDTRY
  2618.     }
  2619. #else
  2620.     _fDocument->InternalizeVersionList(ev);
  2621. #endif
  2622.     somSelf->DestroyVersion(ev);
  2623.     //    _fDocument->Reopen(ev);
  2624.     
  2625.     SOM_CATCH_ALL
  2626.     SOM_ENDTRY
  2627. }
  2628.  
  2629. //------------------------------------------------------------------------------
  2630. // CMDraft: Flush
  2631. //------------------------------------------------------------------------------
  2632.  
  2633. SOM_Scope void  SOMLINK CMDraftFlush(CMDraft *somSelf, Environment *ev)
  2634. {
  2635.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2636.     CMDraftMethodDebug("CMDraft","Flush");
  2637.  
  2638.     if (_fPermissions == kODDPExclusiveWrite) {
  2639.         SOM_TRY
  2640.             somSelf->FlushVersion(ev);
  2641.         SOM_CATCH_ALL
  2642.         SOM_ENDTRY
  2643.     }
  2644. }
  2645.  
  2646.  
  2647. //------------------------------------------------------------------------------
  2648. // CMDraft: IsNewDraft
  2649. //------------------------------------------------------------------------------
  2650.  
  2651. SOM_Scope ODBoolean  SOMLINK CMDraftIsNewDraft(CMDraft *somSelf, Environment *ev)
  2652. {
  2653.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2654.     CMDraftMethodDebug("CMDraft","IsNewDraft");
  2655.  
  2656.     return _fIsNewDraft;
  2657. }
  2658.  
  2659. //------------------------------------------------------------------------------
  2660. // CMDraft: GetEmbeddedContainer
  2661. //------------------------------------------------------------------------------
  2662.  
  2663. SOM_Scope ODEmbeddedContainer*  SOMLINK CMDraftGetEmbeddedContainer(CMDraft *somSelf, Environment *ev)
  2664. {
  2665.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2666.     CMDraftMethodDebug("CMDraft","GetEmbeddedContainer");
  2667.  
  2668. #if lazyOpen
  2669.     SOM_TRY
  2670.     if (_fEmbeddedContainer == kODNULL) {
  2671.         if (_fPermissions == kODDPReadOnly)
  2672.             somSelf->OpenVersion(ev);
  2673.         else
  2674.             somSelf->CreateVersion(ev);
  2675.     }
  2676.     SOM_CATCH_ALL
  2677.     SOM_ENDTRY
  2678. #endif
  2679.  
  2680.     return _fEmbeddedContainer;
  2681. }
  2682.  
  2683. //------------------------------------------------------------------------------
  2684. // CMDraft: GetCMContainer
  2685. //------------------------------------------------------------------------------
  2686.  
  2687. SOM_Scope CMContainer  SOMLINK CMDraftGetCMContainer(CMDraft *somSelf, Environment *ev)
  2688. {
  2689.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2690.     CMDraftMethodDebug("CMDraft","GetCMContainer");
  2691.     
  2692.     SOM_TRY
  2693.  
  2694. #if lazyOpen
  2695.     if (_fEmbeddedContainer == kODNULL) {
  2696.         if (_fPermissions == kODDPReadOnly)
  2697.             somSelf->OpenVersion(ev);
  2698.         else
  2699.             somSelf->CreateVersion(ev);
  2700.     }
  2701. #endif
  2702.  
  2703.     if (_fEmbeddedContainer == kODNULL)
  2704.         THROW(kODErrCannotGetDraftVersion);
  2705.     return _fEmbeddedContainer->GetCMContainer(ev);
  2706.     
  2707.     SOM_CATCH_ALL
  2708.     SOM_ENDTRY
  2709.     return kODNULL;
  2710. }
  2711.  
  2712. //------------------------------------------------------------------------------
  2713. // AcquireDraftPropertiesObject
  2714. //------------------------------------------------------------------------------
  2715.  
  2716. // Callers must ODSessionMustHaveCMAllocReserve() first:
  2717.  
  2718. static CMObject AcquireDraftPropertiesObject(CMContainer container)
  2719. {
  2720.     CMObject        draftPropertiesObject = kODNULL;
  2721.     CMType            rootSUType;
  2722.     CMProperty        rootSUProp;
  2723.     CMValue            rootSU;
  2724.     
  2725.     CMContainerModeFlags    openMode;
  2726.  
  2727.     if ((rootSUType = CMRegisterType(container, kODStorageUnitType)) == kODNULL)
  2728.         THROW(kODErrBentoInvalidType);
  2729.     if ((rootSUProp = CMRegisterProperty(container, kODPropRootSU)) == kODNULL)
  2730.         THROW(kODErrBentoInvalidProperty);
  2731.     draftPropertiesObject = CMGetNextObjectWithProperty(container, kODNULL, rootSUProp);
  2732.     
  2733.     if (draftPropertiesObject == kODNULL) {
  2734.         
  2735.         CMGetContainerInfo(container, kODNULL, kODNULL, kODNULL, kODNULL, &openMode);
  2736.         if (openMode == kCMReading)
  2737.             return kODNULL;
  2738.         
  2739.         draftPropertiesObject = CMNewObject(container);
  2740.  
  2741.         if ((rootSU = CMNewValue(draftPropertiesObject, rootSUProp, rootSUType)) == kODNULL)
  2742.             THROW(kODErrBentoCannotNewValue);
  2743.         CMWriteValueData(rootSU, "", 0, 0);
  2744.     }
  2745.     
  2746.     return draftPropertiesObject;
  2747. }
  2748.  
  2749. //------------------------------------------------------------------------------
  2750. // GetVersionNameFromVersionID
  2751. //------------------------------------------------------------------------------
  2752.  
  2753. static ODType GetVersionNameFromVersionID(ODVersionID id, ODMemoryHeapID heapID)
  2754. {
  2755.     ODSByte*    versionName = kODNULL;
  2756.     ODSByte    cString[kMaxStringSize];
  2757.         
  2758.     if (id != 0) {
  2759.         itoa(id, cString);
  2760.         versionName = (ODSByte*) ODNewPtr(strlen(kODVersionNamePrefix) + strlen(cString) + 1, heapID);
  2761.         strcpy(versionName, kODVersionNamePrefix);
  2762.         strcat(versionName, cString);
  2763.     }
  2764.     return versionName;
  2765. }
  2766.  
  2767. //------------------------------------------------------------------------------
  2768. // CMDraft: RetrievePersistentObject
  2769. //------------------------------------------------------------------------------
  2770.  
  2771. SOM_Scope ODPersistentObject*  SOMLINK CMDraftRetrievePersistentObject(CMDraft *somSelf, Environment *ev,
  2772.         ODStorageUnitID id)
  2773. {
  2774.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2775.     CMDraftMethodDebug("CMDraft","RetrievePersistentObject");
  2776.  
  2777.     ODPersistentObject*    object = kODNULL;
  2778.     
  2779.     SOM_TRY
  2780.     
  2781.     if (_fPersistentObjects->GetValue(&id, &object))
  2782.         object->Acquire(ev);
  2783.     
  2784.     SOM_CATCH_ALL
  2785.     SOM_ENDTRY
  2786.     return object;
  2787. }
  2788.  
  2789. //------------------------------------------------------------------------------
  2790. // CMDraft: ReleasePersistentObject
  2791. //------------------------------------------------------------------------------
  2792.  
  2793. SOM_Scope void  SOMLINK CMDraftReleasePersistentObject(CMDraft *somSelf, Environment *ev,
  2794.         ODPersistentObject* object)
  2795. {
  2796. //  CMDraftData *somThis = CMDraftGetData(somSelf);
  2797.     CMDraftMethodDebug("CMDraft","ReleasePersistentObject");
  2798.     
  2799.     SOM_TRY
  2800.     
  2801.     if (object->GetRefCount(ev) != 0)
  2802.         THROW(kODErrRefCountGreaterThanZero);
  2803.     
  2804.     SOM_CATCH_ALL
  2805.     SOM_ENDTRY
  2806. }
  2807.  
  2808. //------------------------------------------------------------------------------
  2809. // CMDraft: RemovePersistentObject
  2810. //------------------------------------------------------------------------------
  2811.  
  2812. SOM_Scope void  SOMLINK CMDraftRemovePersistentObject(CMDraft *somSelf, Environment *ev,
  2813.         ODPersistentObject* object)
  2814. {
  2815.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2816.     CMDraftMethodDebug("CMDraft","RemovePersistentObject");
  2817.     
  2818.     SOM_TRY
  2819.  
  2820.     ODStorageUnit*        su = object->GetStorageUnit(ev);
  2821.     ODStorageUnitID        id = object->GetID(ev);
  2822.     CMObject            cmObject = kODNULL;
  2823.     
  2824.     if (id == kODNULLID)
  2825.         THROW(kODErrInvalidPersistentObjectID);
  2826.         
  2827.     object->Release(ev);
  2828.  
  2829.     if (object->GetRefCount(ev) != 0)
  2830.         THROW(kODErrRefCountGreaterThanZero);
  2831.  
  2832.     if ((su != kODNULL) && (su->GetRefCount(ev) != 1))
  2833.         THROW(kODErrRefCountNotEqualOne);
  2834.  
  2835.     object->ReleaseAll(ev);
  2836.  
  2837.     _fPersistentObjects->RemoveEntry(&id);
  2838.     delete object;
  2839.     
  2840.     _fStorageUnits->RemoveEntry(&id);
  2841.     delete su;
  2842.  
  2843.     if (_fIDList->Exists(id) != kODFalse) {
  2844.         cmObject = (CMObject) _fIDList->Get(id);
  2845.         _fIDList->Remove(id);
  2846.  
  2847.         CMContainer cmContainer = somSelf->GetCMContainer(ev);
  2848.         ODSessionMustHaveCMAllocReserve(cmContainer);
  2849.  
  2850.         if (cmObject != kODNULL)
  2851.             CMDeleteObject(cmObject);
  2852.  
  2853.         ODSessionRestoreCMAllocReserve(cmContainer);
  2854.     }
  2855.  
  2856.     somSelf->SetChangedFromPrevFlag(ev, kODTrue);
  2857.     
  2858.     SOM_CATCH_ALL
  2859.     SOM_ENDTRY
  2860. }
  2861.  
  2862. //------------------------------------------------------------------------------
  2863. // CMDraft: CreateCollections
  2864. //------------------------------------------------------------------------------
  2865.  
  2866. SOM_Scope void  SOMLINK CMDraftCreateCollections(CMDraft *somSelf, Environment *ev)
  2867. {
  2868.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2869.     CMDraftMethodDebug("CMDraft","CreateCollections");
  2870.     
  2871.     SOM_TRY
  2872.  
  2873.     ODMemoryHeapID heap = somSelf->GetHeap(ev);
  2874.  
  2875.     _fPersistentObjects = new(heap) 
  2876.         OpenHashTable(OpenHashTable::StdEqual,
  2877.                       OpenHashTable::StdHash, heap);
  2878.     _fPersistentObjects->Initialize(kODInitialNumEntries,
  2879.                                     sizeof(ODStorageUnitID),
  2880.                                     sizeof(ODPersistentObject*));
  2881.  
  2882.     _fStorageUnits = new(heap) 
  2883.         OpenHashTable(OpenHashTable::StdEqual,
  2884.                       OpenHashTable::StdHash, heap);
  2885.     _fStorageUnits->Initialize(kODInitialNumEntries,
  2886.                                sizeof(ODStorageUnitID),
  2887.                                sizeof(ODStorageUnit*));
  2888.  
  2889.     _fIDList = new(somSelf->GetHeap(ev)) IDList;
  2890.     _fIDList->Initialize();
  2891.     
  2892.     SOM_CATCH_ALL
  2893.     SOM_ENDTRY
  2894. }
  2895.  
  2896. //------------------------------------------------------------------------------
  2897. // CMDraft: DeleteCollections
  2898. //------------------------------------------------------------------------------
  2899.  
  2900. SOM_Scope void  SOMLINK CMDraftDeleteCollections(CMDraft *somSelf, Environment *ev)
  2901. {
  2902.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2903.     CMDraftMethodDebug("CMDraft","DeleteCollections");
  2904.     
  2905.     SOM_TRY
  2906.  
  2907.     if (_fDraftProperties != kODNULL)
  2908.     {
  2909.         _fDraftProperties->Release(ev);
  2910.         _fDraftProperties = kODNULL;
  2911.     }
  2912.     if (_fPersistentObjects != kODNULL) {
  2913.         ODStorageUnitID        id;
  2914.         ODPersistentObject*    object;
  2915.         OpenHashTableIterator    iter(_fPersistentObjects);
  2916.         
  2917.         for (iter.First(&id, &object); iter.IsNotComplete(); iter.Next(&id, &object)) {
  2918.             if (object != kODNULL) {
  2919.                 SOM_TRY
  2920.                     object->ReleaseAll(ev);
  2921.                 SOM_CATCH_ALL
  2922.                     WARN("Exception thrown by object %x ID %x error %d\n", object, object->GetID(ev), ErrorCode());
  2923.                 SOM_ENDTRY
  2924.             }
  2925.         }
  2926.         
  2927.         for (iter.First(&id, &object); iter.IsNotComplete(); iter.Next(&id, &object)) {
  2928.             if (object != kODNULL) {
  2929.                 delete object;
  2930.             }
  2931.         }
  2932.         delete _fPersistentObjects;
  2933.         _fPersistentObjects = kODNULL;
  2934.     }
  2935.  
  2936.     if (_fStorageUnits != kODNULL) {
  2937.         ODStorageUnitID        id;
  2938.         ODStorageUnit*            su;
  2939.         OpenHashTableIterator    iter(_fStorageUnits);
  2940.         for (iter.First(&id, &su); iter.IsNotComplete(); iter.Next(&id, &su)) {
  2941.             if (su != kODNULL) {
  2942.                 delete su;
  2943.             }
  2944.         }
  2945.         delete _fStorageUnits;
  2946.         _fStorageUnits = kODNULL;
  2947.         _fDraftProperties = kODNULL;
  2948.     }
  2949.     
  2950.     ODDeleteObject(_fIDList);
  2951.     
  2952.     SOM_CATCH_ALL
  2953.     SOM_ENDTRY
  2954. }
  2955.  
  2956. //------------------------------------------------------------------------------
  2957. // CMDraft: ExternalizeCollections
  2958. //------------------------------------------------------------------------------
  2959.  
  2960. SOM_Scope void  SOMLINK CMDraftExternalizeCollections(CMDraft *somSelf, Environment *ev)
  2961. {
  2962.     CMDraftData *somThis = CMDraftGetData(somSelf);
  2963.     CMDraftMethodDebug("CMDraft","ExternalizeCollections");
  2964.     
  2965.     SOM_TRY
  2966.  
  2967.     ODID                    id;
  2968.     ODStorageUnit*            su;
  2969.  
  2970.     OpenHashTableIterator    persistentObjects(_fPersistentObjects);
  2971.     ODPersistentObject*    object;
  2972.     
  2973.     for (persistentObjects.First(&id, &object);
  2974.             persistentObjects.IsNotComplete();
  2975.             persistentObjects.Next(&id, &object)) {
  2976.         // Temporarily bump the refcount to make sure that the object is
  2977.         // in a valid state.
  2978.         object->Acquire(ev);
  2979.         TempODRefCntObject tempObject = object; // ensure it's released
  2980.         su = object->GetStorageUnit(ev);
  2981.         if ((su != kODNULL) && (su->Exists(ev, kODNULL, kODNULL, 0) != kODFalse))
  2982.         object->Externalize(ev);
  2983.     }
  2984.  
  2985.     OpenHashTable            suCollection(*_fStorageUnits);
  2986.     suCollection.InitAndCopyFrom(*_fStorageUnits);
  2987.     OpenHashTableIterator    storageUnits(&suCollection);
  2988.  
  2989.     for (storageUnits.First(&id, &su);
  2990.             storageUnits.IsNotComplete();
  2991.             storageUnits.Next(&id, &su)) {
  2992.         // Temporarily bump the refcount to make sure that the object is
  2993.         // in a valid state.
  2994.         su->Acquire(ev);
  2995.         TempODStorageUnit tempSU = su; // ensure it's released
  2996.         if (su->Exists(ev, kODNULL, kODNULL, 0) != kODFalse)
  2997.             su->Externalize(ev);
  2998.     }
  2999.     
  3000.     SOM_CATCH_ALL
  3001.     SOM_ENDTRY
  3002. }
  3003.  
  3004. //------------------------------------------------------------------------------
  3005. // CMDraft: CloseCollections
  3006. //------------------------------------------------------------------------------
  3007.  
  3008. SOM_Scope void  SOMLINK CMDraftCloseCollections(CMDraft *somSelf, Environment *ev)
  3009. {
  3010.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3011.     CMDraftMethodDebug("CMDraft","CloseCollections");
  3012.     
  3013.     SOM_TRY
  3014.     
  3015.     somSelf->FailIfNotExclusiveWrite(ev);
  3016.     
  3017.     somSelf->Purge(ev, 0);
  3018.     PurgeAllStorageUnits(ev, _fStorageUnits, _fIDList); // purge SU, relase CMObjects
  3019.     
  3020.     SOM_CATCH_ALL
  3021.     SOM_ENDTRY
  3022. }
  3023.  
  3024. //------------------------------------------------------------------------------
  3025. // CMDraft: OpenCollections
  3026. //------------------------------------------------------------------------------
  3027.  
  3028. SOM_Scope void  SOMLINK CMDraftOpenCollections(CMDraft *somSelf, Environment *ev)
  3029. {
  3030.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3031.     CMDraftMethodDebug("CMDraft","OpenCollections");
  3032.     
  3033.     SOM_TRY
  3034.  
  3035.     OpenHashTableIterator    storageUnits(_fStorageUnits);
  3036.     
  3037.     ODID                    id;
  3038.     ODStorageUnit*            su;
  3039.  
  3040.     for (storageUnits.First(&id, &su);
  3041.             storageUnits.IsNotComplete();
  3042.             storageUnits.Next(&id, &su)) {
  3043.         su->Internalize(ev);
  3044.     }
  3045.     
  3046.     SOM_CATCH_ALL
  3047.     SOM_ENDTRY
  3048. }
  3049.  
  3050. //------------------------------------------------------------------------------
  3051. // CMDraft: AreEmptyCollections
  3052. //------------------------------------------------------------------------------
  3053.  
  3054. SOM_Scope ODBoolean  SOMLINK CMDraftAreEmptyCollections(CMDraft *somSelf, Environment *ev)
  3055. {
  3056.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3057.     CMDraftMethodDebug("CMDraft","AreEmptyCollections");
  3058.     
  3059.     SOM_TRY
  3060.  
  3061.     OpenHashTableIterator    storageUnits(_fStorageUnits);
  3062.     OpenHashTableIterator    persistentObjects(_fPersistentObjects);
  3063.     ODID                    id;
  3064.     ODPersistentObject*    object;
  3065.     ODStorageUnit*            su;
  3066.     
  3067.     for (persistentObjects.First(&id, &object);
  3068.             persistentObjects.IsNotComplete();
  3069.             persistentObjects.Next(&id, &object)) {
  3070.         if (object->GetRefCount(ev) > 0)
  3071.             return kODFalse;
  3072.     }
  3073.  
  3074.     for (storageUnits.First(&id, &su); storageUnits.IsNotComplete(); storageUnits.Next(&id, &su)) {
  3075.         if (su->GetRefCount(ev) > 0)
  3076.             return kODFalse;
  3077.     }
  3078.     
  3079.     SOM_CATCH_ALL
  3080.     SOM_ENDTRY
  3081.         
  3082.     return kODTrue;
  3083. }
  3084.  
  3085. //------------------------------------------------------------------------------
  3086. // CMDraft: NeedExternalizing
  3087. //------------------------------------------------------------------------------
  3088.  
  3089. SOM_Scope ODBoolean  SOMLINK CMDraftNeedExternalizing(CMDraft *somSelf, Environment *ev)
  3090. {
  3091.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3092.     CMDraftMethodDebug("CMDraft","NeedExternalizing");
  3093.  
  3094.     return _fExternalized;
  3095. }
  3096.  
  3097.  
  3098. //------------------------------------------------------------------------------
  3099. // CMDraft: GetIDList
  3100. //------------------------------------------------------------------------------
  3101.  
  3102. SOM_Scope IDList*  SOMLINK CMDraftGetIDList(CMDraft *somSelf, Environment *ev)
  3103. {
  3104.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3105.     CMDraftMethodDebug("CMDraft","GetIDList");
  3106.  
  3107.     return _fIDList;
  3108. }
  3109.  
  3110. //------------------------------------------------------------------------------
  3111. // CMDraft: IsChangedFromPrev
  3112. //------------------------------------------------------------------------------
  3113.  
  3114. SOM_Scope ODBoolean  SOMLINK CMDraftIsChangedFromPrev(CMDraft *somSelf, Environment *ev,
  3115.         VersionList* versionList)
  3116. {
  3117.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3118.     CMDraftMethodDebug("CMDraft","IsChangedFromPrev");
  3119.  
  3120.     ODBoolean        changedFromPrev = kODFalse;
  3121.     ODVersionID    prevVersionID;
  3122.     ODDraftID        prevDraftID;
  3123.     
  3124.     // If this draft has been modified, return kODTrue.
  3125.     
  3126.     if (_fChangedFromPrev != kODFalse)
  3127.         return kODTrue;
  3128.  
  3129.     // versionList->ChangedFromPrev is accurate only when the draft is
  3130.     // opened read-only. Therefore, additional check is needed to ensure that
  3131.     // we don't return kODTrue even when the draft has not be changed.
  3132.  
  3133.     SOM_TRY
  3134.         changedFromPrev = versionList->ChangedFromPrev(_fID);
  3135.         
  3136.         if ((changedFromPrev != kODFalse) && (_fPermissions == kODDPExclusiveWrite)) {
  3137.             prevDraftID = versionList->GetPreviousDraftID(_fID);
  3138.             prevVersionID = versionList->GetDraft(prevDraftID);
  3139.             if (prevVersionID == _fPrevVersionID)
  3140.                 changedFromPrev = kODFalse;
  3141.         }
  3142.     SOM_CATCH_ALL
  3143.     SOM_ENDTRY
  3144.     
  3145.     return changedFromPrev;
  3146. }
  3147.  
  3148. //------------------------------------------------------------------------------
  3149. // CMDraft: BeginClone
  3150. //------------------------------------------------------------------------------
  3151.  
  3152. SOM_Scope ODDraftKey  SOMLINK CMDraftBeginClone(CMDraft *somSelf, Environment *ev,
  3153.         ODDraft* destDraft,
  3154.         ODFrame* destFrame,
  3155.         ODCloneKind kind)
  3156. {
  3157.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3158.     CMDraftMethodDebug("CMDraft","BeginClone");
  3159.  
  3160.     OpenHashTable* clonedSUIDs = kODNULL;        ODVolatile(clonedSUIDs);
  3161.     OpenHashTable* weakClonedSUIDs = kODNULL;    ODVolatile(weakClonedSUIDs);
  3162.     OpenHashTable* linksToCloneSUIDs = kODNULL;    ODVolatile(linksToCloneSUIDs);
  3163.  
  3164.     ODDraftKey result = 0;
  3165.  
  3166.     SOM_TRY
  3167.  
  3168.         // Allow beginning a new clone into a link if a clone from a link
  3169.         // is in progress; common if the link contains promises
  3170.         if ( (kind == kODCloneToLink) && (_fCloneKind == kODCloneFromLink) )
  3171.         {
  3172.             if ( _fLockCount > 1 )
  3173.                 THROW(kODErrCloningInProgress);
  3174.         }
  3175.         else if (_fLockCount > 0)
  3176.             THROW(kODErrCloningInProgress);
  3177.  
  3178. #ifdef DebugClone
  3179.         somPrintf("\nCMDraft::BeginClone - ");
  3180.         switch (kind)
  3181.         {
  3182.         case kODCloneCut:        somPrintf("Cut\n"); break;
  3183.         case kODCloneCopy:        somPrintf("Copy\n"); break;
  3184.         case kODClonePaste:        somPrintf("Paste\n"); break;
  3185.         case kODCloneDropCopy:    somPrintf("Drop Copy\n"); break;
  3186.         case kODCloneDropMove:    somPrintf("Drop Move\n"); break;
  3187.         case kODCloneToLink:    somPrintf("To Link\n"); break;
  3188.         case kODCloneFromLink:    somPrintf("From Link\n"); break;
  3189.         case kODCloneAll:        somPrintf("All\n"); break;
  3190.         case kODCloneToFile:    somPrintf("To File\n"); break;
  3191.         default:                somPrintf("Invalid clone kind!\n"); break;
  3192.         }
  3193. #endif
  3194.  
  3195.         // Validate the clone kind parameter
  3196.         switch (kind)
  3197.         {
  3198.         case kODClonePaste:
  3199.         case kODCloneDropCopy:
  3200.         case kODCloneDropMove:
  3201.         case kODCloneToFile:
  3202.             {
  3203.             ODCloneKind origCloneKind = GetOriginalCloneKind(ev, somSelf);
  3204.             if ( (origCloneKind != kODCloneCut) && (origCloneKind != kODCloneCopy) )
  3205.                 THROW(kODErrInconsistentCloneKind);
  3206.             }
  3207.             if ( somSelf == destDraft )
  3208.                 THROW(kODErrInvalidDestinationDraft);
  3209.             break;
  3210.     
  3211.         case kODCloneCut:
  3212.         case kODCloneCopy:
  3213.             if ( somSelf == destDraft )
  3214.                 THROW(kODErrInvalidDestinationDraft);
  3215.             break;
  3216.     
  3217.         case kODCloneToLink:
  3218.         case kODCloneFromLink:
  3219.             if ( somSelf != destDraft )
  3220.                 THROW(kODErrInvalidDestinationDraft);
  3221.             break;
  3222.     
  3223.         case kODCloneAll:
  3224.             break;
  3225.     
  3226.         default:
  3227.             THROW(kODErrInvalidCloneKind);
  3228.             break;
  3229.         }
  3230.     
  3231.         ODMemoryHeapID heap = somSelf->GetHeap(ev);
  3232.  
  3233.         // Ensure both hash tables can be allocated
  3234.         if ( _fLockCount == 0 )
  3235.         {
  3236.             clonedSUIDs = new(heap) 
  3237.                 OpenHashTable(OpenHashTable::StdEqual,
  3238.                               OpenHashTable::StdHash, heap);
  3239.             clonedSUIDs->Initialize(kInitialHashTableEntries,
  3240.                                       sizeof(ODStorageUnitID),
  3241.                                       sizeof(ODStorageUnitID));
  3242.             
  3243.             if ( (kind == kODCloneCut) || (kind == kODCloneCopy) )
  3244.                 ReadClonedObjectTable(ev, clonedSUIDs, destDraft);
  3245.  
  3246.             if ( (kind == kODCloneDropCopy) ||
  3247.                  (kind == kODCloneDropMove) ||
  3248.                  (kind == kODClonePaste)    ||
  3249.                  (kind == kODCloneToFile) )
  3250.             {
  3251.                 if ( GetOriginalDraft(ev, somSelf) == kODNULL )
  3252.                 {
  3253.                     // Clone is from a document draft to a document draft,
  3254.                     // so create the table for deferred strong clones
  3255.                     linksToCloneSUIDs = new(heap) 
  3256.                         OpenHashTable(OpenHashTable::StdEqual,
  3257.                                       OpenHashTable::StdHash, heap);
  3258.                     linksToCloneSUIDs->Initialize(kInitialHashTableEntries,
  3259.                                               sizeof(ODStorageUnitID),
  3260.                                               sizeof(ODStorageUnitID));
  3261.                 }
  3262.             }
  3263.         }
  3264.  
  3265.         weakClonedSUIDs = new(heap) 
  3266.             OpenHashTable(OpenHashTable::StdEqual,
  3267.                           OpenHashTable::StdHash, heap);
  3268.         weakClonedSUIDs->Initialize(kInitialHashTableEntries,
  3269.                                       sizeof(ODStorageUnitID),
  3270.                                       sizeof(ODStorageUnitID));
  3271.  
  3272.         // BeginClone must not fail beyond this point
  3273.  
  3274.         _fLockCount++;
  3275.     
  3276.         if ( _fLockCount == 1 )
  3277.         {
  3278.             _fCurrentKey++;
  3279.             _fCloneKind = kind;
  3280.             _fDestDraft = destDraft;
  3281.             _fDestFrame = destFrame;
  3282.             
  3283.             _fAnyFrameCloned = kODFalse;
  3284.             _fRootPartReused = kODFalse;
  3285.         
  3286.             _fClonedSUIDs = clonedSUIDs;
  3287.             _fLinksToCloneSUIDs = linksToCloneSUIDs;
  3288.         }
  3289.     
  3290.         _fSavedWeakClonedSUIDs = _fWeakClonedSUIDs;
  3291.         _fWeakClonedSUIDs = weakClonedSUIDs;
  3292.         
  3293.         result = _fCurrentKey;
  3294.  
  3295.     SOM_CATCH_ALL
  3296.     
  3297.         ODDeleteObject(clonedSUIDs);
  3298.         ODDeleteObject(linksToCloneSUIDs);
  3299.         ODDeleteObject(weakClonedSUIDs);
  3300.  
  3301.     SOM_ENDTRY
  3302.     
  3303.     return result;
  3304. }
  3305.  
  3306. //------------------------------------------------------------------------------
  3307. // CMDraft: GetClonedSUIDs
  3308. //------------------------------------------------------------------------------
  3309.  
  3310. SOM_Scope OpenHashTable*  SOMLINK CMDraftGetClonedSUIDs(CMDraft *somSelf, Environment *ev,
  3311.         ODDraft* destDraft)
  3312. {
  3313.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3314.     CMDraftMethodDebug("CMDraft","GetClonedSUIDs");
  3315.  
  3316.     if ((_fDestDraft != kODNULL) && (_fDestDraft != destDraft)) {
  3317.         ODDeleteObject(_fClonedSUIDs);
  3318.         ODDeleteObject(_fWeakClonedSUIDs);
  3319.         ODSetSOMException(ev,kODErrInvalidDestinationDraft);
  3320.         return kODNULL;
  3321.     }
  3322.     _fDestDraft = destDraft;
  3323.     
  3324.     return _fClonedSUIDs;    
  3325. }
  3326.  
  3327. //------------------------------------------------------------------------------
  3328. // CMDraft: EndClone
  3329. //------------------------------------------------------------------------------
  3330.  
  3331. SOM_Scope void  SOMLINK CMDraftEndClone(CMDraft *somSelf, Environment *ev,
  3332.         ODDraftKey key)
  3333. {
  3334.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3335.     CMDraftMethodDebug("CMDraft","EndClone");
  3336.  
  3337.     ODStorageUnitID        fromID;
  3338.     ODStorageUnitID        toID;
  3339.  
  3340.     SOM_TRY
  3341.  
  3342.     if ((key != _fCurrentKey) || (_fLockCount == 0))
  3343.         THROW(kODErrInvalidDraftKey);
  3344.  
  3345.     somSelf->DoDeferredClones(ev, key);
  3346.  
  3347.     OpenHashTableIterator iter(_fWeakClonedSUIDs);
  3348.     for (iter.First(&fromID, &toID); iter.IsNotComplete(); iter.Next(&fromID, &toID)) {
  3349.         if (toID != 0) {
  3350.             ODStorageUnit* toSU = _fDestDraft->AcquireStorageUnit(ev, toID);
  3351. #ifdef DebugClone
  3352.             somPrintf("Removing weakly cloned ID %d (%d)\n", toID, ((CMStorageUnit*) toSU)->GetObjectID(ev));
  3353. #endif
  3354.             _fDestDraft->RemoveStorageUnit(ev, toSU);
  3355.         }
  3356.     }
  3357.  
  3358.     switch (_fCloneKind)
  3359.     {
  3360.     case kODCloneCopy:
  3361.     case kODCloneCut:
  3362.         SetOriginalDraft(ev, _fDestDraft, somSelf);
  3363.         if ( !OriginalCloneKindExists(ev, _fDestDraft) )
  3364.             SetOriginalCloneKind(ev, _fDestDraft, _fCloneKind);
  3365.         WriteClonedObjectTable(ev, _fClonedSUIDs, _fDestDraft);
  3366.         break;
  3367.     
  3368.     case kODClonePaste:
  3369.     case kODCloneDropCopy:
  3370.     case kODCloneDropMove:
  3371.     case kODCloneToFile:
  3372.         if ( (_fCloneKind == kODClonePaste) && (GetOriginalCloneKind(ev, somSelf) == kODCloneCut) )
  3373.             SetOriginalCloneKind(ev, somSelf, kODCloneCopy);
  3374.         break;
  3375.  
  3376.     default:
  3377.         break;
  3378.     }
  3379.  
  3380.     if ( somSelf->GetCloneKind(ev) == kODCloneDropMove )
  3381.     {
  3382.         if ( GetOriginalDraft(ev, somSelf) == _fDestDraft )
  3383.         {
  3384.             if ( _fAnyFrameCloned )
  3385.             {
  3386.                 if ( somSelf->ContainingPartInClone(ev, _fDestFrame) )
  3387.                     THROW(kODErrMoveIntoSelf);
  3388.             }
  3389.         }
  3390.     }
  3391.  
  3392.     --_fLockCount;
  3393.     
  3394.     if ( _fLockCount == 0 )
  3395.     {
  3396.         _fDestDraft = kODNULL;
  3397.         _fDestFrame = kODNULL;
  3398.     
  3399.         ODDeleteObject(_fClonedSUIDs);
  3400.         ODDeleteObject(_fLinksToCloneSUIDs);
  3401.     }
  3402.  
  3403.     ODDeleteObject(_fWeakClonedSUIDs);
  3404.     _fWeakClonedSUIDs = _fSavedWeakClonedSUIDs;
  3405.  
  3406. #ifdef DebugClone
  3407.     somPrintf("CMDraft::EndClone - Clone completed\n\n");
  3408. #endif
  3409.  
  3410.     SOM_CATCH_ALL
  3411.     SOM_ENDTRY
  3412. }
  3413.  
  3414. //------------------------------------------------------------------------------
  3415. // CMDraft: AbortClone
  3416. //------------------------------------------------------------------------------
  3417.  
  3418. SOM_Scope void  SOMLINK CMDraftAbortClone(CMDraft *somSelf, Environment *ev,
  3419.         ODDraftKey key)
  3420. {
  3421.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3422.     CMDraftMethodDebug("CMDraft","AbortClone");
  3423.  
  3424.     SOM_TRY
  3425.  
  3426. #if ODDebug_Drafts
  3427.     somPrintf("CMDraftAbort: %d\n", somSelf->GetID(ev));
  3428. #endif
  3429.  
  3430.     if ((key != _fCurrentKey) || (_fLockCount == 0))
  3431.         THROW(kODErrInvalidDraftKey);
  3432.  
  3433.     --_fLockCount;
  3434.  
  3435.     if ( _fLockCount == 0 )
  3436.     {
  3437.         _fDestDraft = kODNULL;
  3438.         _fDestFrame = kODNULL;
  3439.         
  3440.         ODDeleteObject(_fClonedSUIDs);
  3441.         ODDeleteObject(_fLinksToCloneSUIDs);
  3442.     }
  3443.  
  3444.     ODDeleteObject(_fWeakClonedSUIDs);
  3445.     _fWeakClonedSUIDs = _fSavedWeakClonedSUIDs;
  3446.  
  3447.     SOM_CATCH_ALL
  3448.     SOM_ENDTRY
  3449. }
  3450.  
  3451. //------------------------------------------------------------------------------
  3452. // CMDraft: SetOriginalID
  3453. //------------------------------------------------------------------------------
  3454.  
  3455. SOM_Scope void  SOMLINK CMDraftSetOriginalID(CMDraft *somSelf, Environment* ev,
  3456.         ODStorageUnitID destID,
  3457.         ODStorageUnitID originalID)
  3458. {
  3459.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3460.     CMDraftMethodDebug("CMDraft","SetOriginalID");
  3461.  
  3462.     SOM_TRY
  3463.     
  3464.     TempODStorageUnit destSU = _fDestDraft->AcquireStorageUnit(ev, destID);
  3465.     ODSetULongProp(ev, destSU, kODPropOriginalID, kODULong, originalID);
  3466.  
  3467.     SOM_CATCH_ALL
  3468.     SOM_ENDTRY
  3469. }
  3470.  
  3471. //------------------------------------------------------------------------------
  3472. // CMDraft: GetOriginalID
  3473. //------------------------------------------------------------------------------
  3474. // An original ID may not be present in the root storage unit of the draft,
  3475. // since this SU is often constructed in place rather than cloned.
  3476. // An null object ID is returned if the property is not present.
  3477.  
  3478. SOM_Scope ODStorageUnitID  SOMLINK CMDraftGetOriginalID(CMDraft *somSelf, Environment* ev,
  3479.         ODStorageUnitID fromID)
  3480. {
  3481.     //CMDraftData *somThis = CMDraftGetData(somSelf);
  3482.     CMDraftMethodDebug("CMDraft","GetOriginalID");
  3483.     
  3484.     SOM_TRY
  3485.  
  3486.     TempODStorageUnit fromSU = somSelf->AcquireStorageUnit(ev, fromID);
  3487.     return (ODStorageUnitID)ODGetULongProp(ev, fromSU, kODPropOriginalID, kODULong);
  3488.  
  3489.     SOM_CATCH_ALL
  3490.     SOM_ENDTRY
  3491.     return 0;
  3492. }
  3493.  
  3494. //------------------------------------------------------------------------------
  3495. // CheckPartAction
  3496. //------------------------------------------------------------------------------
  3497.  
  3498. static ODBoolean CheckPartAction(void* k, void* v, ODULong s, void* r)
  3499. {
  3500.     ODID            originalID =  * (ODID *) k;
  3501.     ODID            interupdateID = * (ODID *) v;
  3502.     OpenHashTable*    targetParts = (OpenHashTable*) r;
  3503.     ODBoolean        result = kODFalse;
  3504.     Environment*     ev = somGetGlobalEnvironment();
  3505.  
  3506.     // Note that storage units in the original document draft may not be up to date
  3507.     // if changes have not been externalized.  In particular, a frame's storage
  3508.     // unit may not have a valid reference to its part's storage unit.  For this
  3509.     // reason, use the storage units in the data interchange draft instead.
  3510.  
  3511. #ifdef DebugClone
  3512.     somPrintf("interupdateID %d, originalID %d\n", interupdateID, originalID);
  3513. #endif
  3514.  
  3515.     TempODStorageUnit interchangeSU = ::sInterchangeDraft->AcquireStorageUnit(ev, interupdateID);
  3516.     if ( ODSUExistsThenFocus(ev, interchangeSU, kODPropStorageUnitType, kODISOStr) )
  3517.     {
  3518.         if ( interchangeSU->GetSize(ev) == ODISOStrLength(kODFrameObject)+1 )
  3519.         {
  3520.             ODULong size = ODISOStrLength(kODFrameObject)+1;
  3521.             // Only read the same number of characters as in kODFrameObject, to prevent overwriting the
  3522.             // terminating zero byte of the buffer.
  3523.             if (ODGetISOStrProp(ev, interchangeSU, kODPropStorageUnitType, kODISOStr, (ODISOStr) ::sSUTypeBuffer, &size) 
  3524.                 != kODNULL)
  3525.             {
  3526.                 if (ODISOStrEqual(kODFrameObject, ::sSUTypeBuffer))
  3527.                 {
  3528.                     ODID interchangePartID = ODGetStrongSURefProp(ev, interchangeSU, kODPropPart, kODStrongStorageUnitRef);
  3529.                     if ( interchangePartID == kODNULLID )
  3530.                     {
  3531.                         // Note: If the reference isn't valid, ODGetStrongSURefProp will return
  3532.                         //   kODNULLID so it isn't necessary to call IsValidID instead.
  3533. #ifdef DebugClone
  3534.                         somPrintf("Invalid part reference from frame id %d\n", interupdateID);
  3535. #endif
  3536.                         result = kODTrue;    // Better safe than sorry!
  3537.                     }
  3538.                     else if ( interchangePartID != ::sRootPartIDToIgnore )
  3539.                     {
  3540.                         ODID targetPartID = ::sInterchangeDraft->GetOriginalID(ev, interchangePartID);
  3541. #ifdef DebugClone
  3542.                         somPrintf("Checking part id %d from frame id %d\n", targetPartID, originalID);
  3543. #endif
  3544.                         result = targetParts->Exists(&targetPartID);
  3545.                     }
  3546. #ifdef DebugClone
  3547.                     else
  3548.                     {
  3549.                         somPrintf("Skipping root part id %d because it was not cloned\n", interchangePartID);
  3550.                     }
  3551. #endif
  3552.                 }
  3553.             }
  3554.         }
  3555.     }
  3556.  
  3557.     return result;
  3558. }
  3559.  
  3560. //------------------------------------------------------------------------------
  3561. // CMDraft: ContainingPartInClone
  3562. //------------------------------------------------------------------------------
  3563.  
  3564. SOM_Scope ODBoolean  SOMLINK CMDraftContainingPartInClone(CMDraft *somSelf, Environment* ev,
  3565.         ODFrame* targetFrame)
  3566. {
  3567.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3568.     CMDraftMethodDebug("CMDraft","ContainingPartInClone");
  3569.  
  3570.     ODBoolean        result = kODFalse;
  3571.     ODFrame*        frame;
  3572.     ODFrame*        nextFrame;
  3573.     ODID            partID;
  3574.  
  3575.     OpenHashTable* targetParts = kODNULL;
  3576.     OpenHashTable* clonedSUIDs = kODNULL;
  3577.  
  3578.     SOM_TRY
  3579.  
  3580.         ODMemoryHeapID    heap = somSelf->GetHeap(ev);
  3581.  
  3582. #ifdef DebugClone
  3583.         somPrintf("ContainingPartInClone called with target frame id %d <%x>\n", targetFrame->GetID(ev), targetFrame);
  3584. #endif
  3585.  
  3586.         OpenHashTable* targetParts = new(heap) OpenHashTable(OpenHashTable::StdEqual,
  3587.                                                               OpenHashTable::StdHash,
  3588.                                                               heap);
  3589.         targetParts->Initialize(kInitialHashTableEntries, sizeof(ODID), 0, kODTrue);
  3590.     
  3591.         // Build a table of parts that own or embed the target frame
  3592.         frame = targetFrame;
  3593.         if ( frame )
  3594.             frame->Acquire(ev);
  3595.         while ( frame != kODNULL )
  3596.         {
  3597.             TempODFrame tempFrame = frame; // ensure it's released
  3598.             ODPart* part = frame->AcquirePart(ev);
  3599.             partID = part->GetID(ev);
  3600.             part->Release(ev);
  3601. #ifdef DebugClone
  3602.             somPrintf("Adding target part id %d from frame id %d\n", partID, frame->GetID(ev));
  3603. #endif
  3604.             targetParts->ReplaceEntry(&partID, kODNULL);
  3605.     
  3606.             nextFrame = frame->AcquireContainingFrame(ev);
  3607.             if ( nextFrame == kODNULL )
  3608.             {
  3609.                 { TempODWindow window = frame->AcquireWindow(ev);
  3610.                   nextFrame = window->AcquireSourceFrame(ev);
  3611.                 }
  3612.  
  3613.                 // The source frame always displays the same part, so skip to its containing frame.
  3614.                 // Note that it must have a containing frame.
  3615.                 if ( nextFrame != kODNULL )
  3616.                 {
  3617.                     TempODFrame sourceFrame = nextFrame;
  3618.                     nextFrame = sourceFrame->AcquireContainingFrame(ev);
  3619.                 }
  3620.             }
  3621.             frame = nextFrame;
  3622.         }
  3623.     
  3624.         clonedSUIDs = new(heap) OpenHashTable(OpenHashTable::StdEqual,
  3625.                                                  OpenHashTable::StdHash,
  3626.                                                  heap);
  3627.  
  3628.         clonedSUIDs->Initialize(kInitialHashTableEntries,
  3629.                                   sizeof(ODStorageUnitID),
  3630.                                   sizeof(ODStorageUnitID));
  3631.     
  3632.         // Get the table of objects cloned into the data interchange draft
  3633.         ReadClonedObjectTable(ev, clonedSUIDs, somSelf);
  3634.                 
  3635.         // See if any frame of any target part is part of the clone
  3636.         ::sInterchangeDraft = somSelf;
  3637.         ::sSUTypeBuffer = (ODISOStr) ODNewPtrClear(ODISOStrLength(kODFrameObject) + 1);
  3638.         ::sRootPartIDToIgnore = ( _fRootPartReused ? kODNULLID : RootPartID(ev, somSelf) );
  3639.         result = clonedSUIDs->Walk(CheckPartAction, targetParts);
  3640.         ODDisposePtr(::sSUTypeBuffer);
  3641.     
  3642.     SOM_CATCH_ALL
  3643.     
  3644.     SOM_ENDTRY
  3645.  
  3646.     ODDeleteObject(targetParts);
  3647.     ODDeleteObject(clonedSUIDs);
  3648.     
  3649. #ifdef DebugClone
  3650.     somPrintf("ContainingPartInClone returns %d\n", result);
  3651. #endif
  3652.  
  3653.     return result;
  3654. }
  3655.  
  3656. //------------------------------------------------------------------------------
  3657. // CompanionObjectID
  3658. //------------------------------------------------------------------------------
  3659.  
  3660. SOM_Scope ODID  SOMLINK CMDraftCompanionObjectID(CMDraft *somSelf, Environment *ev,
  3661.     ODID objectID)
  3662. {
  3663.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3664.     CMDraftMethodDebug("CMDraft","CompanionObjectID");
  3665.  
  3666.     ODStorageUnitID companionID = kODNULLID;
  3667.     ODPropertyName companionProperty = kODNULL;
  3668.  
  3669.     SOM_TRY
  3670.  
  3671.         if ( IsLinkObject(ev, somSelf, objectID) )
  3672.             companionProperty = kODPropLinkSource;
  3673.         else if ( IsLinkSourceObject(ev, somSelf, objectID) )
  3674.             companionProperty = kODPropLink;
  3675.     
  3676.         if ( companionProperty != kODNULL )
  3677.         {
  3678.             TempODStorageUnit objectSU = somSelf->AcquireStorageUnit(ev, objectID);
  3679.             if ( objectSU != kODNULL )
  3680.             {
  3681.                 companionID = ODGetWeakSURefProp(ev, objectSU, companionProperty, kODWeakStorageUnitRef);
  3682.             }
  3683.         }
  3684.  
  3685.     SOM_CATCH_ALL
  3686.  
  3687.     SOM_ENDTRY
  3688.  
  3689.     return companionID;
  3690. }
  3691.  
  3692. //------------------------------------------------------------------------------
  3693. //  CMDraft: CloneCompanionObject
  3694. //------------------------------------------------------------------------------
  3695. // If fromID is a link or link source object, clone its companion.
  3696. // Note that kODNULLID is always used as the scopeID, since scope is irrelevant
  3697. // for link and link source objects.
  3698.  
  3699. SOM_Scope ODID  SOMLINK CMDraftCloneCompanionObject(CMDraft *somSelf, Environment *ev,
  3700.         ODDraftKey key,
  3701.         ODID fromID)
  3702. {
  3703.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3704.     CMDraftMethodDebug("CMDraft","CloneCompanionObject");
  3705.  
  3706.     ODID toID = kODNULLID;    ODVolatile(toID);
  3707.  
  3708.     SOM_TRY
  3709.  
  3710.         ODStorageUnitID companionID = somSelf->CompanionObjectID(ev, fromID);
  3711.         if ( companionID != kODNULLID )
  3712.         {
  3713.             // Optimization: If the companion object has already been cloned,
  3714.             // there is no need to clone it again since scope is irrelevant for
  3715.             // these objects. [cc 9/28/95]
  3716.             _fClonedSUIDs->GetValue(&companionID, &toID);
  3717.             if ( toID == kODNULLID ) 
  3718.                 toID = somSelf->StrongClone(ev, key, companionID, kODNULLID, kODNULLID);
  3719.         }
  3720.  
  3721.     SOM_CATCH_ALL
  3722.     
  3723.     SOM_ENDTRY
  3724.  
  3725.     return toID;
  3726. }
  3727.  
  3728. //------------------------------------------------------------------------------
  3729. //  CMDraft: CompanionWasCloned
  3730. //------------------------------------------------------------------------------
  3731.  
  3732. SOM_Scope ODBoolean  SOMLINK CMDraftCompanionWasCloned(CMDraft *somSelf, Environment* ev,
  3733.         ODStorageUnitID fromID)
  3734. {
  3735.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3736.     CMDraftMethodDebug("CMDraft","CompanionWasCloned");
  3737.  
  3738.     ODBoolean result = kODFalse;
  3739.     
  3740.     SOM_TRY
  3741.         result = (somSelf->CompanionObjectID(ev, fromID) != kODNULLID);
  3742.     SOM_CATCH_ALL
  3743.     SOM_ENDTRY
  3744.  
  3745.     return result;
  3746. }
  3747.  
  3748. //------------------------------------------------------------------------------
  3749. //  CMDraft: GetCloneKind
  3750. //------------------------------------------------------------------------------
  3751.  
  3752. SOM_Scope ODCloneKind  SOMLINK CMDraftGetCloneKind(CMDraft *somSelf, Environment* ev)
  3753. {
  3754.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3755.     CMDraftMethodDebug("CMDraft","GetCloneKind");
  3756.     
  3757.     ODCloneKind cloneKind = _fCloneKind;
  3758.  
  3759.     SOM_TRY
  3760.  
  3761.     if ( cloneKind == kODClonePaste )
  3762.     {
  3763.         if ( (GetOriginalCloneKind(ev, somSelf) == kODCloneCut) && (GetOriginalDraft(ev, somSelf) == _fDestDraft) )
  3764.             cloneKind = kODCloneDropMove;
  3765.         else
  3766.             cloneKind = kODCloneDropCopy;
  3767.     }
  3768.     else if ( cloneKind == kODCloneToFile )
  3769.     {
  3770.         cloneKind = kODCloneDropCopy;
  3771.     }
  3772.     
  3773.     SOM_CATCH_ALL
  3774.     SOM_ENDTRY
  3775.     return cloneKind;
  3776. }
  3777.  
  3778. //------------------------------------------------------------------------------
  3779. //  CMDraft: DeferStrongClone
  3780. //------------------------------------------------------------------------------
  3781. //
  3782. // Defers cloning of a link or link source object in this draft to the 
  3783. // destination draft.  As in a weak clone, a storage unit is created in the
  3784. // destination draft an its ID is returned.  In addition, the object is put
  3785. // in a list of link objects.  EndClone should iterate over the list and
  3786. // clone those objects once the fate of their companion objects is known.
  3787.  
  3788. SOM_Scope ODID  SOMLINK CMDraftDeferStrongClone(CMDraft *somSelf, Environment* ev,
  3789.         ODID fromID)
  3790. {
  3791.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3792.     CMDraftMethodDebug("CMDraft","DeferStrongClone");
  3793.  
  3794.     ODID toID = kODNULLID; ODVolatile(toID);
  3795.  
  3796.     SOM_TRY
  3797.  
  3798.         ASSERT(IsEitherLinkObject(ev, somSelf, fromID), kODErrInvalidID);
  3799.  
  3800.         ASSERT(_fLinksToCloneSUIDs != kODNULL, kODErrCannotDeferClone);
  3801.  
  3802.         _fWeakClonedSUIDs->GetValue(&fromID, &toID);
  3803.         if ( toID == kODNULLID )
  3804.         {
  3805.             TempODStorageUnit toSU = _fDestDraft->CreateStorageUnit(ev);
  3806.             toID = toSU->GetID(ev);
  3807.             _fWeakClonedSUIDs->ReplaceEntry(&fromID, &toID);
  3808. #ifdef DebugClone
  3809.             somPrintf("Putting deferred clone from ID %d to ID %d on weak clone list\n", fromID, toID);
  3810. #endif
  3811.         }
  3812.  
  3813.         ODID toCloneID = kODNULLID;
  3814.         _fLinksToCloneSUIDs->GetValue(&fromID, &toCloneID);
  3815.         if ( toCloneID == kODNULLID )
  3816.         {
  3817.             _fLinksToCloneSUIDs->ReplaceEntry(&fromID, &toID);
  3818. #ifdef DebugClone
  3819.             somPrintf("Deferring clone from ID %d to ID %d\n", fromID, toID);
  3820. #endif
  3821.         }
  3822.  
  3823.     SOM_CATCH_ALL
  3824.  
  3825.     SOM_ENDTRY
  3826.  
  3827.     return toID;
  3828. }
  3829.  
  3830. //------------------------------------------------------------------------------
  3831. //  CMDraft: DoDeferredClones
  3832. //------------------------------------------------------------------------------
  3833.  
  3834. SOM_Scope void  SOMLINK CMDraftDoDeferredClones(CMDraft *somSelf, Environment* ev,
  3835.     ODDraftKey    key)
  3836. {
  3837.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3838.     CMDraftMethodDebug("CMDraft","DoDeferredClones");
  3839.  
  3840.     ODStorageUnitID fromID;
  3841.     ODStorageUnitID toID;
  3842.     ODStorageUnitID companionID;
  3843.     ODStorageUnitID toCompanionID;
  3844.  
  3845.     if ( _fLinksToCloneSUIDs != kODNULL )
  3846.     {
  3847.         SOM_TRY
  3848.  
  3849. #ifdef DebugClone
  3850.             somPrintf("Cloning deferred link and link source objects\n");
  3851. #endif
  3852.  
  3853.             OpenHashTableIterator iter(_fLinksToCloneSUIDs);
  3854.             for (iter.First(&fromID, &toID); iter.IsNotComplete(); iter.Next(&fromID, &toID))
  3855.             {
  3856.                 companionID = somSelf->CompanionObjectID(ev, fromID);
  3857.                 if ( companionID != kODNULLID )
  3858.                 {
  3859.                     // Because cloning both link and link source objects is deferred,
  3860.                     // it suffices to check just _fLinksToCloneSUIDs to see if the
  3861.                     // companion has also been deferred.
  3862.                     toCompanionID = kODNULLID;    // GetValue doesn't change if not found
  3863.                     _fLinksToCloneSUIDs->GetValue(&companionID, &toCompanionID);
  3864.                     if ( toCompanionID != kODNULLID )
  3865.                     {
  3866.                         // Previously, we just created a storage unit for the object,
  3867.                         // so now we must clone into that storage unit
  3868.                         somSelf->StrongClone(ev, key, fromID, toID, kODNULLID);
  3869.                     }
  3870.                     else
  3871.                     {
  3872.                         // The empty storage unit created in the destination draft
  3873.                         // will be removed with others that were only weakly cloned
  3874. #ifdef DebugClone
  3875.                         somPrintf("Companion object ID %d of ID %d was not cloned\n", companionID, fromID);
  3876. #endif
  3877.                     }
  3878.                 }
  3879.                 else
  3880.                 {
  3881. #ifdef DebugClone
  3882.                     somPrintf("No companion for object ID %d\n", fromID);
  3883. #endif
  3884.                 }
  3885.             }
  3886.  
  3887.         SOM_CATCH_ALL
  3888.         
  3889.         SOM_ENDTRY
  3890.     }
  3891. }
  3892.  
  3893. //------------------------------------------------------------------------------
  3894. //  CMDraft: DropCopyClone
  3895. //------------------------------------------------------------------------------
  3896. //
  3897. // Implements strong cloning of objects during a paste or drop of copied content.
  3898. // Takes into consideration whether the source draft is an
  3899. // intermediate draft or a document draft (for example, an OpenDoc file dragged
  3900. // in from the Finder).  If the clone is from an intermediat draft back into
  3901. // the same document draft, the original object ID may be substituted, or a null
  3902. // object ID may be returned.  Enforces rules for copying link source and link
  3903. // objects.
  3904.  
  3905. SOM_Scope ODID  SOMLINK CMDraftDropCopyClone(CMDraft *somSelf, Environment* ev,
  3906.         ODDraftKey    key,
  3907.         ODID        fromID,
  3908.         ODID        toID,
  3909.         ODID        scopeID)
  3910. {
  3911.     CMDraftData *somThis = CMDraftGetData(somSelf);
  3912.     CMDraftMethodDebug("CMDraft","DropCopyClone");
  3913.  
  3914.     ODID clonedID = kODNULLID; ODVolatile(clonedID);
  3915.  
  3916.     SOM_TRY
  3917.  
  3918.         ASSERT(somSelf->GetCloneKind(ev) == kODCloneDropCopy, kODErrInvalidCloneKind);
  3919.     
  3920.         if ( IsLinkObject(ev, somSelf, fromID) )
  3921.         {
  3922.             ODDraft* originalDraft = GetOriginalDraft(ev, somSelf);
  3923.             if ( originalDraft == _fDestDraft )
  3924.             {
  3925.                 // Clone is from an intermediate draft back into the original draft.
  3926.                 // Because the clone is from an intermediate draft, we can check
  3927.                 // to see if the link source object was also cloned into the
  3928.                 // intermediate draft.
  3929.                 if ( somSelf->CompanionWasCloned(ev, fromID) )
  3930.                 {
  3931.                     // The link source object was copied, so clone the link object
  3932.                     // to create a new one.
  3933.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  3934.                 }
  3935.                 else
  3936.                 {
  3937.                     // The link source object was not cloned, so substitute the ID
  3938.                     // of the original link object so copied destinations reference
  3939.                     // the original link object.
  3940.                     ASSERT(toID == 0, kODErrInvalidID);
  3941.                     clonedID = somSelf->GetOriginalID(ev, fromID);
  3942.                     ASSERT(_fDestDraft->IsValidID(ev, clonedID), kODErrInvalidID);
  3943. #ifdef DebugClone
  3944.                     somPrintf("Reusing existing link object id = %d for cloned object %d\n", clonedID, fromID);
  3945. #endif
  3946.                 }
  3947.             }
  3948.             else if ( originalDraft != kODNULL )
  3949.             {
  3950.                 // Clone is cross-draft via an intermediate draft.  Only link
  3951.                 // and link source pairs are copied.
  3952.                 // Because the clone is from an intermediate draft, we can check
  3953.                 // to see if the link source object was also cloned into the
  3954.                 // intermediate draft.
  3955.                 if ( somSelf->CompanionWasCloned(ev, fromID) )
  3956.                 {
  3957.                     // The link source object was copied, so clone the link object
  3958.                     // to create a new one.
  3959.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  3960.                 }
  3961.                 else
  3962.                 {
  3963.                     // The link source object was not cloned, so don't clone the link
  3964.                     clonedID = kODNULLID;
  3965. #ifdef DebugClone
  3966.                     somPrintf("CMDraftStrongClone NOT cloning from ID %d\n", fromID);
  3967. #endif
  3968.                 }
  3969.             }
  3970.             else
  3971.             {
  3972.                 // Clone is from a document draft.  Create a storage unit and return
  3973.                 // its ID.  EndClone will either clone the object or remove the
  3974.                 // storage unit from the destination draft.
  3975.                 clonedID = somSelf->DeferStrongClone(ev, fromID);
  3976.             }
  3977.         }
  3978.         else if ( IsLinkSourceObject(ev, somSelf, fromID) )
  3979.         {
  3980.             if ( GetOriginalDraft(ev, somSelf) != kODNULL )
  3981.             {
  3982.                 // Clone is from an intermediate draft (it doesn't matter if the
  3983.                 // destination draft is the same as the original draft or not).
  3984.                 // Because the clone is from an intermediate draft, we can check
  3985.                 // to see if the link object was also cloned into the
  3986.                 // intermediate draft.
  3987.                 if ( somSelf->CompanionWasCloned(ev, fromID) )
  3988.                 {
  3989.                     // The link object was copied, so clone the link source object
  3990.                     // to create a new one.
  3991.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  3992.                 }
  3993.                 else
  3994.                 {
  3995.                     // The link object was not cloned, so don't clone the link source
  3996.                     clonedID = kODNULLID;
  3997. #ifdef DebugClone
  3998.                     somPrintf("CMDraftStrongClone NOT cloning from ID %d\n", fromID);
  3999. #endif
  4000.                 }
  4001.             }
  4002.             else
  4003.             {
  4004.                 // Clone is from a document draft.  Create a storage unit and return
  4005.                 // its ID.  EndClone will either clone the object or remove the
  4006.                 // storage unit from the destination draft.
  4007.                 clonedID = somSelf->DeferStrongClone(ev, fromID);
  4008.             }
  4009.         }
  4010.         else
  4011.         {
  4012.             // Not a link or link source object, so clone it
  4013.             clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4014.         }
  4015.     
  4016.     SOM_CATCH_ALL
  4017.     
  4018.     SOM_ENDTRY
  4019.  
  4020.     return clonedID;
  4021. }
  4022.  
  4023. //------------------------------------------------------------------------------
  4024. //  CMDraft: DropMoveClone
  4025. //------------------------------------------------------------------------------
  4026. //
  4027. // Implements strong cloning of objects during a paste of cut content or a drop
  4028. // of moved content.  Takes into consideration wether the source draft is an
  4029. // intermediate draft or a document draft (for example, an OpenDoc file dragged
  4030. // in from the Finder).  If the clone is from an intermediate draft back into
  4031. // the same document draft, the original object ID may be substituted, or a null
  4032. // object ID may be returned.  Enforces rules for moving link source and link
  4033. // objects. When moved to another draft, links behave as if copied.
  4034.  
  4035. SOM_Scope ODID  SOMLINK CMDraftDropMoveClone(CMDraft *somSelf, Environment* ev,
  4036.         ODDraftKey    key,
  4037.         ODID        fromID,
  4038.         ODID        toID,
  4039.         ODID        scopeID)
  4040. {
  4041.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4042.     CMDraftMethodDebug("CMDraft","DropMoveClone");
  4043.  
  4044.     ODID clonedID = kODNULLID; ODVolatile(clonedID);
  4045.  
  4046.     SOM_TRY
  4047.  
  4048.         ASSERT(somSelf->GetCloneKind(ev) == kODCloneDropMove, kODErrInvalidCloneKind);
  4049.     
  4050.         ODDraft* originalDraft = GetOriginalDraft(ev, somSelf);
  4051.         if ( originalDraft == _fDestDraft )
  4052.         {
  4053.             // Clone is from an intermediate draft back into the original draft.
  4054.             // In this case, no distinction is made between link, link source,
  4055.             // and other objects being cloned.
  4056.             // toID will be non-zero if the object has already been weakly cloned.
  4057.             // If the original object is still present in the destination draft,
  4058.             // use it unless the caller explicitly cloned into another storage unit.
  4059.             ODID originalID = somSelf->GetOriginalID(ev, fromID);
  4060.             if ( _fDestDraft->IsValidID(ev, originalID) )
  4061.             {
  4062.                 if ( (toID == 0) || (toID == originalID) )
  4063.                 {
  4064.                     clonedID = originalID;
  4065. #ifdef DebugClone
  4066.                     somPrintf("CMDraftStrongClone from ID %d to substitute ID %d\n", fromID, clonedID);
  4067. #endif
  4068.                 }
  4069.                 else
  4070.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4071.             }
  4072.             else
  4073.             {
  4074.                 clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4075. #ifdef DebugClone
  4076.                 if ( originalID != kODNULLID )
  4077.                     somPrintf("Original id = %d is not valid\n", originalID);
  4078. #endif
  4079.             }
  4080.             somSelf->CheckClonedObject(ev, fromID, clonedID, originalID);
  4081.         }
  4082.         else if ( IsEitherLinkObject(ev, somSelf, fromID) )
  4083.         {
  4084.             if ( originalDraft != kODNULL )
  4085.             {
  4086.                 // Clone is cross-draft via an intermediate draft.  Only link
  4087.                 // and link source pairs are copied.
  4088.                 // Because the clone is from an intermediate draft, we can check
  4089.                 // to see if the companion object was also cloned into the
  4090.                 // intermediate draft.
  4091.                 if ( somSelf->CompanionWasCloned(ev, fromID) )
  4092.                 {
  4093.                     // The link source object was copied, so clone the link object
  4094.                     // to create a new one.
  4095.                     clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4096.                 }
  4097.                 else
  4098.                 {
  4099.                     // The companion object was not cloned, so don't clone the link
  4100.                     clonedID = kODNULLID;
  4101. #ifdef DebugClone
  4102.                     somPrintf("CMDraftStrongClone NOT cloning from ID %d\n", fromID);
  4103. #endif
  4104.                 }
  4105.             }
  4106.             else
  4107.             {
  4108.                 // Clone is from a document draft.  Create a storage unit and return
  4109.                 // its ID.  EndClone will either clone the object or remove the
  4110.                 // storage unit from the destination draft.
  4111.                 clonedID = somSelf->DeferStrongClone(ev, fromID);
  4112.             }
  4113.         }
  4114.         else
  4115.         {
  4116.             // Other objects moved across drafts are always cloned
  4117.             clonedID = somSelf->StrongClone(ev, key, fromID, toID, scopeID);
  4118.         }
  4119.     
  4120.     SOM_CATCH_ALL
  4121.     
  4122.     SOM_ENDTRY
  4123.  
  4124.     return clonedID;
  4125. }
  4126.  
  4127. //------------------------------------------------------------------------------
  4128. //  CMDraft: DoWeakClone
  4129. //------------------------------------------------------------------------------
  4130. //
  4131. // Implements weak clone of objects that have not already been strongly or
  4132. // weakly cloned.
  4133. // If link objects are copied or moved across a draft...
  4134.  
  4135. SOM_Scope ODID  SOMLINK CMDraftDoWeakClone(CMDraft *somSelf, Environment* ev,
  4136.         ODID fromID)
  4137. {
  4138.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4139.     CMDraftMethodDebug("CMDraft","DoWeakClone");
  4140.  
  4141.     ODID        clonedID = kODNULLID; ODVolatile(clonedID);
  4142.     ODBoolean    doWeakClone = kODFalse;
  4143.     ODDraft*    originalDraft = kODNULL;
  4144.  
  4145.     SOM_TRY
  4146.  
  4147.         ODCloneKind cloneKind = somSelf->GetCloneKind(ev);
  4148.         
  4149.         if ( cloneKind == kODCloneDropCopy )
  4150.         {
  4151.             if ( IsLinkObject(ev, somSelf, fromID) )
  4152.             {
  4153.                 originalDraft = GetOriginalDraft(ev, somSelf);
  4154.                 if ( originalDraft == _fDestDraft )
  4155.                 {
  4156.                     // Clone is from an intermediate draft back into the original draft.
  4157.                     // Because the clone is from an intermediate draft, we can check
  4158.                     // to see if the link source object was also cloned into the
  4159.                     // intermediate draft.
  4160.                     if ( somSelf->CompanionWasCloned(ev, fromID) )
  4161.                     {
  4162.                         // The link source object was copied, so clone the link object
  4163.                         // to create a new one.
  4164.                         doWeakClone = kODTrue;
  4165.                     }
  4166.                     else
  4167.                     {
  4168.                         // The link source object was not cloned, so substitute the ID
  4169.                         // of the original link object so copied destinations reference
  4170.                         // the original link object.
  4171.                         clonedID = somSelf->GetOriginalID(ev, fromID);
  4172.                         ASSERT(_fDestDraft->IsValidID(ev, clonedID), kODErrInvalidID);
  4173. #ifdef DebugClone
  4174.                         somPrintf("Reusing existing link object id = %d for weakly cloned object %d\n", clonedID, fromID);
  4175. #endif
  4176.                     }
  4177.                 }
  4178.                 else if ( originalDraft != kODNULL )
  4179.                 {
  4180.                     // Clone is cross-draft via an intermediate draft.  Only link
  4181.                     // and link source pairs are copied.
  4182.                     // Because the clone is from an intermediate draft, we can check
  4183.                     // to see if the link source object was also cloned into the
  4184.                     // intermediate draft.  If the link source was cloned, we can
  4185.                     // weakly clone this link object.
  4186.  
  4187.                     doWeakClone = somSelf->CompanionWasCloned(ev, fromID);
  4188.                 }
  4189.                 else
  4190.                 {
  4191.                     // Clone is from a document draft.  Weakly clone it.
  4192.                     doWeakClone = kODTrue;
  4193.                 }
  4194.             }
  4195.             else if ( IsLinkSourceObject(ev, somSelf, fromID) )
  4196.             {
  4197.                 originalDraft = GetOriginalDraft(ev, somSelf);
  4198.                 if ( originalDraft != kODNULL )
  4199.                 {
  4200.                     // Clone is from an intermediate draft.
  4201.                     // Because the clone is from an intermediate draft, we can check
  4202.                     // to see if the link object was also cloned into the
  4203.                     // intermediate draft.
  4204.                     doWeakClone = somSelf->CompanionWasCloned(ev, fromID);
  4205.                 }
  4206.                 else
  4207.                 {
  4208.                     // Clone is from a document draft.  Weakly clone it.
  4209.                     doWeakClone = kODTrue;
  4210.                 }
  4211.             }
  4212.             else
  4213.             {
  4214.                 // Weakly clone all other objects
  4215.                 doWeakClone = kODTrue;
  4216.             }
  4217.         }
  4218.         else if ( cloneKind == kODCloneDropMove )
  4219.         {
  4220.             originalDraft = GetOriginalDraft(ev, somSelf);
  4221.             if ( originalDraft == _fDestDraft )
  4222.             {
  4223.                 // Clone is from an intermediate draft back into the original draft.
  4224.                 // In this case, no distinction is made between link, link source,
  4225.                 // and other objects being cloned.
  4226.                 ODID originalID = somSelf->GetOriginalID(ev, fromID);
  4227.                 if ( _fDestDraft->IsValidID(ev, originalID) )
  4228.                 {
  4229.                     clonedID = originalID;
  4230.                     
  4231.                     // Assumption: If the original object is substituted for a
  4232.                     // weakly-referenced clone, the clone is also strongly-referenced
  4233.                     // and will be strongly cloned back into the draft, so its
  4234.                     // unnecessary to call somSelf->CheckClonedObject here.
  4235.                 }
  4236.                 else
  4237.                 {
  4238.                     doWeakClone = kODTrue;
  4239. #ifdef DebugClone
  4240.                     if ( originalID != kODNULLID )
  4241.                         somPrintf("Original id = %d is not valid\n", originalID);
  4242. #endif
  4243.                 }
  4244.             }
  4245.             else if ( IsEitherLinkObject(ev, somSelf, fromID) )
  4246.             {
  4247.                 if ( originalDraft != kODNULL )
  4248.                 {
  4249.                     // Clone is cross-draft via an intermediate draft.  Only link
  4250.                     // and link source pairs are copied.
  4251.                     // Because the clone is from an intermediate draft, we can check
  4252.                     // to see if the link source object was also cloned into the
  4253.                     // intermediate draft.
  4254.                     doWeakClone = somSelf->CompanionWasCloned(ev, fromID);
  4255.                 }
  4256.                 else
  4257.                 {
  4258.                     // Clone is from a document draft.
  4259.                     doWeakClone = kODTrue;
  4260.                 }
  4261.             }
  4262.             else
  4263.             {
  4264.                 // Other objects moved across drafts are always cloned
  4265.                 doWeakClone = kODTrue;
  4266.             }
  4267.         }
  4268.         else
  4269.         {
  4270.             // Note a paste or a drop; do a weak clone
  4271.             doWeakClone = kODTrue;
  4272.         }
  4273.  
  4274.         if ( doWeakClone )
  4275.         {
  4276.             TempODStorageUnit toSU = _fDestDraft->CreateStorageUnit(ev);
  4277.             clonedID = toSU->GetID(ev);
  4278.             _fWeakClonedSUIDs->ReplaceEntry(&fromID, &clonedID);
  4279.         }
  4280.  
  4281. #ifdef DebugClone
  4282.         if ( doWeakClone )
  4283.             somPrintf("CMDraftWeakClone from ID %d to ID %d", fromID, clonedID);
  4284.         else
  4285.             somPrintf("CMDraftWeakClone from ID %d to substitute ID %d", fromID, clonedID);
  4286.         TempODISOStr suType = GetStorageUnitType(ev, somSelf, fromID);
  4287.         somPrintf(" type %s\n", (ODISOStr) suType);
  4288. #endif
  4289.  
  4290.     SOM_CATCH_ALL
  4291.     
  4292.     SOM_ENDTRY
  4293.  
  4294.     return clonedID;
  4295. }
  4296.  
  4297. //------------------------------------------------------------------------------
  4298. // CMDraft: Clone
  4299. //------------------------------------------------------------------------------
  4300. //
  4301. // It should really be replaced by a table-driven algorithm.  There are only 
  4302. // three possible actions when cloning a link or link source object:
  4303. //        (1) Go ahead and clone the link,
  4304. //        (2) Don't clone the link,
  4305. //        (3) Substitute the original link rather than clone in a duplicate
  4306. // However, there are four factors that determine which action should be taken.
  4307. // There are 8x3x2x2 = 96 distinct combinations of these factors; however,
  4308. // most combinations are impossible or illegal.
  4309. // The switch statement is an embodyment in code of the resulting sparse matrix.
  4310. // Several cases are sometimes handled at once.  Only by going back to the full 
  4311. // case analysis represented by a table can one understand this code.
  4312. // 
  4313. // Note that its possible that a link object's companion doesn't exist; in this
  4314. // case the link is broken and won't be copied.
  4315. // 
  4316.  
  4317. SOM_Scope ODID  SOMLINK CMDraftClone(CMDraft *somSelf, Environment *ev,
  4318.         ODDraftKey key,
  4319.         ODID fromID,
  4320.         ODID toObjectID,
  4321.         ODID scopeID)
  4322. {
  4323.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4324.     CMDraftMethodDebug("CMDraft","Clone");
  4325.  
  4326.     SOM_TRY
  4327.  
  4328.     if ((key != _fCurrentKey) || (_fLockCount == 0))
  4329.         THROW(kODErrInvalidDraftKey);
  4330.  
  4331.     ODStorageUnitID    toID = 0;
  4332.  
  4333.     switch ( somSelf->GetCloneKind(ev) )
  4334.     {
  4335.     case kODCloneAll:
  4336.         toID = somSelf->StrongClone(ev, key, fromID, toObjectID, scopeID);
  4337.         somSelf->CloneCompanionObject(ev, key, fromID);
  4338.         break;
  4339.  
  4340.     case kODCloneFromLink:
  4341.     case kODCloneToLink:
  4342.         if ( IsNeitherLinkObject(ev, somSelf, fromID) )
  4343.             toID = somSelf->StrongClone(ev, key, fromID, toObjectID, scopeID);
  4344.         break;
  4345.  
  4346.     case kODCloneCopy:
  4347.     case kODCloneCut:
  4348.         toID = somSelf->StrongClone(ev, key, fromID, toObjectID, scopeID);
  4349.         somSelf->SetOriginalID(ev, toID, fromID);
  4350.         break;
  4351.         
  4352.     case kODCloneDropCopy:
  4353.         toID = somSelf->DropCopyClone(ev, key, fromID, toObjectID, scopeID);
  4354.         break;
  4355.  
  4356.     case kODCloneDropMove:
  4357.         toID = somSelf->DropMoveClone(ev, key, fromID, toObjectID, scopeID);
  4358.         break;
  4359.  
  4360.     default:
  4361.         break;
  4362.     }
  4363.  
  4364.     return toID;
  4365.  
  4366.     SOM_CATCH_ALL
  4367.     SOM_ENDTRY
  4368.     return 0;
  4369. }
  4370.  
  4371. //------------------------------------------------------------------------------
  4372. // CMDraft: StrongClone
  4373. //------------------------------------------------------------------------------
  4374.  
  4375. SOM_Scope ODID  SOMLINK CMDraftStrongClone(CMDraft *somSelf, Environment *ev,
  4376.         ODDraftKey key,
  4377.         ODID fromID,
  4378.         ODID toObjectID,
  4379.         ODID scopeID)
  4380. {
  4381.     SOM_TRY
  4382.     
  4383.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4384.     CMDraftMethodDebug("CMDraft","StrongClone");
  4385.  
  4386. #ifdef DebugClone
  4387.     somPrintf("CMDraftStrongClone from ID %d to ID %d scope ID %d\n", fromID, toObjectID, scopeID);
  4388. #endif
  4389.  
  4390.     ODStorageUnitID        toID = 0;
  4391.     TempODStorageUnit toSU = kODNULL;
  4392.     
  4393.     _fClonedSUIDs->GetValue(&fromID, &toID);
  4394.     if (toID == 0) {
  4395.         _fWeakClonedSUIDs->GetValue(&fromID, &toID);
  4396.         if (toID == 0) {
  4397.             if (toObjectID != 0) 
  4398.                 toSU = _fDestDraft->AcquireStorageUnit(ev, toObjectID);
  4399.             else
  4400.                 toSU = _fDestDraft->CreateStorageUnit(ev);
  4401.             toID = toSU->GetID(ev);
  4402.             _fClonedSUIDs->ReplaceEntry(&fromID, &toID);
  4403.         }
  4404.         else {
  4405.             if ((toObjectID != 0) && (toObjectID != toID))
  4406.                 THROW(kODErrInvalidID);
  4407.             _fWeakClonedSUIDs->RemoveEntry(&fromID);
  4408.             _fClonedSUIDs->ReplaceEntry(&fromID, &toID);
  4409.             toSU = _fDestDraft->AcquireStorageUnit(ev, toID);
  4410.         }
  4411.     }
  4412.     else {
  4413.         if ((toObjectID != 0) && (toObjectID != toID))
  4414.             THROW(kODErrInvalidID);
  4415.         toSU = _fDestDraft->AcquireStorageUnit(ev, toID);
  4416.     }
  4417.         
  4418.     ODPersistentObject *fromObject = somSelf->RetrievePersistentObject(ev, fromID);
  4419.     if ( fromObject ) {
  4420.         TempODRefCntObject tempFromObject = fromObject; // so it gets released
  4421.         TempODFrame scopeFrame = kODNULL;
  4422.         if (scopeID != 0)
  4423.             scopeFrame = somSelf->AcquireFrame(ev, scopeID);
  4424.         fromObject->CloneInto(ev, key, toSU, scopeFrame);
  4425.         ODStorageUnit* fromSU = fromObject->GetStorageUnit(ev);
  4426.         if (fromSU != kODNULL)
  4427.             CopyDraftAnnotations(ev, fromSU, toSU);
  4428.     }
  4429.     else {
  4430.         TempODStorageUnit fromSU = somSelf->AcquireStorageUnit(ev, fromID);
  4431.         if (fromSU != kODNULL) {
  4432.             fromSU->CloneInto(ev, key, toSU, scopeID);
  4433.             ODBoolean keepProxyProperties = (_fCloneKind == kODCloneToFile)
  4434.                                         || (_fCloneKind == kODCloneAll);
  4435.             RemoveDataInterchangeProperties(ev, toSU, keepProxyProperties);
  4436. //            CopyDraftAnnotations(ev, fromSU, toSU);
  4437.         }
  4438.     }
  4439.     
  4440. #ifdef DebugClone
  4441.     somPrintf("Done CMDraftStrongClone from ID %d to ID %d\n", fromID, toID);
  4442. #endif
  4443.  
  4444.     return toID;
  4445.  
  4446.     SOM_CATCH_ALL
  4447.     SOM_ENDTRY
  4448.     return 0;
  4449. }        
  4450.  
  4451. //------------------------------------------------------------------------------
  4452. // CMDraft: WeakClone
  4453. //------------------------------------------------------------------------------
  4454.  
  4455. SOM_Scope ODID  SOMLINK CMDraftWeakClone(CMDraft *somSelf, Environment *ev,
  4456.         ODDraftKey key,
  4457.         ODID fromID,
  4458.         ODID toObjectID,
  4459.         ODID scopeID)
  4460. {
  4461.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4462.     CMDraftMethodDebug("CMDraft","Clone");
  4463.  
  4464.     ODUnused(scopeID);
  4465.  
  4466.     SOM_TRY
  4467.  
  4468.     ODStorageUnitID    toID = 0;
  4469.     
  4470.     _fClonedSUIDs->GetValue(&fromID, &toID);
  4471.     if (toID == 0)
  4472.     {
  4473.         _fWeakClonedSUIDs->GetValue(&fromID, &toID);
  4474.         if (toID == 0)
  4475.         {
  4476.             toID = toObjectID;
  4477.             if ( toID == 0 )
  4478.             {
  4479.                 // Note that this may substitute the null object id, which
  4480.                 // will be returned instead of a valid object id!
  4481.                 toID = somSelf->DoWeakClone(ev, fromID);
  4482.             }
  4483.         }
  4484.     }
  4485.     if ((toObjectID != 0) && (toObjectID != toID))
  4486.         THROW(kODErrInvalidID);
  4487.     
  4488.     return toID;
  4489.  
  4490.     SOM_CATCH_ALL
  4491.     SOM_ENDTRY
  4492.     return 0;
  4493. }
  4494.  
  4495. //------------------------------------------------------------------------------
  4496. // CMDraft: IsValidDraftKey
  4497. //------------------------------------------------------------------------------
  4498.  
  4499. SOM_Scope ODBoolean  SOMLINK CMDraftIsValidDraftKey(CMDraft *somSelf, Environment *ev,
  4500.         ODDraftKey key)
  4501. {
  4502.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4503.     CMDraftMethodDebug("CMDraft","IsValidDraftKey");
  4504.  
  4505.     return ((key != kODNULLKey) && (_fCurrentKey == key) ? kODTrue : kODFalse);
  4506. }
  4507.  
  4508. //------------------------------------------------------------------------------
  4509. // CopyProperty
  4510. //------------------------------------------------------------------------------
  4511.  
  4512. static void CopyProperty(Environment *ev, ODStorageUnit* fromSU, ODStorageUnit* toSU, ODPropertyName prop)
  4513. {
  4514.     // Assuming fromSU is focused to prop.    
  4515.     // Copy all values into toSU, overwriting any existing values there.
  4516.  
  4517.     PreserveFocus fromFocus(ev, fromSU);
  4518.     PreserveFocus toFocus(ev, toSU);
  4519.     
  4520.     ODULong            numValues;
  4521.     ODULong            j;
  4522.     ODValueType        valueName;
  4523.  
  4524.     fromSU->Focus(ev, (ODPropertyName) prop, kODPosUndefined, kODNULL, 0, kODPosAll);
  4525.  
  4526.     numValues = fromSU->CountValues(ev);    
  4527.     
  4528.     if ( numValues > 0)
  4529.         ODSUForceFocus(ev, toSU, prop, kODNULL);
  4530.     
  4531.     for (j = 0; j < numValues; j++)
  4532.     {
  4533.         fromSU->Focus(ev, (ODPropertyName) kODNULL, kODPosSame, kODNULL, 0, kODPosNextSib);
  4534.  
  4535.         valueName = fromSU->GetType(ev);
  4536.  
  4537.         ODSUForceFocus(ev, toSU, prop, valueName);
  4538.         ODULong toSize = toSU->GetSize(ev);
  4539.         toSU->DeleteValue(ev, toSize);
  4540.  
  4541.         ODDisposePtr(valueName);
  4542.         
  4543.         ODULong size = fromSU->GetSize(ev);
  4544.         ODPtr buffer = ODNewPtr(size);
  4545.         StorageUnitGetValue(fromSU, ev, size, (ODValue) buffer);
  4546.         StorageUnitSetValue(toSU, ev, size, (ODValue) buffer);
  4547.         ODDisposePtr(buffer);
  4548.     }
  4549. }
  4550.  
  4551. //------------------------------------------------------------------------------
  4552. // CopyDraftAnnotations
  4553. //------------------------------------------------------------------------------
  4554.  
  4555. static void CopyDraftAnnotations(Environment *ev, ODStorageUnit* fromSU, ODStorageUnit* toSU)
  4556. {
  4557.     ODULong annotationPrefixLength = ODISOStrLength(kODPropPreAnnotation);
  4558.     ODULong metaDataPrefixLength = ODISOStrLength(kODPropPreODMetaData);
  4559.     
  4560.     fromSU->Focus(ev, (ODPropertyName) kODNULL, 
  4561.                             kODPosAll,
  4562.                             kODTypeAll,
  4563.                             0,
  4564.                             kODPosUndefined);
  4565.     ODULong numProperties = fromSU->CountProperties(ev);
  4566.     for (ODULong i = 1; i <= numProperties; i++) {
  4567.         fromSU->Focus(ev, (ODPropertyName) kODNULL,
  4568.                         kODPosNextSib,
  4569.                         kODTypeAll,
  4570.                         0,
  4571.                         kODPosUndefined);
  4572.         ODPropertyName propertyName = fromSU->GetProperty(ev);
  4573.         if (ODISOStrNCompare(propertyName, kODPropPreAnnotation, annotationPrefixLength) == 0)
  4574.             CopyProperty(ev, fromSU, toSU, propertyName);
  4575.         else if ((ODISOStrNCompare(propertyName, kODPropPreODMetaData, metaDataPrefixLength) == 0) &&
  4576.             (toSU->Exists(ev, propertyName, kODNULL, 0) == kODFalse)) {
  4577. #ifdef ODDebug_CloningAnnotations
  4578.             SetOutputMode(kWriteToFile);
  4579.             PRINT("metadata property %s does not exist in destination su.\n", propertyName);
  4580. #endif
  4581.             CopyProperty(ev, fromSU, toSU, propertyName);
  4582.         }
  4583.         ODDisposePtr(propertyName);
  4584.     }
  4585.  
  4586.     // Force copying of storage unit type property, which always exists so is
  4587.     // not copied in the iteration above.
  4588.     CopyProperty(ev, fromSU, toSU, kODPropStorageUnitType);
  4589. }
  4590.  
  4591. //------------------------------------------------------------------------------
  4592. // IsLinkObject
  4593. //------------------------------------------------------------------------------
  4594.  
  4595. static ODBoolean IsLinkObject(Environment* ev, ODDraft* draft, ODID objectID)
  4596. {
  4597.     // Only link objects contain a kODPropLinkSource property
  4598.  
  4599.     TRY
  4600.  
  4601.     TempODStorageUnit su = draft->AcquireStorageUnit(ev, objectID);
  4602.     ODBoolean isLink = su->Exists(ev, kODPropLinkSource, kODNULL, 0);
  4603.  
  4604. #ifdef DebugClone
  4605.     if ( isLink )
  4606.         somPrintf("Object ID %d is a link\n", objectID);
  4607. #endif
  4608.     
  4609.     return isLink;
  4610.  
  4611.     CATCH_ALL
  4612.     ENDTRY
  4613.     return kODFalse;
  4614. }
  4615.  
  4616. //------------------------------------------------------------------------------
  4617. // IsLinkSourceObject
  4618. //------------------------------------------------------------------------------
  4619.  
  4620. static ODBoolean IsLinkSourceObject(Environment* ev, ODDraft* draft, ODID objectID)
  4621. {
  4622.     // Only link source objects contain a kODPropLink property
  4623.  
  4624.     TRY
  4625.  
  4626.     TempODStorageUnit su = draft->AcquireStorageUnit(ev, objectID);
  4627.     ODBoolean isLinkSource = su->Exists(ev, kODPropLink, kODNULL, 0);
  4628.  
  4629. #ifdef DebugClone
  4630.     if ( isLinkSource )
  4631.         somPrintf("Object ID %d is a link source\n", objectID);
  4632. #endif
  4633.     
  4634.     return isLinkSource;
  4635.  
  4636.     CATCH_ALL
  4637.     ENDTRY
  4638.     return kODFalse;
  4639. }
  4640.  
  4641. //------------------------------------------------------------------------------
  4642. // IsEitherLinkObject
  4643. //------------------------------------------------------------------------------
  4644.  
  4645. static ODBoolean IsEitherLinkObject(Environment* ev, ODDraft* draft, ODID objectID)
  4646. {
  4647.     if ( IsLinkObject(ev, draft, objectID) )
  4648.         return kODTrue;
  4649.     else
  4650.         return IsLinkSourceObject(ev, draft, objectID);
  4651. }
  4652.  
  4653. //------------------------------------------------------------------------------
  4654. // IsNeitherLinkObject
  4655. //------------------------------------------------------------------------------
  4656.  
  4657. static ODBoolean IsNeitherLinkObject(Environment* ev, ODDraft* draft, ODID objectID)
  4658. {
  4659.     if ( IsLinkObject(ev, draft, objectID) )
  4660.         return kODFalse;
  4661.     else
  4662.         return !IsLinkSourceObject(ev, draft, objectID);
  4663. }
  4664.  
  4665. //------------------------------------------------------------------------------
  4666. // SetStorageUnitType
  4667. //------------------------------------------------------------------------------
  4668.  
  4669. static void SetStorageUnitType(Environment* ev, ODDraftPermissions perms, ODStorageUnit* su, ODType suType)
  4670. {    
  4671.     if (perms == kODDPExclusiveWrite)
  4672.     {
  4673.         TempODType curType = ODGetISOStrProp(ev, su, kODPropStorageUnitType, kODISOStr, kODNULL, kODNULL);
  4674.         if (!curType || !ODISOStrEqual(curType, suType))
  4675.             ODSetISOStrProp(ev, su, kODPropStorageUnitType, kODISOStr, suType);
  4676.     }
  4677. }
  4678.  
  4679. //------------------------------------------------------------------------------
  4680. // GetStorageUnitType
  4681. //------------------------------------------------------------------------------
  4682.  
  4683. static ODISOStr GetStorageUnitType(Environment* ev, ODDraft* draft, ODID objectID)
  4684. {
  4685.     TRY
  4686.  
  4687.     TempODStorageUnit su = draft->AcquireStorageUnit(ev, objectID);
  4688.     PreserveFocus fromFocus(ev, su);
  4689.  
  4690.     return ODGetISOStrProp(ev, su, kODPropStorageUnitType, kODISOStr, kODNULL, kODNULL);
  4691.  
  4692.     CATCH_ALL
  4693.     ENDTRY
  4694.     return kODNULL;
  4695. }
  4696.  
  4697. //------------------------------------------------------------------------------
  4698. // RootPartID
  4699. //------------------------------------------------------------------------------
  4700.  
  4701. static ODID RootPartID(Environment* ev, ODDraft* draft)
  4702. {
  4703.     TempODStorageUnit draftProperties = draft->AcquireDraftProperties(ev);
  4704.     return ODGetStrongSURefProp(ev, draftProperties, kODPropRootPartSU, kODStrongStorageUnitRef);
  4705. }
  4706.  
  4707. //------------------------------------------------------------------------------
  4708. // CheckClonedObject
  4709. //------------------------------------------------------------------------------
  4710.  
  4711. SOM_Scope void  SOMLINK CMDraftCheckClonedObject(CMDraft *somSelf, Environment *ev,
  4712.         ODID fromID,
  4713.         ODID toID,
  4714.         ODID originalID)
  4715. {
  4716.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4717.     CMDraftMethodDebug("CMDraft","CheckClonedObject");
  4718.     
  4719.     ODISOStr storageUnitType = kODNULL; ODVolatile(storageUnitType);
  4720.     
  4721.     SOM_TRY
  4722.     
  4723.     storageUnitType = GetStorageUnitType(ev, somSelf, fromID);
  4724.     
  4725. #ifdef DebugClone
  4726.     somPrintf("CheckClonedObject: Type is %s\n", storageUnitType);
  4727. #endif
  4728.    
  4729.     if ( ODISOStrEqual(kODFrameObject, storageUnitType) )
  4730.     {
  4731.         _fAnyFrameCloned = kODTrue;
  4732.     }
  4733.     else if ( ODISOStrEqual(kODPartObject, storageUnitType) )
  4734.     {
  4735.         if ( (toID == originalID) && (RootPartID(ev, somSelf) == fromID) )
  4736.         {
  4737.             _fRootPartReused = kODTrue;
  4738. #ifdef DebugClone
  4739.             somPrintf("CheckClonedObject: Root part reused\n");
  4740. #endif
  4741.         }
  4742.     }
  4743.  
  4744.     SOM_CATCH_ALL
  4745.     SOM_ENDTRY
  4746.  
  4747.     ODDisposePtr(storageUnitType);
  4748. }
  4749.  
  4750. //------------------------------------------------------------------------------
  4751. // SetOriginalDraft
  4752. //------------------------------------------------------------------------------
  4753.  
  4754. static void SetOriginalDraft(Environment* ev, ODDraft* targetDraft, ODDraft* originalDraft)
  4755. {
  4756.     TempODStorageUnit draftProperties = targetDraft->AcquireDraftProperties(ev);
  4757.     ODSetULongProp(ev, draftProperties, kODPropOriginalDraft, kODULong, (ODULong) originalDraft);
  4758. }
  4759.  
  4760. //------------------------------------------------------------------------------
  4761. // GetOriginalDraft
  4762. //------------------------------------------------------------------------------
  4763. // Returns kODNULL if the original draft is unknown.  This is the case when content
  4764. // was placed in the draft without cloning.
  4765.  
  4766. static ODDraft* GetOriginalDraft(Environment* ev, ODDraft* draft)
  4767. {
  4768.     TempODStorageUnit    draftProperties = draft->AcquireDraftProperties(ev);
  4769.     return (ODDraft*)ODGetULongProp(ev, draftProperties, kODPropOriginalDraft, kODULong);
  4770. }
  4771.  
  4772. //------------------------------------------------------------------------------
  4773. // OriginalCloneKindExists
  4774. //------------------------------------------------------------------------------
  4775.  
  4776. static ODBoolean OriginalCloneKindExists(Environment* ev, ODDraft* draft)
  4777. {
  4778.     TempODStorageUnit draftProperties = draft->AcquireDraftProperties(ev);
  4779.     return draftProperties->Exists(ev, kODPropOriginalCloneKind, kODULong, 0);
  4780. }
  4781.  
  4782. //------------------------------------------------------------------------------
  4783. // SetOriginalCloneKind
  4784. //------------------------------------------------------------------------------
  4785.  
  4786. static void SetOriginalCloneKind(Environment* ev, ODDraft* targetDraft, ODCloneKind cloneKind)
  4787. {
  4788.     TempODStorageUnit draftProperties = targetDraft->AcquireDraftProperties(ev);
  4789.     ODSetULongProp(ev, draftProperties, kODPropOriginalCloneKind, kODULong, (ODULong) cloneKind);
  4790. }
  4791.  
  4792. //------------------------------------------------------------------------------
  4793. // CMDraft: GetHeap
  4794. //------------------------------------------------------------------------------
  4795.  
  4796. SOM_Scope ODMemoryHeapID  SOMLINK CMDraftGetHeap(CMDraft *somSelf, Environment *ev)
  4797. {
  4798.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4799.     CMDraftMethodDebug("CMDraft","GetHeap");
  4800.  
  4801.     return _fHeap;
  4802. }
  4803.  
  4804. //------------------------------------------------------------------------------
  4805. // CMDraft: CreateLinkIterator
  4806. //------------------------------------------------------------------------------
  4807.  
  4808. SOM_Scope ODLinkIterator*  SOMLINK CMDraftCreateLinkIterator(CMDraft *somSelf, Environment *ev)
  4809. {
  4810.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4811.     CMDraftMethodDebug("CMDraft","CreateLinkIterator");
  4812.  
  4813.     CMLinkIterator* iter = kODNULL;
  4814.     ODVolatile(iter);
  4815.     SOM_TRY
  4816.     
  4817.         iter = new CMLinkIterator();
  4818.         THROW_IF_NULL(iter, kODErrOutOfMemory);
  4819.         iter->InitCMLinkIterator(ev, somSelf);
  4820.     
  4821.     SOM_CATCH_ALL
  4822.         
  4823.         ODDeleteObject(iter);
  4824.     
  4825.     SOM_ENDTRY
  4826.     
  4827.     return (ODLinkIterator*) iter;
  4828. }
  4829.  
  4830. //------------------------------------------------------------------------------
  4831. // CMDraft: CreateLinkSourceIterator
  4832. //------------------------------------------------------------------------------
  4833.  
  4834. SOM_Scope ODLinkSourceIterator*  SOMLINK CMDraftCreateLinkSourceIterator(CMDraft *somSelf, Environment *ev)
  4835. {
  4836.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4837.     CMDraftMethodDebug("CMDraft","CreateLinkSourceIterator");
  4838.  
  4839.     CMLinkSourceIterator* iter  = kODNULL;
  4840.     ODVolatile(iter);
  4841.     SOM_TRY
  4842.     
  4843.         iter = new CMLinkSourceIterator();
  4844.         THROW_IF_NULL(iter, kODErrOutOfMemory);
  4845.         iter->InitCMLinkSourceIterator(ev, somSelf);
  4846.         
  4847.     SOM_CATCH_ALL
  4848.         
  4849.         ODDeleteObject(iter);
  4850.     
  4851.     SOM_ENDTRY
  4852.     
  4853.     return (ODLinkSourceIterator*) iter;
  4854. }
  4855.  
  4856. //------------------------------------------------------------------------------
  4857. // itoa
  4858. //------------------------------------------------------------------------------
  4859. static void itoa(ODULong number, ODSByte* cstring)
  4860. {
  4861.     ODULong    i = 0;
  4862.     
  4863.     do {
  4864.         cstring[i++] = (ODSByte) (number % 10 + '0');
  4865.     } while ((number /= 10) > 0);
  4866.     cstring[i] = '\0';
  4867.  
  4868.     ODSByte    c;
  4869.     
  4870.     ODULong    j;
  4871.     
  4872.     for (i = 0, j = strlen(cstring)-1; i < j;i++, j--) {
  4873.         c = cstring[i];
  4874.         cstring[i] = cstring[j];
  4875.         cstring[j] = c;
  4876.     }
  4877. }
  4878.  
  4879. //------------------------------------------------------------------------------
  4880. // NewCMStorageUnit
  4881. //------------------------------------------------------------------------------
  4882.  
  4883. static CMStorageUnit* NewCMStorageUnit(ODMemoryHeapID heapID)
  4884. {
  4885.     SOMClass*    cmStorageUnitClass = somNewClassReference(CMStorageUnit);
  4886.     THROW_IF_NULL( cmStorageUnitClass );
  4887.     ODULong        size = cmStorageUnitClass->somGetInstanceSize();
  4888.     ODPtr        buffer = ODNewPtr(size, heapID);
  4889.     CMStorageUnit*    cmStorageUnit = (CMStorageUnit*) cmStorageUnitClass->somRenew(buffer);
  4890.     somReleaseClassReference ( cmStorageUnitClass );
  4891.     
  4892.     return cmStorageUnit;
  4893. }
  4894.  
  4895. //------------------------------------------------------------------------------
  4896. // PurgeAllStorageUnits
  4897. //------------------------------------------------------------------------------
  4898.  
  4899. static ODULong PurgeAllStorageUnits(Environment* ev, OpenHashTable* storageUnits, IDList* idList)
  4900. {
  4901.     ODID                    id;
  4902.     ODStorageUnit*            su;
  4903.     ODULong                    runningTotal = 0;
  4904.  
  4905. // idList is used to indicate whether we need to remove linkage between id and cmObject
  4906.  
  4907.     OpenHashTableIterator    suIter(storageUnits);
  4908.     for (suIter.First(&id, &su); suIter.IsNotComplete(); suIter.Next(&id, &su)) {
  4909.         if (su->GetRefCount(ev) != 0) {
  4910.             if (idList) // purge should release CMObject, signal that by removing from idList
  4911.                 idList->Remove(id); 
  4912.             runningTotal += su->Purge(ev, 0);
  4913.         }
  4914.     }
  4915. /*
  4916.     for (suIter.First(&id, &su); suIter.IsNotComplete(); suIter.Next(&id, &su)) {
  4917.         if (su->GetRefCount(ev) == 0) {
  4918.             suIter.RemoveCurrent();
  4919.             delete su;
  4920.         }
  4921.     }
  4922. */
  4923.     // ShrinkToFit() allocates new tables first, and this aggravates
  4924.     // low memory conditions during Purge().
  4925.     // storageUnits->ShrinkToFit(/*extraSlots*/ 0);
  4926.         
  4927.     return runningTotal;
  4928. }
  4929.  
  4930. //------------------------------------------------------------------------------
  4931. // CMDraft: PartInstantiated
  4932. //------------------------------------------------------------------------------
  4933.  
  4934. SOM_Scope void  SOMLINK CMDraftPartInstantiated(CMDraft *somSelf, Environment *ev,
  4935.         ODPart* realPart)
  4936. {
  4937.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4938.     CMDraftMethodDebug("CMDraft","PartInstantiated");
  4939. }
  4940.  
  4941. //------------------------------------------------------------------------------
  4942. // CMDraft: PartDeleted
  4943. //------------------------------------------------------------------------------
  4944.  
  4945. SOM_Scope void  SOMLINK CMDraftPartDeleted(CMDraft *somSelf, Environment *ev,
  4946.         ODPart* realPart)
  4947. {
  4948.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4949.     CMDraftMethodDebug("CMDraft","PartDeleted");
  4950. }
  4951.  
  4952. //------------------------------------------------------------------------------
  4953. // CMDraft: SwapPart
  4954. //------------------------------------------------------------------------------
  4955.  
  4956. SOM_Scope void  SOMLINK CMDraftSwapPart(CMDraft *somSelf, Environment *ev,
  4957.         ODPart* part)
  4958. {
  4959.     CMDraftData *somThis = CMDraftGetData(somSelf);
  4960.     CMDraftMethodDebug("CMDraft","SwapPart");
  4961.  
  4962.     SOM_TRY
  4963.         OpenHashTableIterator     i(_fPersistentObjects);
  4964.         ODStorageUnitID            id;
  4965.         ODPersistentObject*        object;
  4966.         ODFrame*                frame;
  4967.  
  4968.         somSelf->Externalize(ev);
  4969.         
  4970.         for (i.First(&id, &object); i.IsNotComplete(); i.Next(&id, &object)) {
  4971.             if ( strcmp(object->somGetClassName(), kFrameClassName)==0 ) {
  4972.                 frame = (ODFrame*)object;
  4973.                 if ( frame->IsSubframe(ev) == kODFalse )
  4974.                     frame->PrepareToSwap(ev, part);
  4975.             }
  4976.         }
  4977.     SOM_CATCH_ALL
  4978.     SOM_ENDTRY
  4979. }
  4980.