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 Development Framework / ODFDev / ODF / Framewrk / FWPart / FWLnkDst.cpp < prev    next >
Encoding:
Text File  |  1996-09-17  |  15.7 KB  |  514 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWLnkDst.cpp
  4. //    Release Version:    $ ODF 2 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFrameW.hpp"
  11.  
  12. #ifndef FWLNKDST_H
  13. #include "FWLnkDst.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 FWCLNINF_H
  31. #include "FWClnInf.h"
  32. #endif
  33.  
  34. #ifndef FWINTER_H
  35. #include "FWInter.h"
  36. #endif
  37.  
  38. #ifndef FWCLPCMD_H
  39. #include "FWClpCmd.h"
  40. #endif
  41.  
  42. #ifndef FWLNKCMD_H
  43. #include "FWLnkCmd.h"
  44. #endif
  45.  
  46. #ifndef FWSESION_H
  47. #include "FWSesion.h"
  48. #endif
  49.  
  50. // ----- Foundation Includes -----
  51.  
  52. #ifndef FWPRIDEB_H
  53. #include "FWPriDeb.h"
  54. #endif
  55.  
  56. #ifndef FWBARRAY_H
  57. #include "FWBArray.h"
  58. #endif
  59.  
  60. #ifndef FWMEMMGR_H
  61. #include "FWMemMgr.h"
  62. #endif
  63.  
  64. // ----- OpenDoc Includes -----
  65.  
  66. #ifndef SOM_Module_OpenDoc_StdProps_defined
  67. #include <StdProps.xh>
  68. #endif
  69.  
  70. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  71. #include <StdTypes.xh>
  72. #endif
  73.  
  74. #ifndef SOM_ODStorageUnit_xh
  75. #include <StorageU.xh>
  76. #endif
  77.  
  78. #ifndef SOM_ODSession_xh
  79. #include <ODSessn.xh>
  80. #endif
  81.  
  82. #ifndef SOM_ODLink_xh
  83. #include <Link.xh>
  84. #endif
  85.  
  86. //========================================================================================
  87. //    Runtime information
  88. //========================================================================================
  89.  
  90. #ifdef FW_BUILD_MAC
  91. #pragma segment odflinking
  92. #endif
  93.  
  94. //========================================================================================
  95. //    Template Instantiations
  96. //========================================================================================
  97.  
  98. FW_DEFINE_AUTO_TEMPLATE(FW_TOrderedCollectionIterator, FW_CLinkDestination)
  99. FW_DEFINE_AUTO_TEMPLATE(FW_TOrderedCollection, FW_CLinkDestination)
  100.  
  101. #ifdef FW_USE_TEMPLATE_PRAGMAS
  102.  
  103. #pragma template_access public
  104. #pragma template FW_TOrderedCollection<FW_CLinkDestination>
  105. #pragma template FW_TOrderedCollectionIterator<FW_CLinkDestination>
  106.  
  107. #endif
  108.  
  109. //========================================================================================
  110. //    class FW_CLinkDestination
  111. //========================================================================================
  112.  
  113. //----------------------------------------------------------------------------------------
  114. //    FW_CLinkDestination::FW_CLinkDestination
  115. //----------------------------------------------------------------------------------------
  116.  
  117. FW_CLinkDestination::FW_CLinkDestination(Environment* ev, 
  118.                                          ODLink* odLink, 
  119.                                          ODLinkInfo* linkInfo, 
  120.                                          FW_CPresentation* presentation)
  121. :    FW_CLink(ev, presentation),
  122.     fODLink(NULL),
  123.     fPart(NULL),
  124.     fCommandWaitingToEndAction(NULL),
  125.     fRegistered(false),
  126.     fEstablished(false),
  127.     fEmbed(false),
  128.     fDataInterchange(presentation->GetPart(ev)->GetDataInterchange(ev))
  129. {
  130.     if (odLink)
  131.     {
  132.         fODLink = odLink;
  133.         odLink->Acquire(ev);
  134.     }
  135.  
  136.     // Copy link info
  137.     fLinkInfo = *linkInfo;
  138. }
  139.  
  140. //----------------------------------------------------------------------------------------
  141. //    FW_CLinkDestination::~FW_CLinkDestination
  142. //----------------------------------------------------------------------------------------
  143.  
  144. FW_CLinkDestination::~FW_CLinkDestination()
  145. {
  146.     FW_SOMEnvironment ev;
  147.     this->Unregister(ev);
  148.     if (fODLink)
  149.         fODLink->Release(ev);
  150.  
  151.     if (fEmbed)                // fEmbedInfo is valid
  152.         FW_MPasteAsHandler::PrivDisposeEmbedInfoFields(&fEmbedInfo);
  153. }
  154.  
  155. //----------------------------------------------------------------------------------------
  156. //    FW_CLinkDestination::PrivEstablishLink
  157. //----------------------------------------------------------------------------------------
  158.  
  159. void FW_CLinkDestination::PrivEstablishLink(Environment* ev)
  160. {
  161.     this->LinkEstablished(ev);
  162.     fEstablished = true;
  163.     
  164.     if (fRegistered && !fLinkInfo.autoUpdate)
  165.         this->Unregister(ev);
  166.  
  167.     if (fCommandWaitingToEndAction)
  168.     {
  169.         fCommandWaitingToEndAction->PrivAddEndAction(ev);
  170.         fCommandWaitingToEndAction = NULL;
  171.     }
  172. }
  173.  
  174. //----------------------------------------------------------------------------------------
  175. //    FW_CLinkDestination::LinkEstablished
  176. //---------------------------------------------------------------------------------------
  177. void FW_CLinkDestination::LinkEstablished(Environment* ev)
  178. {
  179. FW_UNUSED(ev);
  180.     // Override to change the status of embedded frames to kODInLinkDestination
  181. }
  182.  
  183. //----------------------------------------------------------------------------------------
  184. //    FW_CLinkDestination::LinkUpdated
  185. //----------------------------------------------------------------------------------------
  186.  
  187. void FW_CLinkDestination::LinkUpdated(Environment* ev, ODUpdateID id)
  188. {
  189.     ODLinkKey linkKey;
  190.     if (!fODLink->Lock(ev, 0, &linkKey)) 
  191.         return;
  192.  
  193.     /* The following Try-block is for when OpenDoc throws an exception in GetContentStorageUnit.
  194.        If a cross-document link was just created, LinkUpdated gets called before the link content SU 
  195.        has received any data. In that case we want to just let the exception fall on the floor.
  196.        LinkUpdated will be called again after the link data has been written.
  197.     */
  198.     ODStorageUnit* su;
  199.     FW_VOLATILE(linkKey);
  200.     FW_TRY
  201.     {
  202.         su = fODLink->GetContentStorageUnit(ev, linkKey); /* cross-doc link will fail the 1st time */
  203.     }
  204.     FW_CATCH_BEGIN
  205.     FW_CATCH_REFERENCE(FW_XException, ex)
  206.     {
  207.         fODLink->Unlock(ev, linkKey);
  208.         // If GetContentStorageUnit returned the error kODErrNoLinkContent,
  209.         // the last source update failed; don't update the link at this time.
  210.         if (ex.GetPlatformError() == kODErrNoLinkContent)
  211.             return;
  212.         FW_THROW_SAME();
  213.     }
  214.     FW_CATCH_END
  215.  
  216.     FW_Boolean updateSuccessful = false;
  217.     FW_TRY
  218.     {
  219.         if (this->DoUpdateLink(ev, su, fEmbed ? &fEmbedInfo : NULL))    // part-specific
  220.         {
  221.             // --- Update the link info  ---
  222.             
  223.             // When updating a manual link, id is a new id, to avoid possible link cycle
  224.             // dialog.  But the link info needs the original id from the source so that
  225.             // the 'Update Now' button in link info dlg will be propery enabled or disabled
  226.             // next time the dialog is displayed.
  227.             
  228.             fLinkInfo.change = this->GetODLink(ev)->GetUpdateID(ev);
  229.             fLinkInfo.changeTime = fODLink->GetChangeTime(ev);
  230.             updateSuccessful = true;
  231.         }
  232.         else                            // Couldn't update the link, for some reason
  233.             if (!fEstablished)
  234.                 FW_Failure(kODErrCannotEstablishLink);
  235.     }
  236.     FW_CATCH_BEGIN
  237.     FW_CATCH_EVERYTHING()
  238.     {
  239.         // error occurred in DoUpdateLink somewhere
  240.         fODLink->Unlock(ev, linkKey);
  241.         FW_THROW_SAME();
  242.     }
  243.     FW_CATCH_END
  244.  
  245.     // --- We're done with the link content SU ---
  246.     fODLink->Unlock(ev, linkKey);
  247.  
  248.     // This used to be conditional upon !fEstablished, so only was executed on the first update.
  249.     // But it sets the link status of embedded frames, which needs done each time.  Other stuff 
  250.     // that should only be done the first time turns out to be a no-op in subsequent updates anyway.
  251.     // But caution:  What is done is part specific, so each linking part should assume that
  252.     // LinkEstablished will be called after every update.
  253.     
  254.     this->PrivEstablishLink(ev);
  255.     
  256.     // --- Propagate changes to source links maintained by the part ---
  257.     if (updateSuccessful)
  258.         this->DoPropagateChanges(ev, id);
  259. }
  260.  
  261. //----------------------------------------------------------------------------------------
  262. //    FW_CLinkDestination::DoPropagateChanges
  263. //----------------------------------------------------------------------------------------
  264. void FW_CLinkDestination::DoPropagateChanges(Environment* ev, ODUpdateID updateID)
  265. {
  266.     // Content in the specified destination link has changed.
  267.     // Override to propagate changes to source links maintained by this part (part-specific)
  268.  
  269.     // --- Notify all containing parts of the change ---
  270.     fPresentation->ContentUpdated(ev, updateID);
  271.  
  272.     fPresentation->Invalidate(ev);    // force all frames to be redrawn
  273. }
  274.  
  275. //----------------------------------------------------------------------------------------
  276. //    FW_CLinkDestination::Register
  277. //----------------------------------------------------------------------------------------
  278. void FW_CLinkDestination::Register(Environment* ev, FW_CPart* itsPart)
  279. {
  280.     if (fRegistered)
  281.         return;
  282.     
  283.     // For a manual link, this may still be needed if the user changes it to 
  284.     // automatic.  It really aught to be passed to the constructor.
  285.     FW_ASSERT(itsPart != kODNULL);
  286.     fPart = itsPart;
  287.         
  288.     ODUpdateID linkUpdateID = fODLink->GetUpdateID(ev);
  289.     FW_Boolean needsUpdate = (fLinkInfo.change != linkUpdateID);
  290.  
  291.     if (!fEstablished || fLinkInfo.autoUpdate)
  292.     {
  293.         fRegistered = TRUE;
  294.  
  295.         //--- Register for automatic updates ---
  296.         // First determine if another link with the same ODLink as ours already registered
  297.         FW_Boolean alreadyRegistered = FALSE;
  298.         FW_CPartLinkDestIterator iter(itsPart);
  299.         for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  300.         {
  301.             if ((link != this) && fODLink->IsEqualTo(ev, link->GetODLink(ev))
  302.                 && link->IsRegistered(ev))
  303.             {
  304.                 alreadyRegistered = TRUE;
  305.                 break;
  306.             }
  307.         }
  308.  
  309.         if (!alreadyRegistered)
  310.         {
  311.             fODLink->RegisterDependent(ev, fPart->GetODPart(ev), fLinkInfo.change);
  312.             // part::LinkUpdated call will be generated
  313.             needsUpdate = FALSE;
  314.         }
  315.     }
  316.  
  317.     if (needsUpdate)    // Manually update now
  318.         this->LinkUpdated(ev, linkUpdateID);
  319. }
  320.  
  321. //----------------------------------------------------------------------------------------
  322. //    FW_CLinkDestination::Unregister
  323. //----------------------------------------------------------------------------------------
  324. void FW_CLinkDestination::Unregister(Environment* ev)
  325. {
  326.     if (!fRegistered) return;
  327.  
  328.     // Unregister, if this is the last automatically updated destination of the link in the part
  329.     FW_ASSERT(fPart);
  330.     short regCount = 0;
  331.     FW_CPartLinkDestIterator iter(fPart);
  332.     for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
  333.     {
  334.         if (link->IsRegistered(ev) && fODLink->IsEqualTo(ev, link->GetODLink(ev)))
  335.             regCount++;
  336.     }
  337.     
  338.     if (regCount == 1)    // this is the only registered link
  339.     {
  340.         fODLink->UnregisterDependent(ev, fPart->GetODPart(ev));
  341.     }
  342.  
  343.     fRegistered = FALSE;
  344. }
  345.  
  346. //----------------------------------------------------------------------------------------
  347. //    FW_CLinkDestination::BreakLink
  348. //----------------------------------------------------------------------------------------
  349. void FW_CLinkDestination::BreakLink(Environment* ev)
  350. {
  351.     this->Unregister(ev);
  352.     fEstablished = false;
  353. }
  354.  
  355. //----------------------------------------------------------------------------------------
  356. //    FW_CLinkDestination::RestoreLink
  357. //----------------------------------------------------------------------------------------
  358. void FW_CLinkDestination::RestoreLink(Environment* ev, FW_CPart* part)
  359. {
  360.     // Re-register the link if necessary
  361.     this->Register(ev, part);
  362. }
  363.  
  364. //----------------------------------------------------------------------------------------
  365. //    FW_CLinkDestination::ExternalizeLink
  366. //----------------------------------------------------------------------------------------
  367. void FW_CLinkDestination::ExternalizeLink(Environment* ev, ODStorageUnit* storageUnit,
  368.                                           FW_CCloneInfo* cloneInfo)
  369. {
  370.     //-- Storage unit must be focused to property kODPropContents, value destLinkFormat
  371.     ODStorageUnitRef suRef;
  372.     fODLink->Externalize(ev);
  373.  
  374.     ODID linkID = fODLink->GetID(ev);
  375.     if (cloneInfo != NULL)
  376.     {
  377.         linkID = cloneInfo->Clone(ev, linkID, 0, 0);
  378.     }
  379.  
  380.     // May not have been able to clone the link
  381.     if (linkID == kODNULL) return;
  382.  
  383.     //--- Write the link version number ---
  384.     long version = FW_kLinkVersionNumber;
  385.     FW_CByteArray byteArray(&version, sizeof(long));
  386.     storageUnit->SetValue(ev, byteArray);
  387.  
  388.     //--- Write a reference to the link ---
  389.     storageUnit->GetStrongStorageUnitRef(ev, linkID, suRef);
  390.     byteArray.Set(&suRef, sizeof(ODStorageUnitRef));
  391.     storageUnit->SetValue(ev, byteArray);
  392.  
  393.     //--- Write link info ---
  394.     ODType savedKind = fLinkInfo.kind;            // save kind string
  395.     fLinkInfo.kind = (ODType) strlen(savedKind) + 1;
  396.     byteArray.Set(&fLinkInfo, sizeof(ODLinkInfo));
  397.     storageUnit->SetValue(ev, byteArray);        // write out linkinfo
  398.     byteArray.Set((void*)savedKind, (ODULong)fLinkInfo.kind);
  399.     storageUnit->SetValue(ev, byteArray);        // write out kind string
  400.     fLinkInfo.kind = savedKind;                    // restore kind string
  401.     
  402.     //--- Write embed info, if any ---
  403.     byteArray.Set(&fEmbed, sizeof(FW_Boolean));
  404.     storageUnit->SetValue(ev, byteArray);
  405.     if (fEmbed)
  406.     {
  407.         //-- save strings, except for selectedKind, which was written above
  408.         savedKind = fEmbedInfo.translateKind;        // save translateKind string
  409.         if (savedKind != NULL)
  410.             fEmbedInfo.translateKind = (ODType) strlen(savedKind) + 1;
  411.         ODEditor savedEditor = fEmbedInfo.editor;    // save editor string
  412.         if (savedEditor != NULL)
  413.             fEmbedInfo.editor = (ODType) strlen(savedEditor) + 1;
  414.  
  415.         //-- write fields of fEmbedInfo
  416.         byteArray.Set(&fEmbedInfo, sizeof(ODPasteAsResult));
  417.         storageUnit->SetValue(ev, byteArray);
  418.         if (savedKind != NULL)                        // write the translateKind string
  419.         {
  420.             byteArray.Set((void*)savedKind, (ODULong)fEmbedInfo.translateKind);
  421.             storageUnit->SetValue(ev, byteArray);
  422.         }
  423.         if (savedEditor != NULL)                    // write the editor string
  424.         {
  425.             byteArray.Set((void*)savedEditor, (ODULong)fEmbedInfo.editor);
  426.             storageUnit->SetValue(ev, byteArray);
  427.         }
  428.  
  429.         //-- Restore string ptrs to fEmbedInfo
  430.         fEmbedInfo.translateKind = savedKind;
  431.         fEmbedInfo.editor = savedEditor;
  432.     }
  433.  
  434.     //--- Write out data specific to this part's link ---
  435.     this->DoExternalizeLink(ev, storageUnit, cloneInfo);
  436. }
  437.  
  438. //----------------------------------------------------------------------------------------
  439. //    FW_CLinkDestination::SavePasteAsSettings
  440. //----------------------------------------------------------------------------------------
  441. void FW_CLinkDestination::SavePasteAsSettings(Environment* ev, ODPasteAsResult& pasteAsResult)
  442. {
  443. FW_UNUSED(ev);
  444.     // Record the PasteAs dialog settings, so links can be updated appropriately
  445.     fLinkInfo.kind = pasteAsResult.selectedKind;    // Copy the pointer
  446.     fEmbed = (pasteAsResult.mergeSetting == kODFalse);
  447.     if (fEmbed)
  448.     {
  449.         // Embed As: remember the user's settings
  450.         fEmbedInfo = pasteAsResult;
  451.         // Set pointer fields to NULL so they won't be disposed by the caller
  452.         pasteAsResult.translateKind = NULL;
  453.         pasteAsResult.editor = NULL;
  454.     }
  455.  
  456.     pasteAsResult.selectedKind = NULL;                // so caller doesn't dispose it
  457. }
  458.  
  459. //----------------------------------------------------------------------------------------
  460. //    FW_CLinkDestination::GetContainingFrame
  461. //----------------------------------------------------------------------------------------
  462. FW_CFrame* FW_CLinkDestination::GetContainingFrame(Environment* ev, ODFrame* odEmbeddedFrame)
  463. {
  464. FW_UNUSED(ev);
  465. FW_UNUSED(odEmbeddedFrame); 
  466.  
  467.     // Should be overridden if the part supports linking and embedding.
  468.     // Return the containing frame if odEmbeddedFrame is involved in this link.
  469.     // Called when finding the source of a link.
  470.  
  471.     return NULL;
  472. }
  473.  
  474. //----------------------------------------------------------------------------------------
  475. //    FW_CLinkDestination::ShowLinkInfo
  476. //----------------------------------------------------------------------------------------
  477. void FW_CLinkDestination::ShowLinkInfo(Environment* ev, FW_CFrame* frame, FW_CLinkManager* linkMgr)
  478. {
  479.     ODLinkInfoResult infoResult;
  480.     if (fODLink->ShowLinkDestinationInfo(ev, frame->GetActiveFacet(ev), &fLinkInfo, true, &infoResult))
  481.     {
  482.         switch (infoResult.action)
  483.         {
  484.             case kODLinkInfoFindSource:
  485.                 fODLink->ShowSourceContent(ev);
  486.                 break;
  487.  
  488.             case kODLinkInfoBreakLink: 
  489.                 {
  490.                 // Create and return an undoable command to break the link
  491.                 FW_CBreakLinkCommand* cmd = FW_NEW(FW_CBreakLinkCommand, (ev, frame, this, linkMgr)); 
  492.                 cmd->Execute(ev);
  493.                 }
  494.                 break;
  495.  
  496.             case kODLinkInfoUpdateNow:
  497.                 this->LinkUpdated(ev, FW_CSession::UniqueUpdateID(ev));
  498.                 break;
  499.  
  500.             case kODLinkInfoOk:
  501.                 if (infoResult.autoUpdate != fLinkInfo.autoUpdate)
  502.                 {
  503.                     fLinkInfo.autoUpdate = infoResult.autoUpdate;
  504.                     if (fLinkInfo.autoUpdate)
  505.                         this->Register(ev, fPart);
  506.                     else
  507.                         this->Unregister(ev);
  508.                 }
  509.                 break;
  510.         }
  511.     }
  512. }
  513.  
  514.