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 / Developer Documentation / Recipes, Tech Notes & Articles / Recipes / Data Interchange / Clipboard Recipes < prev    next >
Encoding:
Text File  |  1995-12-08  |  28.5 KB  |  454 lines  |  [TEXT/ttxt]

  1. OpenDoc™ Recipes
  2.  
  3.  
  4. Clipboard Recipes
  5. By The OpenDoc Design Team
  6. December 8, 1995
  7.  
  8. © 1993-1995  Apple Computer, Inc. All Rights Reserved.
  9. Apple, the Apple logo, and Macintosh are registered trademarks of Apple Computer, Inc.
  10. Mac and OpenDoc are trademarks of Apple Computer, Inc.
  11.  
  12.  
  13. About Clipboard Recipes 
  14.  
  15. This document describes the basic techniques for reading and writing the Clipboard.  It assumes familarity with the document “Basic Data Interchange”, and references coding examples there.  For further details on the Clipboard operations involving embedded frames, see the Layout recipes.  For more information on Clipboard operations involving links, including the posting of link specifications and incorporation of linked content, see the Linking recipes.
  16.  
  17. For a description of individual methods used in the recipes, refer to the Class Documentation for the appropriate class.
  18.  
  19. About The Coding Examples
  20.  
  21. This document contains a number of coding examples in addition to descriptive text.  The coding examples cover:
  22.  
  23. MyWriteToClipboard -- Writing intrinsic content to the clipboard.
  24.  
  25. MyCloneEmbeddedFrameToClipboard -- Writing a single embedded frame to the clipboard.
  26.  
  27. MyIncorporateFromClipboard -- Incorporating content from the clipboard.
  28.  
  29. MyEmbedFromClipboard -- Embedding content from the clipboard.
  30.  
  31. For simplicity, the coding examples use ODByteArrays to represent the content to be read or written.  If your part does not maintain its content as an ODByteArray, you can either copy it into an ODByteArray, or, more likely, write data out or read data in in chunks using the StorageUnitSetValue or StorageUnitGetValue utility functions.
  32.  
  33. The examples use exception handling in the form of TRY…CATCH_ALL…ENDTRY blocks to catch exceptions, and assumes that errors returned by SOM methods are automatically thrown upon return.
  34.  
  35. WARNING: CODE APPEARING IN THESE RECIPES HAS NOT BEEN TESTED, AND MAY CONTAIN ERRORS. 
  36.  
  37. Summary of changes from the DR3 Recipes
  38.  
  39. • Information common to the Clipboard, Drag and Drop, and Linking have been moved into the recipe document “Data Interchange Basics.”
  40.  
  41. • Added comment that parts should read from or write to the clipboard synchronously, rather than spawning a thread to complete the operation.  See the section “When Parts May Access the Clipboard”.
  42.  
  43. • Parts must notify the clipboard when a Cut, Copy, or Paste is done, undone or redone.  New methods ActionDone, ActionUndone, and ActionRedone have been added to ODClipboard.  See the section “Undoing Clipboard Operations”.
  44.  
  45. • In "Relinquishing the Clipboard Focus", an erroneous reference to the non-existent part method RelinquishFocus was removed.
  46.  
  47. Summary of changes from the DR2 Recipes
  48.  
  49. The differences between these recipes and those that accompanied DR2 are summarized here.
  50.  
  51. • Important information was added to “Undoing Clipboard Operations”:
  52.     -  the effect of undo on the clipboard content was clarified.
  53.     - as a temporary work around, parts should clear the clipboard after undoing a cut. 
  54.  
  55. • Recipes were updated to conform to API changes in DR3:
  56.     - Calls to BeginClone include the destFrame argument.
  57.     - References to XXXChanged methods changed to XXXXUpdated as appropriate.
  58.     - ODChangeID replaced by ODUpdateID.
  59.     - GetChangeID has been renamed to GetUpdateID, and it returns an ODUpdateID value.
  60.     - GetXXXX has been changed to AcquireXXXX as necessary.
  61.  
  62. • A discussion of the ODPasteAsMergeSetting parameter to ShowPasteAsDialog has been added.
  63.  
  64. • Parts are reminded that the Clipboard should only be accessed in the foreground process.
  65.  
  66. • The kODPropFrameShape property  has been changed to kODPropSuggestedFrameShape, and some elaboration on the property has been added.
  67.  
  68. • The recipe for copying content to the clipboard was broken into two simpler recipes, one a basic recipe for writing to the content storage unit of a Data Transfer object (clipboard, drag and drop, or link source).
  69.  
  70. Summary of changes from the November 1994 (DR1) Recipes
  71.  
  72. The differences between the DR2 recipes and those that accompanied DR1 are summarized here.
  73.  
  74. • Added the recipe for embedding a part via the Paste As dialog.
  75.  
  76. • Added recipe for determining if a draft can be modified.
  77.  
  78. • Parts must write a kODPropName property to the clipboard (or drag-and-drop storage unit) whenever they write content.  See the recipe "Putting intrinsic content on the clipboard" for details.
  79.  
  80. • Parts may now assume that a call to their AdjustMenus method will be followed by a call to their HandleEvent method.  This simplifies the recipes for acquiring and relinquishing the clipboard focus.  Parts can request the focus in AdjustMenus, and relinquish the focus in HandleEvent.
  81.  
  82. • A brief section for container applications describes when the clipboard object's ExportClipboard and DraftClosing methods should be called.  Parts do not call these methods!
  83.  
  84. • The section “Cleanup in ReleaseAll” has been changed.  Parts no longer need to remove their link spec from the Clipboard in their ReleaseAll method, nor do they need to initiate fulfilling promises.  This is now handled automatically by the Clipboard when the draft is closed.
  85.  
  86. • Parts that support Cut & Paste, or Drag and Drop, must support undo of those operations.  See the section “Undoing Clipboard Operations.”
  87.  
  88. Summary of changes from a6 Recipes
  89.  
  90. The differences between the DR1 recipes and those that accompanied a6 are summarized here.
  91.  
  92. • Conversion to SOM.
  93.  
  94. • The Lock() and Unlock() methods have been removed from the clipboard.  Instead, parts should use the clipboard focus.
  95.  
  96. • Clipboard key parameters have been removed from class methods.
  97.  
  98. • The recipe for copying a single embedded frame has been modified to allow the embedded part to promise its content.  This requires a modification to the embedded part's CloneInto() method.  The a6 recipe for copying a single embedded frame will still work, however.
  99.  
  100. • The recipe for cut-paste (and drag-move) have changed to allow objects to be reused if the move is within the same draft.
  101.  
  102. When a part receives a drop or pastes, the part should use the display frame provided if it chooses to embed the content.  The receiving part may create a new display frame instead, but if the display frame was moved its more efficient to use the provided frame.
  103.  
  104. After a cut, or after a drop of moved content, the source part must release moved objects carefully.  As before, the source part needs to delete any facets displaying moved embedded frames.  If the operation was a drag, the source part must take into account that a moved frame may now be embedded in another part, and may have new facets in its new containing frame.  The source part cannot use the moved frame's facet iterator.  It must instead use the containing facet's iterator to identify the facets to be deleted.  The a6 recipes did not discuss this detail, but the frame's facet iterator was used in the engineering Draw part.
  105.  
  106. • kODPropContentFrame has been added, and kODPropContentIsFrame has been removed.
  107.  
  108. • The recipe for incorporating content from the clipboard has been changed to have the receiving part read values from the root storage unit on the clipboard, rather than cloning the root first.
  109.  
  110. • The recipe for putting content on the clipboard now recommends performing a BeginClone-EndClone transaction, even if cloning is not performed because content is promised.  By performing a clone transaction, parts inform OpenDoc of the semantics of the operation, so that should cloning occur later during the fulfilling of promises, the correct behavior will result.
  111.  
  112. Header File
  113.  
  114. Parts that access the clipboard  need to include the clipboard header file:
  115.  
  116. #ifndef SOM_ODClipboard_xh
  117. #include <Clipbd.xh>
  118. #endif
  119.  
  120. When Parts May Access the Clipboard
  121.  
  122. Parts should access the clipboard only when two conditions are true.  First, the part must be running in the frontmost process.  The Clipboard is only defined for the frontmost process; any attempt to access it in a background process is meaningless (the clipboard method Clear now returns error kODErrBackgroundClipboardClear if called when the process is in the background).  Second, the part must own the clipboard focus.
  123.  
  124. In addition, note that if a part's draft is read only, it should disable Clipboard operations that would change the draft, such as Cut, Paste, and Paste As.
  125.  
  126. Except for the special case of AdjustMenus, described below, parts should complete their access to the clipboard before returning from the method that initiated the access.  For example, parts should modify the clipboard within their HandleEvent method, and relinquish the clipboard focus before returning from HandleEvent.  Parts should not spawn a thread that copies data to the clipboard, all the while holding the clipboard focus.  Parts can minimize the amount of data transferred on a Cut or Copy by writing promises to the clipboard.
  127.  
  128. Determining that a Draft Can Be Modified
  129.  
  130. If a part calls an OpenDoc method that modifies a draft, and the draft's permissions do not allow modifications, the OpenDoc method will return an error.  Parts can determine if a draft can be modified by testing the draft permissions:
  131.  
  132. ODDraftPermissions permissions = storageUnit->GetDraft(ev)->GetPermissions(ev);
  133.  
  134. if ( permissions >= kDPSharedWrite )
  135. {
  136.  ... the draft may be modified
  137. }
  138.  
  139. Parts should check draft permissions before attempting an operation that modifies a draft.  For example, a part should not enable the Cut, Paste, or Paste As menu items if the draft cannot be modified.
  140.  
  141. The Clipboard Focus
  142.  
  143. To be thread safe, parts should acquire the clipboard focus prior to accessing the clipboard. Since parts usually need to inspect the clipboard to enable items on the Edit menu, they should call Arbitrator::RequestFocus from AdjustMenus to request the clipboard focus.  If granted, a part can enable the Cut, Copy, Paste, and Paste As items as appropriate.  A part can assume that a call to AdjustMenus will be followed by a call to HandleEvent; most parts should request the clipboard focus in AdjustMenus and relinquish the focus in HandleEvent.
  144.  
  145. Note:  Your editor should not call ShowPartFrameInfo to display info on its own part. The user may pick another editor for that part, so your display frames may have been closed before ShowPartFrameInfo returns.  In particular, the display frame parameter to HandleEvent may not be valid after your part calls ShowPartFrameInfo.  The Part Info menu item applies to the current selection, so your part shouldn't attempt to do this if it sticks to the guidelines.
  146.  
  147. Acquiring the Clipboard Focus
  148.  
  149. ODSession* session = somSelf->GetStorageUnit(ev)->GetSession(ev);
  150. ODArbitrator* arbitrator = session ->GetArbitrator(ev);
  151.  
  152. ODTypeToken clipboardFocus = session->Tokenize(ev, kODClipboardFocus);
  153. ODFrame* clipboardOwner = arbitrator->AcquireFocusOwner(ev, clipboardFocus);
  154. if ( (frame == clipboardOwner) || arbitrator->RequestFocus(ev, clipboardFocus, frame) )
  155. {
  156.   ODClipboard* clipboard = session->GetClipboard(ev);
  157.   // Access the clipboard here.
  158.   …
  159. }
  160. ODReleaseObject(ev, clipboardOwner);
  161.  
  162. Parts may retain the clipboard focus while active, but must be prepared to relinquish the clipboard focus to allow other parts to inspect the clipboard.  Parts must also relinquish the clipboard focus in their DeactivateFrame method if the deactivated frame owns the focus.
  163.  
  164. Relinquishing the Clipboard Focus
  165.  
  166. If your part retains the clipboard focus while active, it must be prepared to relinquish the clipboard focus in BeginRelinquishFocus/CommitRelinquishFocus to allow other parts to inspect the clipboard.  Parts must also relinquish the clipboard focus in their DeactivateFrame method if the deactivated frame owns the focus.
  167.  
  168. // Insert in your part's DeactivateFrame method (only necessary if
  169. // the part holds the Clipboard focus)
  170.  
  171. ODSession* session = somSelf->GetStorageUnit(ev)->GetSession(ev);
  172. ODArbitrator* arbitrator = session ->GetArbitrator(ev);
  173.  
  174. arbitrator->RelinquishFocus(ev, clipboardFocus, frame);
  175.  
  176. Cloning to the Clipboard
  177.  
  178. Whenever a part puts data on the clipboard, even if object cloning is not performed, it should do so within a BeginClone-EndClone transaction (using the clone kind kODCloneCut or kODCloneCopy, as described in the Data Interchange Basics document).  Using a clone transaction helps OpenDoc ensure that unfulfilled promises are resolved when a draft is closed.
  179.  
  180. Note that the first paste following a cut is always a move in OpenDoc.  There is no way for the part performing a paste to force pasting a copy of the data.  This should not matter to your part; the paste recipes work whether the content is being moved or copied into your part.  However, the behavior of links and embedded content will be different when moved versus copied.
  181.  
  182. Clipboard Update IDs
  183.  
  184. The update ID returned by the ActionDone and GetUpdateID methods of the clipboard object identifies a particular clipboard generation, not a particular change.  When your part pastes data from the clipboard, your part must remember the clipboard update ID in case the operation is later undone, but your part should generate a new update ID (using the UniqueUpdateID method of the session object) to associated with the pasted content.  If the user pastes the contents of the clipboard twice, the clipboard’s update ID will be the same both times.  Each paste is a separate change, however, with which your part must associated different update IDs.  See the Linking Recipes for more information on update IDs.
  185.  
  186. Undoing Clipboard Operations 
  187.  
  188. Parts that support Cut, Paste, Drag or Drop must support undoing and redoing those operations.  If the user moves frames, links, or other objects from one part to another, via Cut & Paste or Drag and Drop, objects may be reused at the destination.  If the clipboard or Drag and Drop operation is undone, the objects must be reinstated at the source.  This can only happen if the the part initiating the cut or drag and the part performing the paste or drop both support undo.
  189.  
  190. Your part is responsible for notifying the clipboard whenever a Cut, Copy, or Paste operation is done, undone, or redone.  (Your part should not perform this notification when pasting a link from the clipboard.)  When yor part performs a Cut, Copy, or Paste, call the ActionDone method of the clipboard.  This method takes as its argument the cloneKind your part used to access the clipboard (either kODCloneCut, kODCloneCopy, or kODClonePaste).  When your part undoes a Cut, Copy, or Paste, call the ActionUndone method of the clipboard object, specifying the update ID returned by the clipboard's ActionDone method at the time of the original action, and the clone kind used at the original access.  When your part redoes a Cut, Copy, or Paste, call the ActionRedone method of the clipboard object instead.
  191.  
  192. When a cut or copy operation is undone, it is not necessary to restore the clipboard to its previous contents.  Because of this, code implementing the redo of a paste operation cannot assume the clipboard content is the same as it was when the original paste was performed.  Redo of a paste operation must be implemented by restoring content from a private cache.
  193.  
  194. When a part cuts an object to the clipboard, a reference to the object should be saved in an undo action.  If the part’s UndoAction method is called, it must (1) reinstate the object into its content model from its undo information, and (2) notify the clipboard that the cut was undone (see below).  Similarly, if the part’s RedoAction method is called, it should (1) remove the object from its content model, and (2) notify the clipboard that the cut was redone.  When the part’s DisposeActionState method is called, the object reference in the action data should be released.  See the section below for special instructions on handling embedded frames that have been cut or pasted.
  195.  
  196. Undoing the Cut or Paste of Embedded Frames
  197.  
  198. The part performing a cut or paste of one or more embedded frames is responsible for handling the in-limbo status of the frame correctly.  If the user undoes the cut of an embedded frame, your part must set the in-limbo flag to kODFalse in its UndoAction method.  If the user redoes the cut of an embedded frame, your part must set the in-limbo flag to kODTrue.  When your DisposeActionState method is called to commit a cut, your part must examine the state of the in-limbo flag.  If the IsInLimbo returns kODFalse, your part must release the frame reference it holds; if IsInLimbo returns kODTrue, your part must remove the frame by calling the Remove method of the frame.
  199.  
  200. Similarly, if the user undoes the paste of an embedded frame, your part's UndoAction method must restore the in-limbo flag to the value it had before the paste was performed.  If the user redoes the paste of an embedded frame, your part must set the in-limbo flag to kODFalse.  When your DisposeActionState method is called to commit a paste, your part must examine the state of the in-limbo flag.  If the IsInLimbo returns kODFalse, your part must release the frame reference it holds.  If IsInLimbo returns kODTrue, your part's action depends on the in-limbo status of the frame at the time the paste was performed.  If the frame was in-limbo, your part must release the frame reference it holds (some other part will remove it.)  If the frame was not in-limbo, your part must remove the frame by calling the Remove method of the frame.
  201.  
  202. Cleanup in ReleaseAll
  203.  
  204. When a part's ReleaseAll method is called, the part should check to see if it has a promise or a link specification on the clipboard.  If so, it needs to fulfill the promise or remove the link specification.
  205.  
  206. Writing Intrinsic Content to the Clipboard
  207.  
  208. MyWriteToClipboard demonstrates how a part might implement a routine to copy intrinsic content to the clipboard.  It uses the MyWriteToContentSU method, described in the Data Interchange Basics recipe, to write promises for the data.
  209. MyWriteToClipboard should only be called when this part holds the clipboard focus and is in the foreground, as described earlier.
  210.  
  211. The promiseData parameter is whatever information the part needs to identify the promised content when its FulfillPromise method is called.
  212.  
  213. The contentShape parameter will be written as the suggested frame shape annotation.  This property will be used as the frame shape should content be embedded from the clipboard.
  214.  
  215. The partName parameter will be written as the part name annotation.  If your part associates a name with the content written, you may  want the part created should the content be embedded at the destination to bear this name.  If not, the partName may be null, and no part name annotation will be created.
  216.  
  217. The optional linkSpecData parameter will be written into a link specification if the operation is a copy.
  218.  
  219. The cloneKind parameter is either kODCloneCut or kODCloneCopy.
  220.  
  221. This method returns the update ID of this clipboard operation.  This ID can be saved and later compared to the current clipboard update ID to determine if the contents of the clipboard have been replaced.
  222.  
  223. ODUpdateID MyWriteToClipboard (Environment *ev,
  224.   ODByteArray* promiseData,
  225.   ODShape* contentShape,
  226.   ODIText* partName,
  227.   ODByteArray* linkSpecData,
  228.   ODCloneKind cloneKind)
  229. {
  230.   ODClipboard* clipboard = fSOMSelf->GetStorageUnit(ev)->GetSession(ev)->GetClipboard(ev);
  231.   ODVolatile(clipboard);
  232.  
  233.   // Remove any existing data on the clipboard
  234.   clipboard->Clear(ev);
  235.  
  236.   // Get the content storage unit for the clipboard
  237.   ODStorageUnit* clipContentSU = clipboard->GetContentStorageUnit(ev);
  238.  
  239.   TRY
  240.  
  241.     self->MyWriteToContentSU(ev, clipContentSU, cloneKind, promiseData, contentShape, partName);
  242.  
  243.     // If a copy operation is being performed, write a link spec to the clipboard.
  244.     if ( (cloneKind == kODCloneCopy) && linkSpecData )
  245.     {
  246.       // See the linking recipes.
  247.       …
  248.     }
  249.  
  250.   CATCH_ALL
  251.  
  252.     // If an exception was raised, clear the clipboard.
  253.     //   The previous contents of the clipboard are lost.
  254.     clipboard->Clear(ev);
  255.     RERAISE;
  256.  
  257.   ENDTRY
  258.  
  259.   // Return the update id associated with this clipboard operation.
  260.   return clipboard->ActionDone(ev, cloneKind);
  261. }
  262.  
  263. Copying Intrinsic Content to the Clipboard
  264.  
  265. Copying intrinsic content to the clipboard is as simple as calling MyWriteToClipboard with the suitable clone kind.
  266.  
  267. ODUpdateID clipboardUpdateID = self->MyWriteToClipboard(ev, 
  268.     promiseData, 
  269.     contentShape, 
  270.     partName, 
  271.     linkSpecData, 
  272.     kODCloneCopy);
  273.  
  274. Cutting Intrinsic Content to the Clipboard
  275.  
  276. If the operation is a cut, after putting content on the clipboard, the intrinsic content should be removed.  When an embedded frame is cut, the part must delete any facets displaying that frame.  Call the containing facet's RemoveFacet method to remove a facet, then delete the facet object.  The cut frame’s containing frame should be set to kODNULL to remove it from the layout hierarchy, but not removed from the part.  A reference to the cut frame should be placed in undo action data.  Other frames displaying the part are not affected.
  277.  
  278. When content is cut, any objects cloned to the clipboard may be reused if pasted back into the same draft.  This includes embedded frames, link and link source objects that a part typically references directly.  If the cut content references any other persistent objects, those references should retained in undo data so the operation can be undone.  When the references are no longer needed to support undo, the objects should be released.  See the section “Undoing Clipboard Operations” for more information.
  279.  
  280. Each embedded frame cut along with intrinsic content must have its in-limbo flag set to kODTrue.
  281.  
  282. cutEmbeddedFrame->SetInLimbo(ev, kODTrue); 
  283.  
  284. Copying a Single Embedded Frame to the Clipboard.
  285.  
  286. Your part should follow this recipe to put a single embedded frame on the clipboard.   The promiseProxyData parameter.  Note the similarity to MyWriteToClipboard; only the line calling MyCloneEmbeddedFrameToContentSU is different!
  287.  
  288. The embeddedFrame parameter is the frame being cut or copied.
  289. The optional promiseProxyData is proxy content that this part associates with the embedded frame and will be written as proxy content.
  290. The optional linkSpecData parameter will be written into a link specification if the operation is a copy.
  291. The cloneKind parameter is either kODCloneCut or kODCloneCopy.
  292.  
  293. This method returns the update ID of this clipboard operation.
  294.  
  295. ODUpdateID MyCloneEmbeddedFrameToClipboard (Environment *ev,
  296.   ODFrame* embeddedFrame,
  297.   ODByteArray* promiseProxyData,
  298.   ODByteArray* linkSpecData,
  299.   ODCloneKind cloneKind)
  300. {
  301.   ODClipboard* clipboard = somSelf->GetStorageUnit(ev)->GetSession(ev)->GetClipboard(ev);
  302.   ODVolatile(clipboard);
  303.  
  304.   // Remove any existing data on the clipboard
  305.   clipboard->Clear(ev);
  306.  
  307.   // Get the content storage unit for the clipboard
  308.   ODStorageUnit* clipContentSU = clipboard->GetContentStorageUnit(ev);
  309.  
  310.   TRY
  311.  
  312.     self->MyCloneEmbeddedFrameToContentSU(ev, clipContentSU, cloneKind, embeddedFrame, promiseProxyData);
  313.  
  314.     // If a copy operation is being performed, write a link spec to the   
  315.     //   clipboard if this part supports linking.
  316.     if ( (cloneKind == kODCloneCopy) && linkSpecData )
  317.     {
  318.       // See the linking recipes; note conditions when a link specification
  319.       //   should not be written.
  320.       …
  321.     }
  322.  
  323.   CATCH_ALL
  324.  
  325.     // If an exception was raised, clear the clipboard.
  326.     //   The previous contents of the clipboard are lost.
  327.     clipboard->Clear(ev);
  328.     RERAISE;
  329.  
  330.   ENDTRY
  331.  
  332.   // Return the update id associated with this clipboard operation.
  333.   return clipboard->ActionDone(ev, cloneKind);
  334. }
  335.  
  336. Cutting a Single Embedded Frame to the Clipboard
  337.  
  338. Unlike Copy, Cut is an undoable operation.  Your implementation of Cut can be based on Copy, with a little work before and after the copy.
  339.  
  340. // Save the current selection in an undo action.  MyMakeUndoAction is not described here.
  341. ODActionData actionState = somSelf->MyMakeUndoAction(ev);
  342.  
  343. ODUpdateID clipboardUpdateID = 
  344.     self->MyCloneEmbeddedFrameToClipboard(embeddedFrame, promiseData, kODCloneCut);
  345.  
  346. // Set the in-limbo flag of the cut frame to kODTrue.
  347. embeddedFrame->SetInLimbo(ev, kODTrue); 
  348.  
  349. // Add an undo action for this operation and delete the selection.
  350. ODUndo* undo = somSelf->GetStorageUnit(ev)->GetSession(ev)->GetUndo(ev);
  351. undo->AddActionToHistory(ev, somThis->fPartWrapper, actionState, kODSingleAction, …);
  352.  
  353. // MyDeleteSelection is a part-specific method not described here.
  354. somSelf->MyDeleteSelection(ev);
  355.  
  356. // Associate an update id with this cut, and notify containing parts of this change
  357. ODUpdateID cutUpdateID = fSOMSelf->GetStorageUnit(ev)->GetSession(ev)->UniqueUpdateID(ev);
  358. myFrame->ContentUpdated(ev, cutUpdateID);
  359.  
  360. // Make sure that this change is saved when the document is closed.
  361. somSelf->GetStorageUnit(ev)->GetDraft(ev)->SetChangedFromPrev(ev);
  362.  
  363. Incorporating Content from the Clipboard 
  364.  
  365. Incorporating from the clipboard is demonstrated by this code that gets the clipboard content storage unit and calls the MyReadFromContentSU routine described in the Data Interchange Basics document.  In this simple example, the incorporated content is inserted where there are no source links maintained by this part.  Because Paste must be an undoable operation, action data is added to the undo history if incorporation is successful.
  366.  
  367. The targetFrame argument identifies the frame being incorporated into and is passed to MyReadFromContentSU.
  368.  
  369. This method returns the update ID of this clipboard operation.  (This is not the same as the update ID associated with the content change to this part!)
  370.  
  371. ODUpdateID MyIncorporateFromClipboard (Environment *ev, ODFrame* targetFrame)
  372. {
  373.   ODClipboard* clipboard = fSOMSelf->GetStorageUnit(ev)->GetSession(ev)->GetClipboard(ev);
  374.   ODUpdateID clipboardUpdateID = kODUnknownUpdate;
  375.  
  376.   // Get the content storage unit of the clipboard
  377.   ODStorageUnit* clipContentSU = clipboard->GetContentStorageUnit(ev);
  378.  
  379.   ODVolatile(clipboard);
  380.  
  381.   TRY
  382.  
  383.     fSOMSelf->MyReadFromContentSU(ev, clipContentSU, targetFrame, kODClonePaste, kODNotInLink);
  384.  
  385.     clipboardUpdateID = clipboard->ActionDone(ev, kODClonePaste);
  386.  
  387.     // If the incorporation was successful, add an undo action.
  388.     //   The undo data should include clipboardUpdateID and the in-limbo status of any
  389.     //   frames that were embedded.
  390.     ODActionData actionState = … // part specific
  391.     ODUndo* undo = somSelf->GetStorageUnit(ev)->GetSession(ev)->GetUndo(ev);
  392.     undo->AddActionToHistory(ev, somThis->fPartWrapper, actionState, kODSingleAction, …);
  393.  
  394.     // Associate an update id with this paste, and notify containing parts of this change
  395.     ODUpdateID pasteUpdateID = fSOMSelf->GetStorageUnit(ev)->GetSession(ev)->UniqueUpdateID(ev);
  396.     targetFrame->ContentUpdated(ev, pasteUpdateID);
  397.  
  398.     // Make sure that this change is saved when the document is closed
  399.     fSOMSelf->GetStorageUnit(ev)->GetDraft(ev)->SetChangedFromPrev(ev);
  400.  
  401.   CATCH_ALL
  402.  
  403.   ENDTRY
  404.  
  405.   // Return the update id associated with this clipboard operation.
  406.   return clipboardUpdateID;
  407. }
  408.  
  409. Embedding a Part from the Clipboard
  410.  
  411. Embedding from the clipboard is demonstrated using the routine MyEmbedContentSU, which performs the actual work and is described in the Data Interchange Basics document.
  412.  
  413. The targetFrame argument identifies the frame being incorporated into and is passed to MyEmbedContentSU.
  414.  
  415. This method returns the update ID of this clipboard operation. 
  416.  
  417. ODUpdateID MyEmbedFromClipboard (Environment *ev, ODFrame* targetFrame)
  418. {
  419.   ODClipboard* clipboard = fSOMSelf->GetStorageUnit(ev)->GetSession(ev)->GetClipboard(ev);
  420.  
  421.   // Get the content storage unit for the clipboard
  422.   ODStorageUnit* clipContentSU = clipboard->GetContentStorageUnit(ev);
  423.  
  424.   ODVolatile(clipboard);
  425.  
  426.   TRY
  427.  
  428.     fSOMSelf->MyEmbedContentSU(ev, clipContentSU, targetFrame, kODClonePaste, kODNotInLink);
  429.  
  430.     // Associate an update id with this paste, and notify containing parts of this change
  431.     ODUpdateID pasteUpdateID = fSOMSelf->GetStorageUnit(ev)->GetSession(ev)->UniqueUpdateID(ev);
  432.     targetFrame->ContentUpdated(ev, pasteUpdateID);
  433.  
  434.     // Make sure that this change is saved when the document is closed
  435.     fSOMSelf->GetStorageUnit(ev)->GetDraft(ev)->SetChangedFromPrev(ev);
  436.  
  437.   CATCH_ALL
  438.  
  439.   ENDTRY
  440.  
  441.   // Return the update id associated with this clipboard operation.
  442.   return clipboard->ActionDone(ev, kODClonePaste);
  443. }
  444.  
  445. Container Application Requirements
  446.  
  447. Container applications need to call clipboard object methods to ensure synchronization with the host platform clipboard mechanism, and to inform the clipboard of draft closings so the correct move or copy semantics can be enforced.  Parts do not call these methods.
  448.  
  449. The ExportClipboard method must be called by the Container Application whenever the current content of the OpenDoc clipboard must be transferred to the platform clipboard.  On the Macintosh, this includes when the application is suspended or quit.
  450.  
  451. The DraftSaved method must be called to notify the clipboard object that a document draft has been saved.
  452.  
  453. The DraftClosing method must be called to notify the clipboard object that a document draft is closing.  This call must be made before the draft object is closed.
  454.