home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / ODF / Framewrk / FWPart / Sources / FWLnkMgr.cpp < prev    next >
Encoding:
Text File  |  1996-08-16  |  26.5 KB  |  851 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWLnkMgr.cpp
  4. //    Release Version:    $ ODF 1 $
  5. //
  6. //    Copyright:            (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFrameW.hpp"
  11.  
  12. #ifndef FWLNKMGR_H
  13. #include "FWLnkMgr.h"
  14. #endif
  15.  
  16. // ----- Framework Includes -----
  17.  
  18. #ifndef FWPART_H
  19. #include "FWPart.h"
  20. #endif
  21.  
  22. #ifndef FWPRESEN_H
  23. #include "FWPresen.h"
  24. #endif
  25.  
  26. #ifndef FWLNKITE_H
  27. #include "FWLnkIte.h"
  28. #endif
  29.  
  30. #ifndef FWUTIL_H
  31. #include "FWUtil.h"
  32. #endif
  33.  
  34. #ifndef FWCLNINF_H
  35. #include "FWClnInf.h"
  36. #endif
  37.  
  38. #ifndef FWLNKCMD_H
  39. #include "FWLnkCmd.h"
  40. #endif
  41.  
  42. // ----- Foundation Includes -----
  43.  
  44. #ifndef FWPRIDEB_H
  45. #include "FWPriDeb.h"
  46. #endif
  47.  
  48. #ifndef FWMEMMGR_H
  49. #include "FWMemMgr.h"
  50. #endif
  51.  
  52. #ifndef FWBARRAY_H
  53. #include "FWBArray.h"
  54. #endif
  55.  
  56. // ----- OS Includes -----
  57.  
  58. #ifndef FWTIME_H
  59. #include "FWTime.h"
  60. #endif
  61.  
  62. // ----- OpenDoc Includes -----
  63.  
  64. #ifndef SOM_Module_OpenDoc_StdProps_defined
  65. #include <StdProps.xh>
  66. #endif
  67.  
  68. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  69. #include <StdTypes.xh>
  70. #endif
  71.  
  72. #ifndef SOM_ODStorageUnit_xh
  73. #include <StorageU.xh>
  74. #endif
  75.  
  76. #ifndef SOM_ODSession_xh
  77. #include <ODSessn.xh>
  78. #endif
  79.  
  80. #ifndef SOM_ODDraft_xh
  81. #include <Draft.xh>
  82. #endif
  83.  
  84. #ifndef SOM_ODClipboard_xh
  85. #include <Clipbd.xh>
  86. #endif
  87.  
  88. #ifndef SOM_ODLink_xh
  89. #include <Link.xh>
  90. #endif
  91.  
  92. #ifndef SOM_ODLinkSpec_xh
  93. #include <LinkSpec.xh>
  94. #endif
  95.  
  96. #ifndef SOM_ODLinkSource_xh
  97. #include <LinkSrc.xh>
  98. #endif
  99.  
  100. //========================================================================================
  101. //    Runtime information
  102. //========================================================================================
  103.  
  104. #ifdef FW_BUILD_MAC
  105. #pragma segment odflinking
  106. #endif
  107.  
  108. FW_DEFINE_AUTO(FW_CLinkManager)
  109.  
  110. //========================================================================================
  111. //    class FW_CLinkManager
  112. //========================================================================================
  113.  
  114. //---------------------------------------------------------------------------------------
  115. //    FW_CLinkManager constructor
  116. //---------------------------------------------------------------------------------------
  117.  
  118. FW_CLinkManager::FW_CLinkManager(Environment* ev, FW_CPart* thePart) :
  119.     fPart(thePart),
  120.     fPendingClipboardLink(NULL),
  121.     fPendingDropLink(NULL),
  122.     fSourceLinkList(NULL),
  123.     fDestLinkList(NULL)
  124. {
  125. FW_UNUSED(ev);
  126.     FW_END_CONSTRUCTOR
  127. }
  128.  
  129. //---------------------------------------------------------------------------------------
  130. //    FW_CLinkManager destructor
  131. //---------------------------------------------------------------------------------------
  132.  
  133. FW_CLinkManager::~FW_CLinkManager()
  134. {
  135.     FW_START_DESTRUCTOR
  136.     
  137.     delete fDestLinkList;
  138.     fDestLinkList = NULL;
  139.  
  140.     delete fSourceLinkList;
  141.     fSourceLinkList = NULL;
  142. }
  143.  
  144. //---------------------------------------------------------------------------------------
  145. //    FW_CLinkManager::RemoveAllLinks
  146. //---------------------------------------------------------------------------------------
  147.  
  148. void FW_CLinkManager::RemoveAllLinks(Environment* ev)
  149. {
  150. FW_UNUSED(ev);
  151.     // ----- Delete source links -----
  152.     if (fSourceLinkList)
  153.     {
  154.         FW_CLinkSource* link;
  155.         while ((link = fSourceLinkList->First()) != NULL)
  156.         {
  157.             fSourceLinkList->Remove(link);
  158.             delete link;
  159.         }        
  160.     }
  161.     
  162.     // ----- Delete destination links -----
  163.     if (fDestLinkList)
  164.     {
  165.         FW_CLinkDestination* link;
  166.         while ((link = fDestLinkList->First()) != NULL)
  167.         {
  168.             fDestLinkList->Remove(link);
  169.             delete link;
  170.         }        
  171.     }
  172. }
  173.  
  174. //---------------------------------------------------------------------------------------
  175. //    FW_CLinkManager::AddToSourceLinkList
  176. //---------------------------------------------------------------------------------------
  177.  
  178. void FW_CLinkManager::AddToSourceLinkList(Environment* ev, FW_CLinkSource* linkSource)
  179. {
  180. FW_UNUSED(ev);
  181.     if (fSourceLinkList == NULL)
  182.         fSourceLinkList = FW_NEW(FW_TOrderedCollection<FW_CLinkSource>, ());
  183.     
  184.     fSourceLinkList->AddLast(linkSource);
  185. }
  186.  
  187. //---------------------------------------------------------------------------------------
  188. //    FW_CLinkManager::AddToDestLinkList
  189. //---------------------------------------------------------------------------------------
  190.  
  191. void FW_CLinkManager::AddToDestLinkList(Environment* ev, FW_CLinkDestination* linkDest)
  192. {
  193. FW_UNUSED(ev);
  194.     if (fDestLinkList == NULL)
  195.         fDestLinkList = FW_NEW(FW_TOrderedCollection<FW_CLinkDestination>, ());
  196.     
  197.     fDestLinkList->AddLast(linkDest);
  198. }
  199.  
  200. //---------------------------------------------------------------------------------------
  201. //    FW_CLinkManager::BreakSourceLink
  202. //---------------------------------------------------------------------------------------
  203. void FW_CLinkManager::BreakSourceLink(Environment* ev, FW_CLinkSource* linkSource)
  204. {
  205.     linkSource->BreakLink(ev);
  206.     this->RemoveFromSourceLinkList(ev, linkSource);
  207. }
  208.  
  209. //---------------------------------------------------------------------------------------
  210. //    FW_CLinkManager::BreakDestinationLink
  211. //---------------------------------------------------------------------------------------
  212. void FW_CLinkManager::BreakDestinationLink(Environment* ev, FW_CLinkDestination* linkDest)
  213. {
  214.     linkDest->BreakLink(ev);
  215.     this->RemoveFromDestLinkList(ev, linkDest);
  216. }
  217.  
  218. //---------------------------------------------------------------------------------------
  219. //    FW_CLinkManager::CountSourceLinks
  220. //---------------------------------------------------------------------------------------
  221.  
  222. unsigned long FW_CLinkManager::CountSourceLinks(Environment* ev) const
  223. {
  224. FW_UNUSED(ev);
  225.     if (fSourceLinkList)
  226.         return fSourceLinkList->Count();
  227.  
  228.     return 0;
  229. }
  230.  
  231. //---------------------------------------------------------------------------------------
  232. //    FW_CLinkManager::CountDestinationLinks
  233. //---------------------------------------------------------------------------------------
  234.  
  235. unsigned long FW_CLinkManager::CountDestinationLinks(Environment* ev) const
  236. {
  237. FW_UNUSED(ev);
  238.     if (fDestLinkList)
  239.         return fDestLinkList->Count();
  240.  
  241.     return 0;
  242. }
  243.  
  244. //---------------------------------------------------------------------------------------
  245. //    FW_CLinkManager::CreateLink
  246. //---------------------------------------------------------------------------------------
  247.  
  248. ODLinkSource* FW_CLinkManager::CreateLink(Environment* ev, ODByteArray* data)
  249. {
  250.     ODLinkSource* odLinkSource = NULL;
  251.     ODUpdateID updateID = *((ODUpdateID*)(data->_buffer));
  252.  
  253.     // The link spec is either on the clipboard or saved from a Drag&Drop operation.
  254.     // Determine which one to use by checking the ids
  255.     FW_Boolean linkSpecOnClipboard = true;
  256.  
  257.     // --- Check the clipboard link spec first, since it's the most likely candidate ---
  258.     FW_CLinkSource* pendingLink = this->GetPendingClipboardLink(ev);
  259.     if (pendingLink && (pendingLink->GetPendingID(ev) == updateID))
  260.     {
  261.         // Get the link if it already exists
  262.         odLinkSource = pendingLink->GetODLinkSource(ev);
  263.     }
  264.     else    // check for a Drag&Drop link spec
  265.     {
  266.         pendingLink = this->GetPendingDropLink(ev);
  267.         FW_ASSERT(pendingLink != NULL);
  268.         FW_ASSERT(pendingLink->GetPendingID(ev) == updateID);
  269.         linkSpecOnClipboard = false;
  270.  
  271.         // The Drag&Drop link spec is only good for creating one link
  272.         this->SetPendingDropLink(ev, NULL);
  273.     }
  274.  
  275.     if (odLinkSource == NULL)        // link does not yet exist
  276.     {
  277.         FW_CFrame* frame = fPart->GetLastActiveFrame(ev);    /* ??? */
  278.         FW_CPrivCreateLinkSourceCommand* cmd = FW_NEW(FW_CPrivCreateLinkSourceCommand, (ev, frame, this, pendingLink));
  279.  
  280.         FW_TRY
  281.         {
  282.             if (cmd->Execute(ev))
  283.             {
  284.                 odLinkSource = cmd->GetODLinkSource(ev);
  285.                 // Don't DeletePendingClipboardLink, because more links may be created from it
  286.             }
  287.             // else cmd has been deleted
  288.         }
  289.         FW_CATCH_BEGIN
  290.         FW_CATCH_EVERYTHING() 
  291.         {
  292.             // don't re-throw; odLinkSource remains NULL
  293.         }
  294.         FW_CATCH_END
  295.     }
  296.     else
  297.     {
  298.         pendingLink->ContentUpdated(ev, kODUnknownUpdate, TRUE);
  299.         odLinkSource->Acquire(ev);
  300.     }
  301.     
  302.     return odLinkSource;
  303. }
  304.  
  305. //---------------------------------------------------------------------------------------
  306. //    FW_CLinkManager::DeletePendingClipboardLink
  307. //---------------------------------------------------------------------------------------
  308.  
  309. void FW_CLinkManager::DeletePendingClipboardLink(Environment* ev)
  310. {
  311.     if (fPendingClipboardLink != NULL)
  312.     {
  313.         ODClipboard* clipboard = fPart->GetSession(ev)->GetClipboard(ev);
  314.         
  315.         if (fPendingClipboardLink->GetPendingID(ev) == clipboard->GetUpdateID(ev)) 
  316.         {
  317.             ODStorageUnit* clipboardSU = clipboard->GetContentStorageUnit(ev);
  318.             if (clipboardSU->Exists(ev, kODPropLinkSpec, (ODValueType) NULL, 0) == TRUE) 
  319.             {
  320.                 clipboardSU->Focus(ev, kODPropLinkSpec, kODPosUndefined, (ODValueType) NULL, 0, kODPosUndefined);
  321.                 clipboardSU->Remove(ev);
  322.             }
  323.         }
  324.         
  325.         if (fPendingClipboardLink->IsPending(ev))    // CreateLink was never called
  326.             delete fPendingClipboardLink;
  327.  
  328.         fPendingClipboardLink = NULL;
  329.     }
  330. }
  331.  
  332. //---------------------------------------------------------------------------------------
  333. //    FW_CLinkManager::DoChangeLinkStatus
  334. //---------------------------------------------------------------------------------------
  335.  
  336. void FW_CLinkManager::DoChangeLinkStatus(Environment* ev, ODFrame* odFrame)
  337. {
  338. FW_UNUSED(ev);
  339.     // Embedding parts should override to call ODFrame::ChangeLinkStatus for any 
  340.     // embedded frames that are involved in a link when a link is created, broken, moved, etc.
  341.     // odFrame is the frame whose link status has changed.
  342.  
  343.   FW_UNUSED(odFrame); 
  344. }
  345.  
  346. //---------------------------------------------------------------------------------------
  347. //    FW_CLinkManager::DoUpdateLinks
  348. //---------------------------------------------------------------------------------------
  349.  
  350. void FW_CLinkManager::DoUpdateLinks(Environment* ev,
  351.                                     ODFrame* odEmbeddedFrame,
  352.                                     ODUpdateID updateID)
  353. {
  354.     // An embedded frame has changed. (Formerly named EmbeddedFrameUpdated)
  355.     // If odEmbeddedFrame is involved in one of my link sources, update the link with new data.
  356.  
  357.     if (this->CountSourceLinks(ev) > 0)
  358.     {
  359.         FW_CLinkMgrLinkSourceIterator iter(this);
  360.         for (FW_CLinkSource* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  361.         {
  362.             if (link->HasEmbeddedFrame(ev, odEmbeddedFrame))
  363.             {
  364.                 link->ContentUpdated(ev, updateID, FALSE);
  365.                 break;
  366.             }
  367.         }
  368.     }
  369. }
  370.  
  371. //---------------------------------------------------------------------------------------
  372. //    FW_CLinkManager::EditInLinkAttempted
  373. //---------------------------------------------------------------------------------------
  374.  
  375. FW_Boolean FW_CLinkManager::EditInLinkAttempted(Environment* ev, ODFrame* odFrame)
  376. {
  377. FW_UNUSED(ev);
  378. FW_UNUSED(odFrame);
  379.     // Not yet implemented
  380.     return FALSE;
  381. }
  382.  
  383. //---------------------------------------------------------------------------------------
  384. //    FW_CLinkManager::ODtoFWLinkSource
  385. //---------------------------------------------------------------------------------------
  386.  
  387. FW_CLinkSource* FW_CLinkManager::ODtoFWLinkSource(Environment* ev, ODLinkSource* odLinkSource) const
  388. {
  389.     FW_TOrderedCollectionIterator<FW_CLinkSource> iter(fSourceLinkList);
  390.     for (FW_CLinkSource* link = iter.First(); iter.IsNotComplete(); link = iter.Next()) 
  391.     {
  392.         if (odLinkSource->IsEqualTo(ev, link->GetODLinkSource(ev)))
  393.             return link;
  394.     }
  395.     return NULL;
  396. }
  397.  
  398. //---------------------------------------------------------------------------------------
  399. //    FW_CLinkManager::ODtoFWLink
  400. //---------------------------------------------------------------------------------------
  401.  
  402. FW_CLinkDestination* FW_CLinkManager::ODtoFWLink(Environment* ev, ODLink* odLink) const
  403. {
  404.     FW_TOrderedCollectionIterator<FW_CLinkDestination> iter(fDestLinkList);
  405.     for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  406.     {
  407.         if (odLink->IsEqualTo(ev, link->GetODLink(ev)))
  408.             return link;
  409.     }
  410.     return NULL;
  411. }
  412.  
  413. //---------------------------------------------------------------------------------------
  414. //    FW_CLinkManager::RevealLink
  415. //---------------------------------------------------------------------------------------
  416.  
  417. void FW_CLinkManager::RevealLink(Environment* ev, ODLinkSource* odLinkSource)
  418. {
  419. FW_UNUSED(ev);
  420. FW_UNUSED(odLinkSource);
  421.     FW_DEBUG_MESSAGE("RevealLink: Not Yet Implemented");
  422. }
  423.  
  424. //---------------------------------------------------------------------------------------
  425. //    FW_CLinkManager::RemoveFromSourceLinkList
  426. //---------------------------------------------------------------------------------------
  427.  
  428. void FW_CLinkManager::RemoveFromSourceLinkList(Environment* ev, FW_CLinkSource* linkSource)
  429. {
  430.     fSourceLinkList->Remove(linkSource);
  431.  
  432.     if (linkSource == fPendingClipboardLink)
  433.         this->DeletePendingClipboardLink(ev);
  434.     
  435.     if (fSourceLinkList->Count() == 0)
  436.     {
  437.         delete fSourceLinkList;
  438.         fSourceLinkList = NULL;
  439.     }
  440. }
  441.  
  442. //---------------------------------------------------------------------------------------
  443. //    FW_CLinkManager::RemoveFromDestLinkList
  444. //---------------------------------------------------------------------------------------
  445.  
  446. void FW_CLinkManager::RemoveFromDestLinkList(Environment* ev, FW_CLinkDestination* linkDest)
  447. {
  448. FW_UNUSED(ev);
  449.     fDestLinkList->Remove(linkDest);
  450.     
  451.     if (fDestLinkList->Count() == 0)
  452.     {
  453.         delete fDestLinkList;
  454.         fDestLinkList = NULL;
  455.     }
  456. }
  457.  
  458. //---------------------------------------------------------------------------------------
  459. //    FW_CLinkManager::RestoreSourceLink
  460. //---------------------------------------------------------------------------------------
  461. void FW_CLinkManager::RestoreSourceLink(Environment* ev, FW_CLinkSource* linkSource)
  462. {
  463.     this->AddToSourceLinkList(ev, linkSource);
  464.     linkSource->RestoreLink(ev, fPart);
  465.     linkSource->PrivLinkEstablished(ev);
  466. }
  467.  
  468. //---------------------------------------------------------------------------------------
  469. //    FW_CLinkManager::RestoreDestinationLink
  470. //---------------------------------------------------------------------------------------
  471. void FW_CLinkManager::RestoreDestinationLink(Environment* ev, FW_CLinkDestination* linkDest)
  472. {
  473.     this->AddToDestLinkList(ev, linkDest);
  474.     linkDest->RestoreLink(ev, fPart);
  475.     linkDest->PrivEstablishLink(ev);
  476. }
  477.  
  478. //---------------------------------------------------------------------------------------
  479. //    FW_CLinkManager::PasteWithLink
  480. //---------------------------------------------------------------------------------------
  481. FW_CLinkDestination* FW_CLinkManager::PasteWithLink(Environment* ev, ODStorageUnit* storageUnit, 
  482.                                                     ODPasteAsResult& pasteAsResult,
  483.                                                     FW_CFrame* frame,
  484.                                                     FW_EStorageKinds storageKind)
  485. {
  486.     FW_CLinkDestination* linkDest = NULL;
  487.     ODLinkSpec* linkSpec = NULL;
  488.     ODLink* odLink = NULL;
  489.     ODDraft* draft = fPart->GetDraft(ev);
  490.     if (!storageUnit->Exists(ev, kODPropLinkSpec, (ODValueType)NULL, 0))
  491.         return linkDest;
  492.  
  493.     FW_CPrivCreateLinkCommand* cmd = NULL;
  494.     FW_VOLATILE(cmd);
  495.     FW_VOLATILE(linkSpec);
  496.     FW_VOLATILE(odLink);
  497.  
  498.     FW_TRY
  499.     {
  500.         linkSpec = draft->CreateLinkSpec(ev, NULL, NULL);
  501.  
  502.         storageUnit->Focus(ev, kODPropLinkSpec, kODPosUndefined, (ODValueType)NULL, 0, kODPosUndefined);
  503.         linkSpec->ReadLinkSpec(ev, storageUnit);
  504.  
  505.         // ---- Write a transaction to the Undo history ----
  506.         cmd = FW_NEW(FW_CPrivCreateLinkCommand, (ev, frame, this, storageKind == FW_kClipboardStorage));
  507.         cmd->Execute(ev);
  508.  
  509.         // ---- Establish the Link ----
  510.         odLink = draft->AcquireLink(ev, (ODStorageUnitID)0, linkSpec);    // use linkSpec to retrieve the link
  511.  
  512.         if (odLink)
  513.         {
  514.             // --- Embed or incorporate the link ---
  515.             linkDest = this->PrivMakeLink(ev, odLink, pasteAsResult, frame->GetPresentation(ev));
  516.             cmd->SetLink(ev, linkDest);
  517.             odLink->Release(ev);    // to balance AcquireLink
  518.         }
  519.     }
  520.     FW_CATCH_BEGIN
  521.     FW_CATCH_EVERYTHING()
  522.     {
  523.         if (linkSpec)
  524.             delete linkSpec;
  525.         if (odLink)
  526.             odLink->Release(ev);
  527.         if (cmd)
  528.             delete cmd;
  529.         FW_THROW_SAME();
  530.     }
  531.     FW_CATCH_END
  532.  
  533.     if (linkSpec)
  534.         delete linkSpec;
  535.                     
  536.     return linkDest;
  537. }
  538.  
  539. //---------------------------------------------------------------------------------------
  540. //    FW_CLinkManager::PrivMakeLink
  541. //---------------------------------------------------------------------------------------
  542. FW_CLinkDestination* FW_CLinkManager::PrivMakeLink(Environment* ev,
  543.                                                    ODLink* odLink,
  544.                                                    ODPasteAsResult& pasteAsResult,
  545.                                                    FW_CPresentation* presentation)
  546. {
  547.     FW_CLinkDestination* linkDest = NULL;
  548.     FW_VOLATILE(linkDest);
  549.  
  550.     FW_TRY
  551.     {
  552.         ODLinkInfo linkInfo;
  553.         linkInfo.change = kODUnknownUpdate;            // not yet updated
  554.         FW_CTime time = FW_CTime::GetCurrentTime();
  555.         linkInfo.creationTime = time.GetTime();
  556.         linkInfo.changeTime = linkInfo.creationTime;
  557.         linkInfo.autoUpdate = pasteAsResult.autoUpdateSetting;
  558.         linkInfo.kind = NULL;
  559.  
  560.         linkDest = this->NewLinkDestination(ev, odLink, &linkInfo, presentation);
  561.         this->AddToDestLinkList(ev, linkDest);
  562.         linkDest->SavePasteAsSettings(ev, pasteAsResult);
  563.  
  564.         linkDest->Register(ev, fPart);    // causes LinkUpdated to be called
  565.         if (linkDest->GetUpdateID(ev) != kODUnknownUpdate)    // LinkUpdated succeeded
  566.             linkDest->PrivEstablishLink(ev);
  567.     }
  568.     FW_CATCH_BEGIN
  569.     FW_CATCH_EVERYTHING()
  570.     {
  571.         if (linkDest)
  572.         {
  573.             this->RemoveFromDestLinkList(ev, linkDest);
  574.             delete linkDest;
  575.         }
  576.         FW_THROW_SAME();
  577.     }
  578.     FW_CATCH_END
  579.  
  580.     return linkDest;
  581. }
  582.  
  583. //---------------------------------------------------------------------------------------
  584. //    FW_CLinkManager::ExternalizeLinks
  585. //---------------------------------------------------------------------------------------
  586. void FW_CLinkManager::ExternalizeLinks(Environment* ev, ODStorageUnit* su,
  587.                                        FW_CCloneInfo* cloneInfo)
  588. {
  589.     // If we're cloning into a link, OpenDoc will return an invalid ID for each link 
  590.     // when we try to clone it. So don't try to clone it.
  591.     if (cloneInfo != NULL && cloneInfo->GetCloneKind(ev) == kODCloneToLink)
  592.         return;
  593.  
  594.     //--- Write out the source links ---
  595.     if (this->CountSourceLinks(ev) > 0)
  596.     {
  597.         //-- Make sure the value is present in the SU --
  598.         FW_SUForceFocus(ev, su, kODPropContents, this->GetSourceLinkFormat(ev));
  599.  
  600.         FW_CLinkMgrLinkSourceIterator iter(this);
  601.         for (FW_CLinkSource* slink = iter.First(); iter.IsNotComplete(); slink = iter.Next())
  602.         {
  603.             slink->ExternalizeLink(ev, su, cloneInfo);
  604.         }
  605.     }
  606.  
  607.     //--- Write out the destination links ---
  608.     if (this->CountDestinationLinks(ev) > 0)
  609.     {
  610.         //-- Make sure the value is present in the SU --
  611.         FW_SUForceFocus(ev, su, kODPropContents, this->GetDestLinkFormat(ev));
  612.  
  613.         FW_CLinkMgrLinkDestIterator iter(this);
  614.         for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  615.         {
  616.             link->ExternalizeLink(ev, su, cloneInfo);
  617.         }
  618.     }
  619. }
  620.  
  621. //---------------------------------------------------------------------------------------
  622. //    FW_CLinkManager::InternalizeLinks
  623. //---------------------------------------------------------------------------------------
  624. void FW_CLinkManager::InternalizeLinks(Environment* ev, ODStorageUnit* storageUnit)
  625. {
  626.     unsigned long valueSize;
  627.  
  628.     if (FW_SUExistsThenFocus(ev, storageUnit, kODPropContents, this->GetSourceLinkFormat(ev)))
  629.     {
  630.         valueSize = storageUnit->GetSize(ev);
  631.         while (storageUnit->GetOffset(ev) < valueSize)
  632.         {
  633.             this->PrivInternalizeOneSourceLink(ev, storageUnit);
  634.         }
  635.     }
  636.  
  637.     if (FW_SUExistsThenFocus(ev, storageUnit, kODPropContents, this->GetDestLinkFormat(ev)))
  638.     {
  639.         valueSize = storageUnit->GetSize(ev);
  640.         while (storageUnit->GetOffset(ev) < valueSize)
  641.         {
  642.             this->PrivInternalizeOneDestLink(ev, storageUnit);
  643.         }
  644.     }
  645. }
  646.  
  647. //---------------------------------------------------------------------------------------
  648. //    FW_CLinkManager::PrivInternalizeOneSourceLink
  649. //---------------------------------------------------------------------------------------
  650. void FW_CLinkManager::PrivInternalizeOneSourceLink(Environment* ev, ODStorageUnit* storageUnit)
  651. {
  652.     // Storage unit must be focused to correct property and value (linkSourceFormat)
  653.     ODStorageUnitRef suRef;
  654.     FW_CByteArray byteArray;
  655.     long version;
  656.  
  657.     //--- First check the link version number ---
  658.     storageUnit->GetValue(ev, sizeof(long), byteArray);
  659.     byteArray.CopyBuffer(&version, sizeof(long));
  660.     FW_ASSERT(version == FW_kLinkVersionNumber);
  661.  
  662.     //--- Read the link reference and validate it ---
  663.     storageUnit->GetValue(ev, sizeof(ODStorageUnitRef), byteArray);
  664.     byteArray.CopyBuffer(&suRef, sizeof(ODStorageUnitRef));
  665.     if (storageUnit->IsValidStorageUnitRef(ev, suRef))
  666.     {
  667.         ODID linkID = storageUnit->GetIDFromStorageUnitRef(ev, suRef);
  668.         this->InternalizeSourceLink(ev, linkID, storageUnit);
  669.     }
  670. }
  671.  
  672. //---------------------------------------------------------------------------------------
  673. //    FW_CLinkManager::PrivInternalizeOneDestLink
  674. //---------------------------------------------------------------------------------------
  675. void FW_CLinkManager::PrivInternalizeOneDestLink(Environment* ev, ODStorageUnit* storageUnit)
  676. {
  677.     // Storage unit must be focused to correct property and value (linkDestFormat)
  678.     ODStorageUnitRef suRef;
  679.     FW_CByteArray byteArray;
  680.     long version;
  681.  
  682.     //--- First check the link version number ---
  683.     storageUnit->GetValue(ev, sizeof(long), byteArray);
  684.     byteArray.CopyBuffer(&version, sizeof(long));
  685.     FW_ASSERT(version == FW_kLinkVersionNumber);
  686.  
  687.     //--- Read the link reference and validate it ---
  688.     storageUnit->GetValue(ev, sizeof(ODStorageUnitRef), byteArray);
  689.     byteArray.CopyBuffer(&suRef, sizeof(ODStorageUnitRef));
  690.     if (storageUnit->IsValidStorageUnitRef(ev, suRef))
  691.     {
  692.         ODID linkID = storageUnit->GetIDFromStorageUnitRef(ev, suRef);
  693.         this->InternalizeDestLink(ev, linkID, storageUnit);
  694.     }
  695. }
  696.  
  697. //---------------------------------------------------------------------------------------
  698. //    FW_CLinkManager::DoInternalizeOneSourceLink
  699. //---------------------------------------------------------------------------------------
  700. FW_CLinkSource* FW_CLinkManager::DoInternalizeOneSourceLink(Environment* ev, 
  701.                                                              ODStorageUnit* storageUnit,
  702.                                                              ODUpdateID updateID)
  703. {
  704.     // Override to:
  705.     //    - read part-specific link source data from the storageUnit
  706.     //    - create and return a link source object
  707.  
  708. FW_UNUSED(ev);
  709. FW_UNUSED(storageUnit); 
  710. FW_UNUSED(updateID);
  711.     return NULL;
  712. }
  713.  
  714. //---------------------------------------------------------------------------------------
  715. //    FW_CLinkManager::DoInternalizeOneDestLink
  716. //---------------------------------------------------------------------------------------
  717. FW_CLinkDestination* FW_CLinkManager::DoInternalizeOneDestLink(Environment* ev, ODStorageUnit* storageUnit,
  718.                                                              ODLink* odLink, ODLinkInfo* linkInfo)
  719. {
  720.     // Override to:
  721.     //    - read part-specific link data from the storageUnit
  722.     //    - create and return a link destination object
  723.  
  724. FW_UNUSED(ev);
  725. FW_UNUSED(storageUnit); 
  726. FW_UNUSED(odLink); 
  727. FW_UNUSED(linkInfo); 
  728.     return NULL;
  729. }
  730.  
  731. //----------------------------------------------------------------------------------------
  732. //    FW_CLinkManager::RegisterLinks
  733. //----------------------------------------------------------------------------------------
  734. void FW_CLinkManager::RegisterLinks(Environment* ev)
  735. {
  736.     if (this->CountDestinationLinks(ev) > 0)
  737.     {
  738.         FW_CLinkMgrLinkDestIterator iter(this);
  739.         for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  740.         {
  741.             link->Register(ev, fPart);    // auto-update link will have its LinkUpdated method called
  742.         }
  743.     }
  744. }
  745.  
  746. //----------------------------------------------------------------------------------------
  747. //    FW_CLinkManager::InternalizeSourceLink
  748. //----------------------------------------------------------------------------------------
  749. void FW_CLinkManager::InternalizeSourceLink(Environment* ev, ODID linkID,
  750.                                             ODStorageUnit* storageUnit)
  751. {
  752.     // Storage unit must be focused to correct property and value (linkSourceFormat)
  753.     // The linkID must be valid
  754.     ODUpdateID updateID;
  755.     FW_CByteArray byteArray;
  756.     ODDraft* myDraft = fPart->GetDraft(ev);
  757.  
  758.     //-- Read the link source data, using the validated ID
  759.     ODLinkSource* odLinkSource = myDraft->AcquireLinkSource(ev, linkID);
  760.     storageUnit->GetValue(ev, sizeof(ODUpdateID), byteArray);
  761.     byteArray.CopyBuffer(&updateID, sizeof(ODUpdateID));
  762.  
  763.     //-- Read the link source data (part-specific)
  764.     FW_CLinkSource* linkSource = this->DoInternalizeOneSourceLink(ev, storageUnit, updateID);
  765.     if (linkSource)
  766.     {
  767.         //-- Ensure the link source object references our part as the source of the link
  768.         odLinkSource->SetSourcePart(ev, fPart->GetStorageUnit(ev));
  769.  
  770.         linkSource->SetODLinkSource(ev, odLinkSource);
  771.         this->AddToSourceLinkList(ev, linkSource);
  772.     }
  773.  
  774.     odLinkSource->Release(ev);    // to balance AcquireLinkSource above
  775. }
  776.  
  777. //----------------------------------------------------------------------------------------
  778. //    FW_CLinkManager::InternalizeDestLink
  779. //----------------------------------------------------------------------------------------
  780. void FW_CLinkManager::InternalizeDestLink(Environment* ev, ODID linkID,
  781.                                           ODStorageUnit* storageUnit)
  782. {
  783.     // Storage unit must be focused to correct property and value (linkDestFormat)
  784.     // The linkID must be valid
  785.     ODLinkInfo linkInfo;
  786.     ODPasteAsResult embedInfo;
  787.     FW_CByteArray byteArray;
  788.     ODDraft* myDraft = fPart->GetDraft(ev);
  789.  
  790.     //-- Acquire the link, using the validated ID
  791.     ODLink* odLink = myDraft->AcquireLink(ev, linkID, NULL);
  792.  
  793.     //--- Read the link info and kind ---
  794.     storageUnit->GetValue(ev, sizeof(ODLinkInfo), byteArray);
  795.     byteArray.CopyBuffer(&linkInfo, sizeof(ODLinkInfo));
  796.     // Allocate space for the kind string (its size is in linkInfo.kind)
  797.     ODType kind = (ODType) FW_CMemoryManager::AllocateBlock((ODULong)linkInfo.kind);
  798.     storageUnit->GetValue(ev, (ODULong)linkInfo.kind, byteArray);
  799.     byteArray.CopyBuffer((void*)kind, (ODULong)linkInfo.kind);
  800.     linkInfo.kind = NULL;
  801.  
  802.     //--- Read the Paste As info, if there is any ---
  803.     FW_Boolean hasEmbedInfo;
  804.     storageUnit->GetValue(ev, sizeof(FW_Boolean), byteArray);
  805.     byteArray.CopyBuffer(&hasEmbedInfo, sizeof(FW_Boolean));
  806.     if (hasEmbedInfo)
  807.     {
  808.         // Read embedInfo struct
  809.         storageUnit->GetValue(ev, sizeof(ODPasteAsResult), byteArray);
  810.         byteArray.CopyBuffer(&embedInfo, sizeof(ODPasteAsResult));
  811.         // Get selectedKind string from link info
  812.         embedInfo.selectedKind = kind;
  813.         // Read translateKind string, if there is one
  814.         if (embedInfo.translateKind != 0)
  815.         {
  816.             kind = (ODType) FW_CMemoryManager::AllocateBlock((ODULong)embedInfo.translateKind);
  817.             storageUnit->GetValue(ev, (ODULong)embedInfo.translateKind, byteArray);
  818.             byteArray.CopyBuffer((void*)kind, (ODULong)embedInfo.translateKind);
  819.             embedInfo.translateKind = kind;
  820.         }
  821.         // Read editor string, if there is one
  822.         if (embedInfo.editor != 0)
  823.         {
  824.             ODEditor temp = (ODEditor) FW_CMemoryManager::AllocateBlock((ODULong)embedInfo.editor);;
  825.             storageUnit->GetValue(ev, (ODULong)embedInfo.editor, byteArray);
  826.             byteArray.CopyBuffer((void*)temp, (ODULong)embedInfo.editor);
  827.             embedInfo.editor = temp;
  828.         }
  829.     }
  830.     else    // SU contains no embed info; initialize fields in the struct to reflect this
  831.     {
  832.         embedInfo.mergeSetting = kODTrue;    // no embedding
  833.         embedInfo.selectedKind = kind;
  834.         embedInfo.translateKind = NULL;
  835.         embedInfo.editor = NULL;
  836.     }
  837.  
  838.     //-- Read the part-specific link data
  839.     FW_CLinkDestination* destLink = this->DoInternalizeOneDestLink(ev, storageUnit, odLink, &linkInfo);
  840.     if (destLink)
  841.     {
  842.         //-- Establish the link
  843.         this->AddToDestLinkList(ev, destLink);
  844.         destLink->SavePasteAsSettings(ev, embedInfo);
  845.         destLink->PrivEstablishLink(ev);
  846.     }
  847.  
  848.     odLink->Release(ev);    // to balance AcquireLink above
  849. }
  850.  
  851.