Annotation of Examples/AppKit/Draw/Links.rtf, revision 1.1.1.1

1.1       root        1: {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;\f1\fmodern Courier;\f2\fnil Times-Roman;\f3\fmodern Ohlfs;}
                      2: \paperw11340
                      3: \paperh8400
                      4: \margl120
                      5: \margr120
                      6: {\colortbl;\red0\green0\blue0;}
                      7: \pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i0\ulnone\fs48\fc0\cf0 Object Links for Draw (file: 
                      8: \f1\fc1\cf1 gvLinks.m
                      9: \f0\fc0\cf0 )
                     10: \fs24 \
                     11: \
                     12: 
                     13: \f2\fs28 There are a number of things you have to do to implement Object Links in an application.  Many of them are optional (depending on the level of functionality you want or are able to provide), but Draw does them ALL, so this should be a good reference point for you.\
                     14: \
                     15: Please refer to the documentation in the system about Object Links to get an overall background in place before reading this document.\
                     16: \
                     17: 
                     18: \f0\fs36\fc1\cf1 DrawDocument\
                     19: 
                     20: \f2\fs28\fc0\cf0 \
                     21: Note first that Object Links only works on a document basis, so the 
                     22: \f1\b\fc1\cf1 GraphicView
                     23: \f2\b0\fc0\cf0  object cannot do links on its own.  Only the 
                     24: \f1\b\fc1\cf1 DrawDocument
                     25: \f2\b0\fc0\cf0  object knows the name of the file, for example, and this is crucial to making links work.  So, even though most of the implementation of Object Links in Draw is in 
                     26: \f1\b\fc1\cf1 GraphicView
                     27: \f2\b0\fc0\cf0  (actually, a category thereof found in 
                     28: \f1\b\fc1\cf1 gvLinks.m
                     29: \f2\b0\fc0\cf0 ), you'll notice that it is the 
                     30: \f1\b\fc1\cf1 DrawDocument
                     31: \f2\b0\fc0\cf0  which creates (and is the delegate of) the 
                     32: \f1\b\fc1\cf1 NXDataLinkManager
                     33: \f2\b0\fc0\cf0 , etc.  However, it usually forwards most of the messages it gets from the 
                     34: \f1\b\fc1\cf1 NXDataLinkManager
                     35: \f2\b0\fc0\cf0  onto the 
                     36: \f1\b\fc1\cf1 GraphicView
                     37: \f2\b0\fc0\cf0 .\
                     38: \
                     39: Note also that a significant part of making Object Links work in Draw is all the messages that 
                     40: \f1\b\fc1\cf1 DrawDocument
                     41: \f2\b0\fc0\cf0  sends TO the 
                     42: \f1\b\fc1\cf1 NXDataLinkManager
                     43: \f2\b0\fc0\cf0  (grep for ``
                     44: \f1\b\fc1\cf1 [linkManager
                     45: \f2\b0\fc0\cf0 '' in 
                     46: \f1\b\fc1\cf1 DrawDocument.m
                     47: \f2\b0\fc0\cf0  to find all those calls).  
                     48: \f1\b\fc1\cf1 DrawDocument
                     49: \f2\b0\fc0\cf0  is responsible for letting the system know when something about the document changes (e.g. the document is saved or closed or reverted to saved or whatever).\
                     50: \
                     51: The ``Publish'' aspect of Draw is done via the 
                     52: \f1\b\fc1\cf1 saveLink:
                     53: \f2\b0\fc0\cf0  method in 
                     54: \f1\b\fc1\cf1 DrawDocument
                     55: \f2\b0\fc0\cf0 .  You should be able to understand the implementation of this method after reading all the description of how Object Links works below.\
                     56: \
                     57: 
                     58: \fc1\cf1 It also calls 
                     59: \f1\b updateLinksPanel
                     60: \f2\b0  from its 
                     61: \f1\b windowDidUpdate:
                     62: \f2\b0  method to keep the Link Inspector panel up to date.\
                     63: \
                     64: Now let's dive into how Draw actually implements the Object Links mechanism ...\
                     65: 
                     66: \fc0\cf0 \
                     67: 
                     68: \f0\fs36\fc1\cf1 Selections\
                     69: 
                     70: \f2\fs28\fc0\cf0 \
                     71: The most important part of participating in Object Links is also the part that requires the most thought.  It is the process of representing a ``selection'' in your document.  It is appropriate that this be the most ``difficult'' thing to do in Object Links because it is the part of the Object Links mechanism that is purely application-dependent.  NeXTSTEP tries to do as much of the Object Links functionality for you, but it cannot do the things that are dependent upon what your application does for a living.\
                     72: \
                     73: 
                     74: \f0\b\fc1\cf1 A ``linked-to
                     75: \f2\b0\fc0\cf0 ''
                     76: \f0\b\fc1\cf1  selection (``source
                     77: \f2\b0\fc0\cf0 ''
                     78: \f0\b\fc1\cf1  selections):\
                     79: 
                     80: \f2\b0\fc0\cf0 \
                     81: If you want people to link to documents in your application, you must be able to describe a selection that the user makes and then copies and pastes (and links) into another document in another application.  This selection description can be anything you want (it's a ``bag o' bits''), but it must survive and make sense no matter what happens to the source document (unless, of course, the items in the selection the user originally made eventually get deleted, but even that case you must detect).\
                     82: \
                     83: How you represent this selection is really something you must think about carefully.  Draw actually has more than one way of representing the selection (this may well be true in the case of your application too).  Draw's selection-representation choice is purely for example purposes and you should, by no means, draw the conclusion that Draw's way is the only way (or even the best way) to represent a selection in an application that manipulates graphical elements (and obviously, Draw's way is not appropriate for text manipulation, spreadsheets, and other kinds of applications).\
                     84: \
                     85: Okay, now that the disclaimer is out of the way, let's talk about how Draw represents selections that it exports to other applications.  First, note that you can get the ``selection'' that the user has made in a 
                     86: \f1\b\fc1\cf1 GraphicView
                     87: \f2\b0\fc0\cf0  at any time by calling the 
                     88: \f1\b\fc1\cf1 currentSelection
                     89: \f2\b0\fc0\cf0  method defined in this file.  It returns an 
                     90: \f1\b\fc1\cf1 NXSelection
                     91: \f2\b0\fc0\cf0  object (the bag o' bits mentioned above) representing the current selection.\
                     92: \
                     93: So, how does Draw represent is current selection?\
                     94: \
                     95: 1. 
                     96: \f1\b\fc1\cf1 [NXSelection allSelection]
                     97: \f2\b0\fc0\cf0 \
                     98: \
                     99: This is the selection that is created when the user does 
                    100: \f0\fs24 Select All
                    101: \f2\fs28  (and only in that case).  The 
                    102: \f1\b\fc1\cf1 allSelection
                    103: \f2\b0\fc0\cf0  method of 
                    104: \f1\b\fc1\cf1 NXSelection
                    105: \f2\b0\fc0\cf0  returns a ``special'' selection that Draw just chooses to know how to interpret.  Most applications will want to handle this special-case of 
                    106: \f1\b\fc1\cf1 allSelection
                    107: \f2\b0\fc0\cf0 .\
                    108: \
                    109: 2. Drag-Selection\
                    110: \
                    111: When the user drags out a box to make a selection in Draw, the 
                    112: \f1\b\fc1\cf1 NXSelection
                    113: \f2\b0\fc0\cf0  that Draw uses to represent that state is the rectangle the user dragged out.  Then, whenever Draw is asked about this 
                    114: \f1\b\fc1\cf1 NXSelection
                    115: \f2\b0\fc0\cf0 , it just intersects that rectangle with the current state of the 
                    116: \f1\b\fc1\cf1 Graphic
                    117: \f2\b0 '
                    118: \fc0\cf0 s in the view.\
                    119: \
                    120: This is a particularly questionable type of selection because the user often ends up with ``not quite what she expected.''  On the other hand, it is a bit more accurate than selection type #3 below because it remembers a bit more of the semantics of what the user selected.  In any case, I have included it to show you what an alternative selection mechanism might be like and how to handle it.\
                    121: \
                    122: The 
                    123: \f1\b\fc1\cf1 getRect:forSelection:
                    124: \f2\b0\fc0\cf0  method returns 
                    125: \f1\b\fc1\cf1 YES
                    126: \f2\b0\fc0\cf0  if the 
                    127: \f1\b\fc1\cf1 NXSelection
                    128: \f2\b0\fc0\cf0  passed to it is of the drag-select type (and, obviously, the ``rect'' that it ``gets'' is the rect the user dragged out to make her original selection).\
                    129: \
                    130: 3. Individual 
                    131: \f1\b\fc1\cf1 Graphic
                    132: \f2\b0\fc0\cf0  Selection\
                    133: \
                    134: In this case, Draw just remembers the unique identifiers of each of the 
                    135: \f1\b\fc1\cf1 Graphic
                    136: \f2\b0 '
                    137: \fc0\cf0 s in the selection.  Then, when the system asks Draw about a selection of this kind, it looks in the current state of the Draw document for all of these items.  Note that it also includes any 
                    138: \f1\b\fc1\cf1 Group
                    139: \f2\b0\fc0\cf0  objects which include one of the 
                    140: \f1\b\fc1\cf1 Graphic
                    141: \f2\b0 '
                    142: \fc0\cf0 s in the original selection.  Users can use this to, for example, have a background which they include in the original copy/paste link and then group whatever image they want to be the ``currently exported thing'' with that background.\
                    143: \
                    144: The best selection mechanism would probably be some mixture of #2 and #3 (and perhaps some other types of selection mechanisms).  I've chosen these two because they are easy to understand.\
                    145: \
                    146: The 
                    147: \f1\b\fc1\cf1 findGraphicsInSelection:
                    148: \f2\b0\fc0\cf0  method returns a 
                    149: \f1\b\fc1\cf1 List
                    150: \f2\b0  
                    151: \fc0\cf0 object with all the 
                    152: \f1\b\fc1\cf1 Graphic
                    153: \f2\b0 '
                    154: \fc0\cf0 s in the current document represented by the 
                    155: \f1\b\fc1\cf1 NXSelection
                    156: \f2\b0\fc0\cf0  passed to it.  This method can handle all three sorts of ``source'' selections (i.e. #1, #2, and #3 above).  This method calls the above-mentioned 
                    157: \f1\b\fc1\cf1 getRect:forSelection:
                    158: \f2\b0\fc0\cf0  method to handle case #2.\
                    159: \
                    160: 
                    161: \f0\b\fc1\cf1 A ``linked-from'' selection (``destination'' selections):\
                    162: 
                    163: \f2\b0\fc0\cf0 \
                    164: If you allow the user to copy something from another application and 
                    165: \f0\fs24\fc1\cf1 Paste and Link
                    166: \f2\fs28\fc0\cf0  it into the documents your application edits, you must be able to describe where in your document the thing was 
                    167: \f0\fs24\fc1\cf1 Paste and Link
                    168: \f2\fs28\fc0\cf0 'ed.  This, too, is just a description of a selection in your document.\
                    169: \
                    170: Since Draw only allows PostScript and TIFF (i.e. 
                    171: \f1\b\fc1\cf1 NXImage
                    172: \f2\b0\fc0\cf0 -handled data types) and RTF and ASCII (i.e. 
                    173: \f1\fc1\cf1 Text
                    174: \f2\fc0\cf0  object-handled data types) to be 
                    175: \f0\fs24\fc1\cf1 Paste and Link
                    176: \f2\fs28\fc0\cf0 'ed in (of course, these are the only types Draw allows to be normal-pasted in as well!), Draw represents this sort of ``destination'' selection by just remembering which 
                    177: \f1\b\fc1\cf1 Image
                    178: \f2\b0\fc0\cf0  or 
                    179: \f1\b\fc1\cf1 TextGraphic
                    180: \f2\b0\fc0\cf0  was created to import the data (since all objects in Draw have a unique identifier associated with them, this is an easy task).\
                    181: \
                    182: There is a method implemented in the 
                    183: \f1\b\fc1\cf1 Graphic
                    184: \f2\b0\fc0\cf0  base class called ``selection'' which returns an 
                    185: \f1\b\fc1\cf1 NXSelection
                    186: \f2\b0\fc0\cf0  which describes the 
                    187: \f1\b\fc1\cf1 Graphic
                    188: \f2\b0\fc0\cf0  you sent the message to in terms of its unique identifier (i.e., it creates an 
                    189: \f1\b\fc1\cf1 NXSelection
                    190: \f2\b0\fc0\cf0  and tosses the unique identifier of the receiving 
                    191: \f1\b\fc1\cf1 Graphic
                    192: \f2\b0\fc0\cf0  into the bag o' bits and returns it to you).  The 
                    193: \f1\b\fc1\cf1 findGraphicInSelection:
                    194: \f2\b0  
                    195: \fc0\cf0 method in this file searches through the document to find the 
                    196: \f1\b\fc1\cf1 Graphic
                    197: \f2\b0\fc0\cf0  with the corresponding unique identifier extracted from the 
                    198: \f1\b\fc1\cf1 NXSelection
                    199: \f2\b0\fc0\cf0  passed to it.\
                    200: \
                    201: 
                    202: \f0\fs36\fc1\cf1 Importing/Exporting Link Data\
                    203: 
                    204: \f2\fs28\fc0\cf0 \
                    205: Okay, so now you understand how Draw creates an 
                    206: \f1\b\fc1\cf1 NXSelection
                    207: \f2\b0\fc0\cf0  object to represent either a selection made in a Draw document which is going to be exported to another application via 
                    208: \f0\fs24\fc1\cf1 Copy/Paste and Link
                    209: \f2\fs28\fc0\cf0  and also how it represents a selection which describes which 
                    210: \f1\b\fc1\cf1 Graphic
                    211: \f2\b0\fc0\cf0  is the receiving end of an Object Link.  Let's quickly talk about how Draw exports a link and how it imports a link.\
                    212: \
                    213: 
                    214: \f0\b\fc1\cf1 Exporting:\
                    215: 
                    216: \f2\b0\fc0\cf0 \
                    217: It exports a link via the method 
                    218: \f1\b\fc1\cf1 writeLinkToPasteboard:types:
                    219: \f2\b0\fc0\cf0 .  This is a very simple method, but very important to the Object Links mechanism.  It does two distinct things:\
                    220: \
                    221: 1. It creates and writes an 
                    222: \f1\b\fc1\cf1 NXDataLink
                    223: \f2\b0\fc0\cf0  object to the 
                    224: \f1\b\fc1\cf1 Pasteboard
                    225: \f2\b0\fc0\cf0  which includes all the stuff another application would need to know to create an Object Link to the current selection the user has made in Draw (primarily just the 
                    226: \f1\b\fc1\cf1 currentSelection
                    227: \f2\b0\fc0\cf0  itself and the data types Draw will export (e.g. PostScript and TIFF)).  This is the most important thing this method does.\
                    228: \
                    229: 2. It writes all of the links in the 
                    230: \f1\b\fc1\cf1 GraphicView
                    231: \f2\b0\fc0\cf0  to the 
                    232: \f1\b\fc1\cf1 Pasteboard
                    233: \f2\b0\fc0\cf0 .\
                    234: \
                    235: Why, you may ask, does it do this?  Well, if you copy an 
                    236: \f1\b\fc1\cf1 Image
                    237: \f2\b0\fc0\cf0  in Draw which is actually the destination of an Object Link (not the source of a link, but the DESTINATION), then if you pasted that 
                    238: \f1\b\fc1\cf1 Image
                    239: \f2\b0\fc0\cf0  into another Draw document, you want it to keep its ``linkness'', i.e., you want the thing you pasted to also get updates when the source of that 
                    240: \f1\b\fc1\cf1 Image
                    241: \f2\b0\fc0\cf0  gets updated.  Simple, huh?\
                    242: \
                    243: Which brings us to the 
                    244: \f1\b\fc1\cf1 readLinkForGraphic:fromPasteboard:useNewIdentifier:
                    245: \f2\b0\fc0\cf0  method.  It's the thing that is called every time you paste a 
                    246: \f1\b\fc1\cf1 Graphic
                    247: \f2\b0\fc0\cf0  into Draw to get that pasted 
                    248: \f1\b\fc1\cf1 Graphic
                    249: \f2\b0\fc0\cf0  properly linked up with the 
                    250: \f1\b\fc1\cf1 NXDataLinkManager
                    251: \f2\b0\fc0\cf0  in the Draw document you paste it into.\
                    252: \
                    253: It is implemented by calling the 
                    254: \f1\b\fc1\cf1 addLinkPreviouslyAt:fromPasteboard:at:
                    255: \f2\b0\fc0\cf0  method in 
                    256: \f1\b\fc1\cf1 NXDataLinkManager
                    257: \f2\b0\fc0\cf0  which simply reestablishes the link that 
                    258: \f1\b\fc1\cf1 Image
                    259: \f2\b0\fc0\cf0  has to another document (that was at 
                    260: \i oldSelection
                    261: \i0  in the old document) by setting the destination selection of the link to the selection which represents the 
                    262: \f1\b\fc1\cf1 Image
                    263: \f2\b0\fc0\cf0 's location in the new document (
                    264: \f1\b\fc1\cf1 [graphic selection]
                    265: \f2\b0\fc0\cf0 ).\
                    266: \
                    267: The 
                    268: \i useNewIdentifier
                    269: \i0  thing is so that if you copy and immediately paste back into the same document, no actual change occurs (this is important in case someone else is linked to something that is in turn linked to something else--just trust me, you want copy/paste from/to the same document to be a net ``no-change'' in the document as far as links are concerned).\
                    270: \
                    271: 
                    272: \f0\b\fc1\cf1 Importing:\
                    273: 
                    274: \f2\b0\fc0\cf0 \
                    275: Importing a linked thing happens 
                    276: \b only
                    277: \b0  via the 
                    278: \f1\b\fc1\cf1 addLink:toGraphic:at:update:
                    279: \f2\b0\fc0\cf0  method.  No where else in Draw is a linked thing added to the document (except, of course in 
                    280: \f1\b\fc1\cf1 readLinkForGraphic:fromPasteboard:useNewIdentifier:
                    281: \f2\b0\fc0\cf0 , but that's a special case).\
                    282: \
                    283: Let's quickly summarize how this method works:\
                    284: \
                    285: The arguments are simple.  The 
                    286: \i link
                    287: \i0  is an 
                    288: \f1\b\fc1\cf1 NXDataLink
                    289: \f2\b0\fc0\cf0  gotten either from a file (
                    290: \f1\b\fc1\cf1 .objlink
                    291: \f2\b0\fc0\cf0 ) or from a 
                    292: \f1\b\fc1\cf1 Pasteboard
                    293: \f2\b0\fc0\cf0  (during 
                    294: \f0\fs24\fc1\cf1 Paste and Link
                    295: \f2\fs28\fc0\cf0 ) or was alloc/init'ed pointing to a file.  See the callers of 
                    296: \f1\b\fc1\cf1 addLink:
                    297: \f2 ...
                    298: \b0\fc0\cf0  to see about that.  The 
                    299: \i graphic
                    300: \i0  is just an 
                    301: \f1\b\fc1\cf1 Image
                    302: \f2\b0\fc0\cf0  or 
                    303: \f1\b\fc1\cf1 TextGraphic
                    304: \f2\b0\fc0\cf0  created from the same 
                    305: \f1\b\fc1\cf1 Pasteboard
                    306: \f2\b0\fc0\cf0  we got the 
                    307: \i link
                    308: \i0  out of or from the file that we alloc/init'ed the 
                    309: \i link
                    310: \i0  to point to.  If 
                    311: \i graphic
                    312: \i0  
                    313: \f1\b\fc1\cf1 nil
                    314: \f2\b0\fc0\cf0 , then we probably got the 
                    315: \i link
                    316: \i0  from a 
                    317: \f1\b\fc1\cf1 .objlink
                    318: \f2\b0\fc0\cf0  file, so we don't actually know what kind of data we're talking about yet.  We take care of that first thing in this method (see the next paragraph).  The 
                    319: \i update
                    320: \i0  argument is used to describe whether this is a normal link, or a link which is never updated (link buttons and links to files represented by the file's icon are the classic examples of these) or a link which must be updated immediately because we don't yet have any data for it (again, see the next paragraph).\
                    321: \
                    322: The first if-statement handles the case of pasting or dragging in an 
                    323: \f1\b\fc1\cf1 NXDataLink
                    324: \f2\b0\fc0\cf0  without any corresponding data (i.e. no PostScript or TIFF to go with it).  This is always the case for a 
                    325: \f1\b\fc1\cf1 .objlink
                    326: \f2\b0\fc0\cf0  file, and could conceivably be the case for a 
                    327: \f0\fs24\fc1\cf1 Copy/Paste and Link
                    328: \f2\fs28\fc0\cf0  if the app that copied the stuff in only copied the 
                    329: \f1\b\fc1\cf1 NXDataLink
                    330: \f2\b0\fc0\cf0  and forgot to (or chose not to for some reason) put the thing being linked to itself in the 
                    331: \f1\b\fc1\cf1 Pasteboard
                    332: \f2\b0\fc0\cf0 .  Anyway, what that first if-statement does is figure out what data types the 
                    333: \f1\b\fc1\cf1 NXDataLink
                    334: \f2\b0\fc0\cf0  deals in (again, e.g., PostScript or RTF or some such) and creates an ``empty'' 
                    335: \f1\b\fc1\cf1 Graphic
                    336: \f2\b0\fc0\cf0  (an 
                    337: \f1\b\fc1\cf1 Image
                    338: \f2\b0\fc0\cf0  or 
                    339: \f1\b\fc1\cf1 TextGraphic
                    340: \f2\b0\fc0\cf0 ) which will be filled in immediately when, later in the method, we force an 
                    341: \f1\b\fc1\cf1 updateDestination
                    342: \f2\b0\fc0\cf0  to occur (setting the update mode to 
                    343: \f1\b\fc1\cf1 UPDATE_IMMEDIATELY
                    344: \f2\b0\fc0\cf0  is what does this).\
                    345: \
                    346: The second if-statement is what's doing all the work, of course.  First, it asks the 
                    347: \f1\b\fc1\cf1 Graphic
                    348: \f2\b0\fc0\cf0  which is going to be the destination of this Object Link (it'll be an 
                    349: \f1\b\fc1\cf1 Image
                    350: \f2\b0\fc0\cf0  or 
                    351: \f1\b\fc1\cf1 TextGraphic
                    352: \f2\b0\fc0\cf0 ) for an 
                    353: \f1\b\fc1\cf1 NXSelection
                    354: \f2\b0\fc0\cf0  object which represents it.  Then it ``adds'' the link to the 
                    355: \f1\b\fc1\cf1 NXDataLinkManager
                    356: \f2\b0\fc0\cf0 .    If the link is successfully added, then we let the 
                    357: \f1\b\fc1\cf1 Image
                    358: \f2\b0\fc0\cf0  or 
                    359: \f1\b\fc1\cf1 TextGraphic
                    360: \f2\b0\fc0\cf0  know about the link to it (only so that we can ask for it back later, the 
                    361: \f1\b\fc1\cf1 Image
                    362: \f2\b0\fc0\cf0  and 
                    363: \f1\b\fc1\cf1 TextGraphic
                    364: \f2\b0\fc0\cf0 's never actually do anything themselves with the link).  Next, we put the 
                    365: \f1\b\fc1\cf1 Graphic
                    366: \f2\b0\fc0\cf0  into the document using the standard 
                    367: \f1\b\fc1\cf1 placeGraphic:at:
                    368: \f2\b0\fc0\cf0  method that we always use to add foreign data to the view (see 
                    369: \f1\b\fc1\cf1 gvPasteboard.m
                    370: \f2\b0\fc0\cf0 ).\
                    371: \
                    372: Finally, if we need to update the link immediately because we have no data, we do so by calling 
                    373: \f1\b\fc1\cf1 updateDestination
                    374: \f2\b0\fc0\cf0 , then ensuring that the update actually caused some data to flow over by seeing if the 
                    375: \f1\b\fc1\cf1 Graphic
                    376: \f2\b0\fc0\cf0  
                    377: \f1\b\fc1\cf1 isValid
                    378: \f2\b0\fc0\cf0 .  This works well for 
                    379: \f1\b\fc1\cf1 Image
                    380: \f2\b0\fc0\cf0 's, but not so well for 
                    381: \f1\b\fc1\cf1 TextGraphic
                    382: \f2\b0\fc0\cf0 's, I'm afraid (they always say they are valid!).  Anyway, it's better than nothing.\
                    383: \
                    384: That's it for exporting and importing links.  Not so bad, is it?\
                    385: \
                    386: 
                    387: \f0\fs36\fc1\cf1 Updating Links\
                    388: 
                    389: \f2\fs28\fc0\cf0 \
                    390: Now, how do we actually update links (in either direction)?  This, too, is simple.  Whenever NeXTSTEP wants you to update someone else who is linked to you, it sends you the message 
                    391: \f1\b\fc1\cf1 copyToPasteboard:at:cheapCopyAllowed:
                    392: \f2\b0\fc0\cf0 .  Whenever NeXTSTEP asks someone else to update something that is linked into your document, it sends you the message 
                    393: \f1\b\fc1\cf1 pasteFromPasteboard:at:
                    394: \f2\b0\fc0\cf0  (or 
                    395: \f1\b\fc1\cf1 importFile:at:
                    396: \f2\b0\fc0\cf0  if it's a whole file).  All you have to do is to responds to these messages sensibly (you should assume that they can be called at any time).  Return 
                    397: \f1\b\fc1\cf1 nil
                    398: \f2\b0\fc0\cf0  from these methods if the 
                    399: \f1\b\fc1\cf1 NXSelection
                    400: \f2\b0\fc0\cf0 's in question no longer exist (in their entirety).\
                    401: \
                    402: Draw's implementation of these methods is very straightforward (these methods are almost always really easy to implement if you already implement 
                    403: \f0\fs24\fc1\cf1 Copy/Paste
                    404: \f2\fs28\fc0\cf0  or 
                    405: \f0\fs24\fc1\cf1 Services
                    406: \f2\fs28\fc0\cf0 ).\
                    407: \
                    408: In 
                    409: \f1\b\fc1\cf1 pasteFromPasteboard:at:
                    410: \f2\b0\fc0\cf0 , it just finds the 
                    411: \f1\b\fc1\cf1 Image
                    412: \f2\b0\fc0\cf0  or 
                    413: \f1\b\fc1\cf1 TextGraphic
                    414: \f2\b0\fc0\cf0  represented by the 
                    415: \f1\b\fc1\cf1 NXSelection
                    416: \f2\b0\fc0\cf0  passed to it (see 
                    417: \f1\b\fc1\cf1 findGraphicInSelection:
                    418: \f2\b0\fc0\cf0 ), then sends a message to that 
                    419: \f1\b\fc1\cf1 Graphic
                    420: \f2\b0\fc0\cf0  to reinitialize itself with the data in the 
                    421: \f1\b\fc1\cf1 Pasteboard
                    422: \f2\b0\fc0\cf0  passed to it.  It then updates the view and marks the view as edited.\
                    423: \
                    424: The method 
                    425: \f1\b\fc1\cf1 importFile:at:
                    426: \f2\b0\fc0\cf0  is just like 
                    427: \f1\b\fc1\cf1 pasteFromPasteboard:at:
                    428: \f2\b0\fc0\cf0 , except that the source of the data comes out of a file instead of from a 
                    429: \f1\b\fc1\cf1 Pasteboard
                    430: \f2\b0\fc0\cf0 .  This happens when you create an Object Link to a whole file without involving the application that knows how to edit that file (see 
                    431: \f1\b\fc1\cf1 gvDrag.m
                    432: \f2\b0\fc0\cf0  and the stuff where we drag a file into Draw with the Control key down (which means create a link to this file)).\
                    433: \
                    434: In 
                    435: \f1\b\fc1\cf1 copyToPasteboard:at:cheapCopyAllowed:
                    436: \f2\b0\fc0\cf0 , there are basically two paths that can be taken depending on whether 
                    437: \i\fc1\cf1 cheapCopyAllowed
                    438: \i0  is true
                    439: \fc0\cf0 .  
                    440: \i cheapCopyAllowed
                    441: \i0  just means that you can use the lazy pasteboard mechanism to the fullest because NeXTSTEP guarantees that no changes to your document can occur between the time this method is called and the time the lazy 
                    442: \f1\b\fc1\cf1 provideData:
                    443: \f2\b0\fc0\cf0  is called.  In other words, when 
                    444: \i cheapCopyAllowed
                    445: \i0  is true, we don't actually have to write the Draw objects in the selection to the pasteboard by value, we can simply write a reference to them.\
                    446: \
                    447: So, in Draw, when 
                    448: \i cheapCopyAllowed
                    449: \i0  is true, we just declare that we can provide PostScript and TIFF, but write neither to the 
                    450: \f1\b\fc1\cf1 Pasteboard
                    451: \f2\b0\fc0\cf0  (we'll provide it lazily).  Of course, when the lazy 
                    452: \f1\b\fc1\cf1 provideData:
                    453: \f2\b0\fc0\cf0  is called, we have to know what part of our document to put into the 
                    454: \f1\b\fc1\cf1 Pasteboard
                    455: \f2\b0\fc0\cf0 , so we simply drop in the 
                    456: \f1\b\fc1\cf1 NXSelection
                    457: \f2\b0\fc0\cf0  that we were asked to 
                    458: \f1\b\fc1\cf1 copyToPasteboard:
                    459: \f2\b0\fc0\cf0 .\
                    460: \
                    461: Thus, in the 
                    462: \i cheapCopyAllowed
                    463: \i0  case, the actual work of putting the data in is done in the INSTANCE method 
                    464: \f1\b\fc1\cf1 pasteboard:provideData:
                    465: \f2\b0\fc0\cf0 !  It is okay to use the instance as the owner of the 
                    466: \f1\b\fc1\cf1 Pasteboard
                    467: \f2\b0\fc0\cf0  because the system has guaranteed us that our document would not be changed (especially not FREED!).  The implementation of 
                    468: \f1\b\fc1\cf1 provideData:
                    469: \f2\b0\fc0\cf0  is really simple since we already had methods lying around that could write the PostScript or TIFF for a list of 
                    470: \f1\b\fc1\cf1 Graphic
                    471: \f2\b0 '
                    472: \fc0\cf0 s into a stream (
                    473: \f1\b\fc1\cf1 write
                    474: \f2 \{
                    475: \f1 PS
                    476: \f2 ,
                    477: \f1 TIFF
                    478: \f2 \}
                    479: \f1 ToStream:usingList:
                    480: \f2\b0\fc0\cf0 ).  We get the list of 
                    481: \f1\b\fc1\cf1 Graphic
                    482: \f2\b0 '
                    483: \fc0\cf0 s to write from the 
                    484: \f1\b\fc1\cf1 NXSelection
                    485: \f2\b0\fc0\cf0  we put in there (see how this all just dovetails together? Idn it great?).\
                    486: \
                    487: When 
                    488: \i cheapCopyAllowed
                    489: \i0  is not true, then we just do what we normally do when the user hits 
                    490: \f0\fs24\fc1\cf1 Copy
                    491: \f2\fs28\fc0\cf0 , we just do it with the 
                    492: \f1\b\fc1\cf1 Graphic
                    493: \f2\b0 '
                    494: \fc0\cf0 s that are in the passed 
                    495: \f1\b\fc1\cf1 NXSelection
                    496: \f2\b0\fc0\cf0  instead of the ones in the current selection.  We plop the list of 
                    497: \f1\b\fc1\cf1 Graphic
                    498: \f2\b0 '
                    499: \fc0\cf0 s into the 
                    500: \f1\b\fc1\cf1 Pasteboard
                    501: \f2\b0\fc0\cf0  and let the normal lazy 
                    502: \f1\b\fc1\cf1 Pasteboard
                    503: \f2\b0\fc0\cf0  stuff take care of the rest (the CLASS method 
                    504: \f1\b\fc1\cf1 pasteboard:provideData:
                    505: \f2\b0\fc0\cf0  in this case, see 
                    506: \f1\b\fc1\cf1 gvPasteboard.m
                    507: \f2\b0\fc0\cf0 ).\
                    508: \
                    509: 
                    510: \f0\fs36\fc1\cf1 Miscellaneous methods.\
                    511: 
                    512: \f2\fs28\fc0\cf0 \
                    513: There's a few other little methods you may want to implement.\
                    514: \
                    515: You'll probably want something akin to 
                    516: \f1\b\fc1\cf1 updateLinksPanel
                    517: \f2\b0\fc0\cf0  which just keeps the Link Inspector panel up to date (it is called from 
                    518: \f1\b\fc1\cf1 windowDidUpdate:
                    519: \f2\b0\fc0\cf0  in 
                    520: \f1\b\fc1\cf1 DrawDocument
                    521: \f2\b0\fc0\cf0 ).\
                    522: \
                    523: The 
                    524: \f1\b\fc1\cf1 showSelection:
                    525: \f2\b0\fc0\cf0  method in 
                    526: \f1\b\fc1\cf1 gvLinks.m
                    527: \f2\b0\fc0\cf0  (the actual names of some of these methods is different, see 
                    528: \f1\b\fc1\cf1 DrawDocument.m
                    529: \f2\b0\fc0\cf0  which forwards them onto 
                    530: \f1\b\fc1\cf1 GraphicView
                    531: \f2\b0\fc0\cf0 ) is sent by NeXTSTEP when the user asks to show the source of an Object Link that comes from your document.  It is very nice to respond properly to this message (the user will certainly be expecting this to work in your application).  It is very easy for Draw to get the bounding box of the 
                    532: \f1\b\fc1\cf1 Graphic
                    533: \f2\b0 '
                    534: \fc0\cf0 s in the passed selection (it even draws the little drag-selection rectangle if that's the kind of 
                    535: \f1\b\fc1\cf1 NXSelection
                    536: \f2\b0\fc0\cf0  it is) since we already have methods lying around that, given a list of 
                    537: \f1\b\fc1\cf1 Graphic
                    538: \f2\b0\fc0\cf0 's can find their bounding box.\
                    539: \
                    540: There is one notable thing that Draw does when showing source selections.  It uses the fact that all the drawing done in a Draw document is actually done in an off-screen cache and composited to the screen.  When Draw shows a source selection, it draws them directly to the on-screen window, then remembers the areas in which it draw (this is the 
                    541: \f1\b\fc1\cf1 invalidRect
                    542: \f2\b0\fc0\cf0 ).  Then, it leaves the source selection showing until the user touches the view (see 
                    543: \f1\b\fc1\cf1 drawSelf::
                    544: \f2\b0\fc0\cf0 ) at which point, it just blows the 
                    545: \f1\b\fc1\cf1 invalidRect
                    546: \f2\b0\fc0\cf0  away by copying that rectangle from the off-screen cache.  If you do double-buffering like this in your application, this trick is easy and effective.\
                    547: \
                    548: The 
                    549: \f1\b\fc1\cf1 breakLinkAndRedrawOutlines:
                    550: \f2\b0\fc0\cf0  method in Draw is what keeps the link outlines up-to-date.  When the user chooses 
                    551: \f0\fs24\fc1\cf1 Show Links
                    552: \f2\fs28\fc0\cf0  from the menu, all things that are linked into your document should show a border around them (there is a NeXTSTEP function to draw this border).  These borders are kind of the opposite of what the 
                    553: \f1\b\fc1\cf1 showSelection:
                    554: \f2\b0\fc0\cf0  method draws (i.e. 
                    555: \f1\b\fc1\cf1 showSelection:
                    556: \f2\b0\fc0\cf0  shows what Object Links originate in your document, and 
                    557: \f0\fs24\fc1\cf1 Show Links
                    558: \f2\fs28\fc0\cf0  shows the Object Links that are linked into your document from somewhere else).  The argument to 
                    559: \f1\b\fc1\cf1 breakLinkAndRedrawOutlines:
                    560: \f2\b0\fc0\cf0  is a 
                    561: \i link
                    562: \i0  that was recently broken by NeXTSTEP (this method is called from 
                    563: \b DrawDocument
                    564: \b0 's 
                    565: \f1\b\fc1\cf1 dataLinkManager:didBreakLink:
                    566: \f2\b0\fc0\cf0  and 
                    567: \f1\b\fc1\cf1 dataLinkManagerRedrawLinkOutlines:
                    568: \f2\b0\fc0\cf0  methods which are sent by NeXTSTEP).\
                    569: \
                    570: If the 
                    571: \i link
                    572: \i0  argument is 
                    573: \f1\b\fc1\cf1 nil
                    574: \f2\b0\fc0\cf0 , it means that no link was broken, so Draw just redraws 
                    575: \b all
                    576: \b0  the link outlines.  If the argument is not 
                    577: \f1\b\fc1\cf1 nil
                    578: \f2\b0\fc0\cf0 , then the method searches for the 
                    579: \f1\b\fc1\cf1 Graphic
                    580: \f2\b0\fc0\cf0  which held that 
                    581: \i link
                    582: \i0  and redraws it so that it's outline goes away.  Furthermore, if it was a link that didn't show the source data (i.e. it was a link button or file icon or something), that 
                    583: \f1\b\fc1\cf1 Graphic
                    584: \f2\b0\fc0\cf0  is removed from the document (since it is now disconnected and useless--don't we all feel that way sometimes?).\
                    585: \
                    586: 
                    587: \f0\fs36\fc1\cf1 Tracking Links\
                    588: 
                    589: \f2\fs28\fc0\cf0 \
                    590: Finally, there is the task of tracking the sources of links.  This is optional behaviour but is really a must if you want to implement 
                    591: \f0\fs24\fc1\cf1 Continually
                    592: \f2\fs28\fc0\cf0  updating links.  The idea here is that you tell NeXTSTEP when a selection which is the source of a link which you export has changed.  Otherwise, NeXTSTEP has to assume that every time your document is edited that all the links that you export have changed.  In other words, this is a performance optimization, but a valuable one.\
                    593: \
                    594: Note that you don't have to track 
                    595: \b all
                    596: \b0  your links, only the ones that are showing up in other documents that are on the screen at the same time.  NeXTSTEP (through the 
                    597: \f1\b\fc1\cf1 NXDataLinkManager
                    598: \f2\b0\fc0\cf0 ) will tell you when to start and stop tracking links (NeXTSTEP is such a polite entity, is it not?).\
                    599: \
                    600: Draw tracks links very easily by making the assumption that if any region of the Draw document which is redrawn overlaps the source of a link, that link must have changed and needs to be updated.  Since Draw has a nice knothole through which all updates to the document go (
                    601: \f1\b\fc1\cf1 cache:
                    602: \f2\b0\fc0\cf0 ), this is a mere matter of keeping track of the boundaries of the sources of links which Draw exports.\
                    603: \
                    604: Draw does this by keeping a 
                    605: \f1\b\fc1\cf1 Storage
                    606: \f2\b0\fc0\cf0  object which a struct in it that has three pieces of information.\
                    607: \
                    608: 1. The rectangle which encloses the source of the link.\
                    609: 2. The link in question.\
                    610: 3. What type of selection is involved (all, drag or normal).\
                    611: \
                    612: Almost every time 
                    613: \f1\b\fc1\cf1 cache:
                    614: \f2\b0\fc0\cf0  is called (sometimes 
                    615: \f1\b\fc1\cf1 cache:
                    616: andUpdateLinks:
                    617: \f2\b0  is called with 
                    618: \f1 NO
                    619: \f2  as its argument
                    620: \fc0\cf0 , but not very often, grep the code and you find out the times when that is necessary) the method 
                    621: \f1\fc1\cf1 updateTrackedLinks:
                    622: \f2\fc0\cf0  is called.  This method has a two-fold purpose:\
                    623: \
                    624: 1. Notify the 
                    625: \f1\b\fc1\cf1 NXDataLinkManager
                    626: \f2\b0\fc0\cf0  if any of the currently-being-tracked links intersects the area which was just 
                    627: \f1\b\fc1\cf1 cache:
                    628: \f2\b0\fc0\cf0 'ed.\
                    629: 2. Reevaluate the bounds of any of the source selections that intersects the area which was just 
                    630: \f1\b\fc1\cf1 cache:
                    631: \f2\b0\fc0\cf0 'ed.\
                    632: \
                    633: We must do step #2, because the thing that might have caused 
                    634: \f1\b\fc1\cf1 cache:
                    635: \f2\b0\fc0\cf0  to get called could have been that the user resized one of the objects which are linked to.  Thus, step #2 is not necessary for the drag-selection (since that originally dragged-out box can never ``change size'') and 
                    636: \f1\b\fc1\cf1 allSelection
                    637: \f2\b0\fc0\cf0  cases.  Step #2 is implemented simply by getting the 
                    638: \f1\b\fc1\cf1 NXSelection
                    639: \f2\b0\fc0\cf0  from the link, calling 
                    640: \f1\b\fc1\cf1 findGraphicsInSelection:
                    641: \f2\b0\fc0\cf0 , then calling the already-existing 
                    642: \f1\b\fc1\cf1 getBBox:of:
                    643: \f2\b0\fc0\cf0  method.\
                    644: \
                    645: All we do in 
                    646: \f1\b\fc1\cf1 startTrackingLinks:
                    647: \f2\b0\fc0\cf0  and 
                    648: \f1\b\fc1\cf1 stopTrackingLinks:
                    649: \f2\b0\fc0\cf0  is add/remove structs from the 
                    650: \f1\b\fc1\cf1 Storage
                    651: \f2\b0\fc0\cf0  object.\
                    652: \
                    653: 
                    654: \f0\fs36\fc1\cf1 Summary\
                    655: 
                    656: \f2\fs28\fc0\cf0 \
                    657: Well, that's all there is about links and Draw.  I hope this document is illuminating.  The take-home messages should be that Object Links should be simple to implement if you already implement 
                    658: \f0\fs24\fc1\cf1 Copy/Paste
                    659: \f2\fs28\fc0\cf0  and/or 
                    660: \f0\fs24\fc1\cf1 Services
                    661: \f2\fs28\fc0\cf0 .  The only ``hard part'' might be figuring out how to represent a selection in your document.  Good luck with that part. :-)\
                    662: 
                    663: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.