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 / Documentation / Engineering Notes / Embedding / Basic Embedding next >
Encoding:
Text File  |  1996-08-16  |  14.0 KB  |  371 lines  |  [TEXT/ttxt]

  1. OpenDoc
  2. Development
  3. Framework
  4.                                                                                                                                                                                      
  5. Basic Embedding 
  6. ODF Release 1                                                                                                                                                             
  7.  
  8.  
  9. Table of Contents
  10. -------------------
  11. • Overview
  12. • FW_MProxy & Data Structures
  13. • Content Objects
  14. • Frame Object
  15. • Selection Object
  16.  
  17.  
  18. Overview
  19.  
  20. One of the major benefits of using ODF is in the area of embedding. ODF  makes embedding much easier to implement and also makes your part behave correctly by following the OpenDoc guidelines. 
  21.  
  22. How you implement embedding is very dependent on the intrinsic content of your part (text, spreadsheet, drawing, ...). You cannot implement embedding without thinking about your data, how you will present it, and how the user is going to interact with it. 
  23.  
  24. ODF provides several examples of embedding part editors, each with a different content model. For example the ODFDraw part editor shows one way of implementing embedding in the context of a drawing part. We think this is a very interesting case because of the direct interaction between intrinsic content (rectangles, oval objects...) and embedded frames (z-ordering, direct user interaction to resize or move objects...). 
  25.  
  26. Note that ODFDraw is a relatively complex part editor. Your part editor may not have to implement everything that it implements. For example, embedded frames in ODFDraw can be partially hidden behind other frames or drawing objects. For this reason the ODFDraw part editor has a CDrawFacetClipper object that calculates the clipping shape of embedded frames. Your part editor may not have overlapping embedded frames. In that case you will not have to use a facet clipper. An example of a part editor without overlapping embedded frames is ODFTable.
  27.  
  28. FW_MProxy & Data Structures
  29.  
  30. The first thing you have to do in order to support embedding is to find a way to incorporate the FW_MProxy class defined by ODF into your data structure classes (as a mix in or simply as a field in another class)
  31.  
  32. For example, the ODFDraw class hierarchy (without embedding) looks like this:
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40.  
  41. This is a very simple class hierarchy. Draw objects (rectangles, ovals, lines...) are maintained in a z-ordered collection. Every shape object has the following protocol:
  42.  
  43. - draw
  44. - set and Get Properties (foreground or background color, pen size, pattern etc.)
  45. - flatten (persistence)
  46. - resize
  47. - move
  48. - and more...
  49.  
  50. Supporting embedding required us to add a new type of shape (CProxyShape).
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.  
  60. CProxyShape is a subclass of CRectShape. CProxyShape is also a subclass of FW_MProxy. 
  61.  
  62. It is easier to explain what an FW_MProxy is by using an example. The following figure shows the ODFDraw part editor embedded in a root part (it doesn’t matter what this root part is). Notice that the ODFDraw part editor is active, and has some intrinsic content (a rectangle and an oval) and another part embedded in it (a clock part).
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73. The user selects View in Window. 
  74.  
  75.  
  76.  
  77.  
  78.  
  79.  
  80.  
  81.  
  82.  
  83.  
  84.  
  85.  
  86.  
  87.  
  88.  
  89. The Draw part now has two display frames (frame1 and frame2) and two embedded frames (one in frame1 and one in frame2). 
  90.  
  91. If the user decides to move a graphic object, like the rectangle, it is obvious that the rectangle object in frame1 and frame2 should move the same way. After all, both frames display the same document. Now if the user decides to move the clock it should also move the same way in both frames. There should not be any difference for the user between a rectangle object and the clock. The problem is that the clock in frame1 and the clock in frame2 are displayed in two different embedded frames. You need a way to synchronize those two embedded frames so that moving one will also move the other one. This is what FW_MProxy provides. It is a list of the embedded frames that represent the same object in your data structure. 
  92.  
  93.  
  94. The ProxyShape move protocol, for example, iterates through all the embedded frames in the proxy list, moving them one by one.
  95.  
  96. Your subclass of FW_MProxy will usually have to override the following methods:
  97.  
  98. - UsedShapeChanged: One of your embedded frames has changed its used shape. Your part editor, depending on its content model, may have to recalculate its embedded facet’s clip shape.
  99.  
  100. - FrameShapeRequested: One of your embedded frames is requesting a new frame shape. Depending on your content model you may grant or refuse this request. By default ODF always grants the request. For this reason, ODFTable has to override FrameShapeRequested because embedded frames always have the size of their containing cell.
  101.  
  102. //-----------------------------------------------------------------------
  103. //    CTableProxy::FrameShapeRequested
  104. //-----------------------------------------------------------------------
  105.  
  106. ODShape* CTableProxy::FrameShapeRequested(Environment* ev, 
  107.                             ODFrame* odEmbeddedFrame, 
  108.                             ODShape* askedFrameShape)
  109. {
  110. FW_UNUSED(askedFrameShape);
  111.  
  112.     // ----- Get the size of the cell -----
  113.     FW_CRect cellRect;
  114.     fTablePart->FindRect(fCell, cellRect);
  115.  
  116.     // ----- Frame shapes are always zero based -----
  117.     cellRect.Place(FW_kZeroPoint);
  118.     ODShape* cellShape = ::FW_NewODShape(ev, cellRect);
  119.     
  120.     return cellShape;
  121. }
  122.  
  123. - AdjustBorderShape: this method is called in order to adjust one of your embedded facet’s active border shape.
  124.  
  125. You may also want to call the following methods:
  126.  
  127. - FW_MProxy::ChangeExternalTransforms: call ChangeExternalTransforms when you want to move an embedded facet in each one of your display frames.
  128.  
  129. - FW_MProxy::ChangeFrameShapes: call ChangeFrameShapes when you want to change the size of one of your embedded frames in each one of your display frames.
  130.  
  131. Content Objects
  132.  
  133. Three methods of your Content Objects (derived from of FW_CEmbeddingContent) are directly affected by embedding: 
  134.  
  135. - Internalize
  136. - Externalize
  137. - SingleEmbeddedFrameInternalized
  138.  
  139. Remember that it is your responsibility to internalize/externalize your embedded frames along with your data in the kODPropContents property. ODF does not provide any default behavior because ODF does not know anything about your content model. It is your responsibility to call FW_MProxy::Internalize/Externalize in your override of FW_CEmbeddingContent::Internalize/Externalize.
  140.  
  141. Here is an example from ODFTable:
  142.  
  143. //----------------------------------------------------------------------------
  144. //    CTableContent::Externalize
  145. //----------------------------------------------------------------------------
  146. void CTableContent::Externalize(Environment* ev,
  147.                     ODStorageUnit* storageUnit, 
  148.                     FW_EStorageKinds storageKind,
  149.                     FW_CCloneInfo* cloneInfo)
  150. {
  151.     FW_UNUSED(storageKind);
  152.  
  153.     // ---- Write out grid info ----
  154.     FW_PStorageUnitSink suSink(ev, storageUnit, kODPropContents, fTablePart->GetPartKind(ev));
  155.     FW_CWritableStream archive(suSink);
  156.  
  157.     archive << fCells.fX;
  158.     archive << fCells.fY;
  159.     archive.Write(fWidth, fCells.fX);
  160.     archive.Write(fHeight, fCells.fY);
  161.  
  162.     // ---- Write number of embedded parts ----
  163.     unsigned long partCount = fProxys->Count();
  164.     archive << partCount;
  165.  
  166.     // ---- Write out embedded parts ----
  167.     if (partCount > 0)
  168.     {
  169.         FW_TOrderedCollectionIterator<CTableProxy> iter(fProxys);
  170.         for (CTableProxy* proxy = iter.First(); iter.IsNotComplete(); proxy = iter.Next())
  171.         {
  172.             CCell cell = proxy->GetCell();
  173.             archive << cell.fX;
  174.             archive << cell.fY;
  175.             proxy->Externalize(ev, suSink.GetStorageUnitSink()->GetStorageUnitView(ev), cloneInfo);
  176.         }
  177.     }
  178.  
  179.     //--- Write source and destination links, if any ---
  180.     CTableLinkManager* linkMgr = (CTableLinkManager*) fTablePart->GetLinkManager(ev);
  181.     linkMgr->ExternalizeLinks(ev, storageUnit, cloneInfo);
  182. }
  183.  
  184. //----------------------------------------------------------------------------
  185. //    CTableContent::Internalize
  186. //----------------------------------------------------------------------------
  187. FW_Boolean CTableContent::Internalize(Environment* ev,
  188.                         ODStorageUnit* storageUnit, 
  189.                         FW_EStorageKinds storageKind,
  190.                         FW_CCloneInfo* cloneInfo)
  191. {
  192.     FW_UNUSED(storageKind);
  193.  
  194.     if (!storageUnit->Exists(ev, 
  195.                     kODPropContents, 
  196.                     fTablePart->GetPartKind(ev), 0))
  197.         return false;
  198.  
  199.     // ---- Read grid info -----
  200.     FW_PStorageUnitSink suSink(ev, storageUnit, kODPropContents, fTablePart->GetPartKind(ev));
  201.     FW_PBufferedSink sink(ev, suSink);
  202.     FW_CReadableStream archive(sink);
  203.  
  204.     archive >> fCells.fX;
  205.     archive >> fCells.fY;
  206.  
  207.     FW_ASSERT(fCells.fX == kMaxCols);
  208.     archive.Read(fWidth, fCells.fX);
  209.  
  210.     FW_ASSERT(fCells.fY == kMaxRows);
  211.     archive.Read(fHeight, fCells.fY);
  212.  
  213.     // ---- Read number of embedded parts ----
  214.     unsigned long partCount;
  215.     archive >> partCount;
  216.  
  217.     // ---- Read embedded parts ----
  218.     CCell cell;
  219.     CTableProxy* proxy;
  220.     for (unsigned long i = 0; i < partCount; i++)
  221.     {
  222.         archive >> cell.fX;
  223.         archive >> cell.fY;
  224.         proxy = new CTableProxy(ev, fTablePart, this, fTablePart->GetTablePresentation(ev));
  225.         proxy->SetCell(cell);
  226.         proxy->Internalize(ev, suSink.GetStorageUnitSink()->GetStorageUnitView(ev), cloneInfo);        // read part and embed it
  227.         this->AddProxy(proxy);
  228.     }
  229.  
  230.     // ----- Read link information -----
  231.     CTableLinkManager* linkMgr = (CTableLinkManager*) fTablePart->GetLinkManager(ev);
  232.     linkMgr->InternalizeLinks(ev, storageUnit);
  233.     
  234.     return true;
  235. }
  236.  
  237. Your selection's content object (the subclass of FW_CEmbeddingContent associated with your FW_CSelection object) must override SingleEmbeddedFrameInternalized. This method is called when a single embedded frame is copied or dragged into one of your frame. If more than one embedded frames needs to be added to your content, then the Internalize method of your selection's content object will be called instead.
  238.  
  239. Along with the embedded frame, a suggested frame shape is also provided. This suggested frame shape can be NULL; in this case you should provide a default frame shape consistent with your content model. The suggested frame shape could also be completely ignored (see ODFTable).
  240.  
  241. //----------------------------------------------------------------------------------------
  242. //    CTableSelectionContent::SingleEmbeddedFrameInternalized
  243. //----------------------------------------------------------------------------------------
  244.  
  245. void CTableSelectionContent::SingleEmbeddedFrameInternalized(Environment* ev, 
  246.                 FW_CEmbeddingFrame* scopeFrame,
  247.                 ODPart* embeddedPart, 
  248.                 ODFrame* embeddedFrame,
  249.                 ODShape* suggestedShape,
  250.                 ODTypeToken viewType)
  251. {
  252.     FW_UNUSED(suggestedShape);
  253.     
  254.     CCell selectionCell = GetCell();
  255.     
  256.     CTableProxy* proxy = fTableContent->CellToProxy(selectionCell);
  257.     
  258.     FW_CRect rect;
  259.     fTableContent->FindRect(selectionCell, rect);
  260.     rect.Place(FW_kZeroPoint);
  261.  
  262.     FW_CAcquiredODShape aqShape = ::FW_NewODShape(ev, rect);
  263.  
  264.     // ----- Create the proxy -----
  265.     CTableProxy* newProxy = new CTableProxy(ev, fTablePart, fTableContent, scopeFrame->GetPresentation(ev));
  266.     newProxy->SetCell(selectionCell);
  267.  
  268.     // ----- Add the newProxy to the part -----
  269.     fTableContent->AddProxy(newProxy);
  270.     
  271.     // ----- Embed the part or the frame -----
  272.     scopeFrame->GetPresentation(ev)->Embed(ev, 
  273.                         embeddedPart,
  274.                         embeddedFrame,
  275.                         kODFrameObject,    
  276.                         newProxy,
  277.                         aqShape,
  278.                         viewType,
  279.                         NULL,        // no presentation
  280.                         0,        // group id
  281.                         false,        // overlaid
  282.                         false);        // sub frame
  283.  
  284.     // ----- Delete the old proxy if there was one in the cell
  285.     if (proxy != NULL)
  286.     {
  287.         proxy->DetachEmbeddedFrames(ev);
  288.         fTableContent->RemoveProxy(proxy);
  289.         delete proxy;
  290.     }
  291.  
  292.     // ----- Select the new proxy -----
  293.     newProxy->Selected(TRUE);
  294.     
  295.     // ----- Change its hilite state
  296.     if (scopeFrame && scopeFrame->HasSelectionFocus(ev))
  297.         newProxy->ChangeHighlight(ev, 
  298.                     scopeFrame->GetWindow(ev)->IsActive(ev) ?                                 kODFullHighlight : kODDimHighlight, 
  299.                     scopeFrame);
  300.  
  301. }
  302.  
  303.  
  304. Frame Object
  305.  
  306. Your frame object, in the case where you want to support embedding, must be a subclass of FW_CEmbeddingFrame. The minimum API you need to support is:
  307.  
  308. - CreateEmbeddedFacet:  is called to let you create your embedded facets. Don’t forget that as an embedding part, you are in charge of creating your embedded frame’s facets. The embedded facet’s external transform describes the location of embedded frames.
  309.  
  310. //----------------------------------------------------------------------------------------
  311. //    CDrawFrame::CreateEmbeddedFacet
  312. //----------------------------------------------------------------------------------------
  313.  
  314. ODFacet* CDrawFrame::CreateEmbeddedFacet(Environment* ev,
  315.                         ODFacet* embeddingFacet,
  316.                         FW_MProxy* proxy,
  317.                         ODFrame* embeddedFrame,
  318.                         ODShape* proposedClipShape)
  319. {
  320.     FW_CRect embeddedFrameBounds = ((CProxyShape*)proxy)->GetFrameRect(ev);
  321.     
  322.     FW_CAcquiredODTransform aqExternalTransform = ::FW_NewODTransform(ev, embeddedFrameBounds.TopLeft());
  323.  
  324.     return embeddingFacet->CreateEmbeddedFacet(ev,
  325.                             embeddedFrame,
  326.                             proposedClipShape,
  327.                             aqExternalTransform,
  328.                             NULL,        // Canvas
  329.                             NULL,        // biasCanvas
  330.                             NULL,        // siblingFacet
  331.                             kODFrameInFront);
  332. }
  333.  
  334.  
  335. Selection Object
  336.  
  337. The minimum API you need to support is:
  338.  
  339. - UpdateSelectionOnMouseDown is called as a result of a mouse down event. Although UpdateSelectionOnMouseDown is not specific to embedding, one of its parameters is ‘inEmbeddedFrameBorder’. This means that the user has clicked in the active border of one of your embedded facets.
  340.  
  341. //-----------------------------------------------------------------------
  342. // CDrawSelection::UpdateSelectionOnMouseDown
  343. //-----------------------------------------------------------------------
  344.  
  345. void CDrawSelection::UpdateSelectionOnMouseDown(Environment* ev, 
  346.                         const FW_CMouseEvent& mouseEvent,
  347.                         ODFacet* embeddedFacet,
  348.                         FW_Boolean inEmbeddedFrameBorder,
  349.                         FW_Boolean inBackground)
  350. {
  351.     if (inEmbeddedFrameBorder)
  352.     {
  353.         fClickedHandle = 0;
  354.         fAnchorShape = NULL;
  355.  
  356.         CProxyShape *theShape = (CProxyShape*)fDrawPart->FindProxy(ev,                         embeddedFacet->GetFrame(ev)->GetID(ev));
  357.             
  358.         this->CloseSelection(ev);
  359.         this->AddToSelection(ev, theShape, TRUE);
  360.         
  361.         fAnchorShape = theShape;
  362.     }
  363.     else
  364.     {
  365.         .....
  366.     }
  367. }
  368.  
  369.  
  370. © 1993 - 1996 Apple Computer, Inc. All rights reserved.
  371. Apple, the Apple Logo, Macintosh, and OpenDoc are trademarks of Apple Computer, Inc., registered in the United States and other countries.