Annotation of Examples/AppKit/Draw/gvLinks.m, revision 1.1.1.1

1.1       root        1: #import "draw.h"
                      2: 
                      3: @implementation GraphicView(Links)
                      4: 
                      5: /* See the Links.rtf file for overview about Object Links in Draw. */
                      6: 
                      7: #define BUFFER_SIZE 1100
                      8: #define INT_WIDTH 11
                      9: 
                     10: /*
                     11:  * Returns an NXSelection describe the current Graphic's selected in the view.
                     12:  * If the user did Select All, then the gvFlags.selectAll bit is set and we
                     13:  * return the allSelection NXSelection.  If the user dragged out a rectangle,
                     14:  * then the dragRect rectangle is set and we return a ByRect NXSelection.
                     15:  * Otherwise, we return a ByGraphic NXSelection.
                     16:  *
                     17:  * We use the writeIdentifierTo: mechanism so that Group Graphic's can ask
                     18:  * their components to write out all their identifiers so that we have a
                     19:  * maximal chance of getting all the objects.
                     20:  */
                     21: 
                     22: - (NXSelection *)currentSelection
                     23: {
                     24:     NXRect sbounds;
                     25:     int i, graphicCount;
                     26:     NXSelection *retval = nil;
                     27:     char *s, *selbuf, buffer[BUFFER_SIZE];
                     28: 
                     29:     if (![slist count]) return [NXSelection emptySelection];
                     30: 
                     31:     if (gvFlags.selectAll) {
                     32:        if ([slist count] == [glist count]) {
                     33:            return [NXSelection allSelection];
                     34:        } else {
                     35:            gvFlags.selectAll = NO;
                     36:        }
                     37:     }
                     38: 
                     39:     if (dragRect) {
                     40:        sbounds = *dragRect;
                     41:        sprintf(buffer, "%d %d %d %d %d", ByRect, 
                     42:            (int)sbounds.origin.x, (int)sbounds.origin.y,
                     43:            (int)(sbounds.size.width+0.5), (int)(sbounds.size.height+0.5));
                     44:        selbuf = buffer;
                     45:     } else {
                     46:        graphicCount = 0;
                     47:        i = [slist count];
                     48:        while (i--) graphicCount += [[slist objectAt:i] graphicCount];
                     49:        if (graphicCount > (BUFFER_SIZE / INT_WIDTH)) {
                     50:            NX_MALLOC(selbuf, char, graphicCount * INT_WIDTH);
                     51:        } else {
                     52:            selbuf = buffer;
                     53:        }
                     54:        sprintf(buffer, "%d %d", ByList, graphicCount);
                     55:        s = selbuf + strlen(selbuf);
                     56:        i = [slist count];
                     57:        while (i--) {
                     58:            *s++ = ' ';
                     59:            [[slist objectAt:i] writeIdentifierTo:s];
                     60:            s += strlen(s);
                     61:        }
                     62:     }
                     63: 
                     64:     retval = [[NXSelection allocFromZone:[self zone]] initWithDescription:selbuf length:strlen(selbuf)+1];
                     65: 
                     66:     if (selbuf != buffer) free(selbuf);
                     67: 
                     68:     return retval;
                     69: }
                     70: 
                     71: /*
                     72:  * Used for destination selections only.
                     73:  * Just extracts the unique identifier for the destination Image
                     74:  * or TextGraphic and then searches through the glist to find that
                     75:  * Graphic and returns it.
                     76:  *
                     77:  * Again, we use the graphicIdentifiedBy: mechanism so that we
                     78:  * descend into Group's of Graphics to find a destination.
                     79:  */
                     80: 
                     81: - (Graphic *)findGraphicInSelection:(NXSelection *)selection
                     82: {
                     83:     int i;
                     84:     Graphic *graphic;
                     85:     const char *selectionInfo;
                     86:     int selectionInfoLength, identifier, selectionType;
                     87: 
                     88:     selectionInfo = [selection descriptionOfLength:&selectionInfoLength];
                     89:     if (selectionInfo) {
                     90:        sscanf(selectionInfo, "%d %d", &selectionType, &identifier);
                     91:        if (selectionType == ByGraphic) {
                     92:            for (i = [glist count]-1; i >= 0; i--) {
                     93:                if (graphic = [[glist objectAt:i] graphicIdentifiedBy:identifier]) return graphic;
                     94:            }
                     95:        }
                     96:     }
                     97: 
                     98:     return nil;
                     99: }
                    100: 
                    101: /*
                    102:  * Returns YES and theRect is valid only if the selection is one which
                    103:  * the user created by dragging out a rectangle.
                    104:  */
                    105: 
                    106: - (BOOL)getRect:(NXRect *)theRect forSelection:(NXSelection *)selection
                    107: {
                    108:     NXRect stackRect;
                    109:     const char *selectionInfo;
                    110:     int selectionInfoLength;
                    111:     DrawSelectionType selectionType;
                    112: 
                    113:     if (selectionInfo = [selection descriptionOfLength:&selectionInfoLength]) {
                    114:        if (!theRect) theRect = &stackRect;
                    115:        sscanf(selectionInfo, "%d %f %f %f %f", (int *)&selectionType,
                    116:                &(theRect->origin.x), &(theRect->origin.y),
                    117:                &(theRect->size.width), &(theRect->size.height));
                    118:        if (selectionType == ByRect) return YES;
                    119:     }
                    120: 
                    121:     return NO;
                    122: }
                    123: 
                    124: /*
                    125:  * For source selections only.
                    126:  * Returns the list of Graphics in the current document which were
                    127:  * in the selection passed to this method.  Note that any Group 
                    128:  * which includes a Graphic in the passed selection will be included
                    129:  * in its entirety.
                    130:  */
                    131: 
                    132: - (List *)findGraphicsInSelection:(NXSelection *)selection
                    133: {
                    134:     int i, count;
                    135:     Graphic *graphic;
                    136:     List *list = nil;
                    137:     NXRect sBounds, gBounds;
                    138:     int selectionInfoLength;
                    139:     const char *s, *theGraphics;
                    140:     DrawSelectionType selectionType;
                    141: 
                    142:     if ([selection isEqual:[NXSelection allSelection]]) {
                    143:        count = [glist count];
                    144:        list = [[List allocFromZone:[self zone]] initCount:count];
                    145:        for (i = 0; i < count; i++) [list addObject:[glist objectAt:i]];
                    146:     } else if ([self getRect:&sBounds forSelection:selection]) {
                    147:        count = [glist count];
                    148:        list = [[List allocFromZone:[self zone]] init];
                    149:        for (i = 0; i < count; i++) {
                    150:            graphic = [glist objectAt:i];
                    151:            [graphic getBounds:&gBounds];
                    152:            NXInsetRect(&gBounds, -0.1, -0.1);
                    153:            if (NXIntersectsRect(&gBounds, &sBounds)) [list addObject:graphic];
                    154:        }
                    155:     } else if (s = [selection descriptionOfLength:&selectionInfoLength]) {
                    156:        sscanf(s, "%d %d", (int *)&selectionType, &count);
                    157:        if (selectionType == ByList) {
                    158:            if (s = strchr(s, ' ')) s = strchr(s+1, ' ');
                    159:            if (s++) {
                    160:                theGraphics = s;
                    161:                list = [[List allocFromZone:[self zone]] init];
                    162:                count = [glist count];
                    163:                for (i = 0; i < count; i++) {
                    164:                    graphic = [glist objectAt:i];
                    165:                    s = theGraphics;
                    166:                    while (s && *s) {
                    167:                        if ([graphic graphicIdentifiedBy:atoi(s)]) {
                    168:                            [list addObject:graphic];
                    169:                            break;
                    170:                        }
                    171:                        if (s = strchr(s, ' ')) s++;
                    172:                    }
                    173:                }
                    174:            }
                    175:        }
                    176:     }
                    177: 
                    178:     if (![list count]) {
                    179:        [list free];
                    180:        list = nil;
                    181:     }
                    182: 
                    183:     return list;
                    184: }
                    185: 
                    186: /*
                    187:  * Importing/Exporting links.
                    188:  */
                    189: 
                    190: /*
                    191:  * This method is called by copyToPasteboard:.  It just puts a link to the currentSelection
                    192:  * (presumably just written to the pasteboard by copyToPasteboard:) into the specified
                    193:  * pboard.  Note that it only does all this if we are writing all possible types to the
                    194:  * pasteboard (typesList == NULL) or if we explicitly ask for the link to be written
                    195:  * (typesList includes NXDataLinkPboardType).
                    196:  */
                    197: 
                    198: - writeLinkToPasteboard:(Pasteboard *)pboard types:(const NXAtom *)typesList
                    199: {
                    200:     NXDataLink *link;
                    201: 
                    202:     if (linkManager && (!typesList || IncludesType(typesList, NXDataLinkPboardType))) {
                    203:        if (link = [[NXDataLink alloc] initLinkedToSourceSelection:[self currentSelection] managedBy:linkManager supportingTypes:TypesDrawExports() count:NUM_TYPES_DRAW_EXPORTS]) {
                    204:            [pboard addTypes:&NXDataLinkPboardType num:1 owner:[self class]];
                    205:            [link writeToPasteboard:pboard];
                    206:            [link free];
                    207:        }
                    208:        [linkManager writeLinksToPasteboard:pboard]; // for embedded linked things
                    209:     }
                    210: 
                    211:     return self;
                    212: }
                    213: 
                    214: /*
                    215:  * Sets up a link from the Draw document to another document.
                    216:  * This is called by the drag stuff (gvDrag.m) and the normal copy/paste stuff (gvPasteboard.m).
                    217:  * We allow for the case of graphic being nil as long as the link is capable of supplying
                    218:  * data of a type we can handle (currently Text or Image).
                    219:  */
                    220: 
                    221: - (BOOL)addLink:(NXDataLink *)link toGraphic:(Graphic *)graphic at:(const NXPoint *)p update:(int)update
                    222: {
                    223:     NXSelection *selection = nil;
                    224: 
                    225:     if (!graphic && link && update != UPDATE_NEVER) {
                    226:        if (TextPasteType([link types])) {
                    227:            graphic = [[TextGraphic allocFromZone:[self zone]] initEmpty];
                    228:        } else if (MatchTypes([link types], [NXImage imagePasteboardTypes])) {
                    229:            graphic = [[Image allocFromZone:[self zone]] initEmpty];
                    230:        }
                    231:        update = UPDATE_IMMEDIATELY;
                    232:     }
                    233: 
                    234:     if (graphic && link) {
                    235:        selection = [graphic selection];
                    236:        if ([linkManager addLink:link at:selection]) {
                    237:            if (!update) [link setUpdateMode:NX_UpdateNever];
                    238:            [graphic setLink:link];
                    239:            if (graphic = [self placeGraphic:graphic at:p]) {
                    240:                if (update == UPDATE_IMMEDIATELY) {
                    241:                    [link updateDestination];
                    242:                    graphic = [self findGraphicInSelection:selection];
                    243:                    if (![graphic isValid]) {
                    244:                        NXRunLocalizedAlertPanel(NULL, "Import Link",
                    245:                            "Unable to import linked data.", NULL, NULL, NULL,
                    246:                            "Message given to user when import of linked data fails.");
                    247:                        [self removeGraphic:graphic];
                    248:                    } else {
                    249:                        return YES;
                    250:                    }
                    251:                } else {
                    252:                    return YES;
                    253:                }
                    254:            }
                    255:        }
                    256:     }
                    257: 
                    258:     [link free];
                    259:     [selection free];
                    260:     [graphic free];
                    261: 
                    262:     return NO;
                    263: }
                    264: 
                    265: /*
                    266:  * Keeping links up to date.
                    267:  * These methods are called either to update a link that draw has to another
                    268:  * document or to cause Draw to update another document that is linked to it.
                    269:  */
                    270: 
                    271: /*
                    272:  * Sent whenever NeXTSTEP wants us to update some data in our document which
                    273:  * we get by being linked to some other document.
                    274:  */
                    275: 
                    276: - pasteFromPasteboard:(Pasteboard *)pboard at:(NXSelection *)selection
                    277: {
                    278:     id graphic;
                    279:     NXRect gBounds;
                    280: 
                    281:     if (graphic = [self findGraphicInSelection:selection]) {
                    282:        gBounds = [graphic reinitFromPasteboard:pboard];
                    283:        [self cache:&gBounds];  // updating a destination link
                    284:        [window flushWindow];
                    285:        [self dirty];
                    286:        return self;
                    287:     }
                    288: 
                    289:     return nil;
                    290: }
                    291: 
                    292: /*
                    293:  * Lazy pasteboard method for cheapCopyAllowed case ONLY.
                    294:  * See copyToPasteboard:at:cheapCopyAllowed: below.
                    295:  */
                    296: 
                    297: - pasteboard:(Pasteboard *)sender provideData:(const char *)type
                    298: {
                    299:     List *list;
                    300:     NXStream *stream;
                    301:     NXSelection *selection;
                    302: 
                    303:     selection = [[NXSelection allocFromZone:[self zone]] initFromPasteboard:sender];
                    304:     list = [self findGraphicsInSelection:selection];
                    305:     if (list && (stream = NXOpenMemory(NULL, 0, NX_WRITEONLY))) {
                    306:        if (type == NXPostScriptPboardType) {
                    307:            [self writePSToStream:stream usingList:list];
                    308:        } else if (type == NXTIFFPboardType) {
                    309:            [self writeTIFFToStream:stream usingList:list];
                    310:        }
                    311:        [sender writeType:type fromStream:stream];
                    312:        NXCloseMemory(stream, NX_FREEBUFFER);
                    313:     }
                    314:     [list free];
                    315:     [selection free];
                    316: 
                    317:     return self;
                    318: }
                    319: 
                    320: /*
                    321:  * Called by NeXTSTEP when some other document needs to be updated because
                    322:  * they are linked to something in our document.
                    323:  */
                    324: 
                    325: - copyToPasteboard:(Pasteboard *)pboard at:(NXSelection *)selection cheapCopyAllowed:(BOOL)cheapCopyAllowed
                    326: {
                    327:     List *list;
                    328:     NXStream *stream;
                    329:     NXTypedStream *ts;
                    330:     id retval = self;
                    331:     const char *types[3];
                    332: 
                    333:     types[1] = NXPostScriptPboardType;
                    334:     types[2] = NXTIFFPboardType;
                    335: 
                    336:     if (cheapCopyAllowed) {
                    337:        if (list = [self findGraphicsInSelection:selection]) {
                    338:            types[0] = NXSelectionPboardType;
                    339:            [pboard declareTypes:types num:3 owner:self];
                    340:            [selection writeToPasteboard:pboard];
                    341:        } else {
                    342:            retval = nil;
                    343:        }
                    344:        [list free];
                    345:     } else {
                    346:        types[0] = DrawPboardType;
                    347:        [pboard declareTypes:types num:3 owner:[self class]];
                    348:        list = [self findGraphicsInSelection:selection];
                    349:        if (list && (stream = NXOpenMemory(NULL, 0, NX_WRITEONLY))) {
                    350:            if (ts = NXOpenTypedStream(stream, NX_WRITEONLY)) {
                    351:                NXWriteRootObject(ts, list);
                    352:                NXCloseTypedStream(ts);
                    353:            }
                    354:            [pboard writeType:DrawPboardType fromStream:stream];
                    355:            NXCloseMemory(stream, NX_FREEBUFFER);
                    356:        } else {
                    357:            retval = nil;
                    358:        }
                    359:        [list free];
                    360:     }
                    361: 
                    362:     return retval;
                    363: }
                    364: 
                    365: 
                    366: /*
                    367:  * Supports linking to an entire file (not just a selection therein).
                    368:  * This occurs when you drag a file into Draw and link (see gvDrag).
                    369:  * This is very analogous to the pasteFromPasteboard:at: above.
                    370:  */
                    371: 
                    372: - importFile:(const char *)filename at:(NXSelection *)selection
                    373: {
                    374:     id graphic;
                    375:     NXRect gBounds;
                    376: 
                    377:     if (graphic = [self findGraphicInSelection:selection]) {
                    378:        gBounds = [graphic reinitFromFile:filename];
                    379:        [self cache:&gBounds];  // updating a link to an imported file
                    380:        [window flushWindow];
                    381:        [self dirty];
                    382:        return self;
                    383:     }
                    384: 
                    385:     return nil;
                    386: }
                    387: 
                    388: /* Other Links methods */
                    389: 
                    390: /*
                    391:  * Just makes the Link Inspector panel reflect whether any of the
                    392:  * Graphic's currently selected are linked to some other document.
                    393:  */
                    394: 
                    395: - updateLinksPanel
                    396: {
                    397:     int i, linkCount = 0;
                    398:     Graphic *foundGraphic = nil, *graphic = nil;
                    399: 
                    400:     if (linkManager) {
                    401:        for (i = [slist count]-1; i >= 0; i--) {
                    402:            if (graphic = [[slist objectAt:i] graphicLinkedBy:NULL]) {
                    403:                if ([graphic isKindOf:[Group class]]) {
                    404:                    linkCount += 2;
                    405:                    break;
                    406:                } else {
                    407:                    linkCount += 1;
                    408:                    foundGraphic = graphic;
                    409:                }
                    410:            }
                    411:        }
                    412:        if (linkCount == 1) {
                    413:            [NXDataLinkPanel setLink:[foundGraphic link] andManager:linkManager isMultiple:NO];
                    414:        } else if (linkCount) {
                    415:            [NXDataLinkPanel setLink:[foundGraphic link] andManager:linkManager isMultiple:YES];
                    416:        } else {
                    417:            [NXDataLinkPanel setLink:nil andManager:linkManager isMultiple:NO];
                    418:        }
                    419:     }
                    420: 
                    421:     return self;
                    422: }
                    423: 
                    424: - (NXDataLinkManager *)linkManager
                    425: {
                    426:     return linkManager;
                    427: }
                    428: 
                    429: /*
                    430:  * When we get a linkManager via this method, we must go and revive all the links.
                    431:  * This is due to the fact that we don't archive ANY link information when we
                    432:  * save a Draw document.  However, the unique identifiers ARE archived, and thus,
                    433:  * when we unarchive, we can recreate NXSelections with those unique identifiers
                    434:  * and then ask the NXDataLinkManager for the link objects associated with those
                    435:  * NXSelections.
                    436:  *
                    437:  * After we have revived all the links, we call breakLinkAndRedrawOutlines:
                    438:  * with nil (meaning redraw the link outlines for all links).
                    439:  */
                    440: 
                    441: - setLinkManager:(NXDataLinkManager *)aLinkManager
                    442: {
                    443:     if (!linkManager) {
                    444:        linkManager = aLinkManager;
                    445:        [glist makeObjectsPerform:@selector(reviveLink:) with:linkManager];
                    446:        [self breakLinkAndRedrawOutlines:nil];
                    447:     }
                    448:     return self;
                    449: }
                    450: 
                    451: /*
                    452:  * This is called when the user chooses Open Source.
                    453:  * It uses the trick of drawing directly into the GraphicView
                    454:  * which, of course, is only ephemeral since the REAL contents
                    455:  * of the GraphicView are stored in the backing store.
                    456:  * This is convenient because Open Source is only a temporary
                    457:  * the the user calls to see where the data for his link is
                    458:  * coming from.
                    459:  */
                    460:  
                    461: - showSelection:(NXSelection *)selection
                    462: {
                    463:     id retval = self;
                    464:     List *graphics = nil;
                    465:     NXRect *newInvalidRect;
                    466:     NXRect sBounds, linkBounds;
                    467:     
                    468:     [self lockFocus];
                    469:     if (invalidRect) {
                    470:        [self drawSelf:invalidRect :1];
                    471:        newInvalidRect = invalidRect;
                    472:        invalidRect = NULL;
                    473:     } else{
                    474:        NX_MALLOC(newInvalidRect, NXRect, 1);
                    475:     }
                    476:     if ([self getRect:&linkBounds forSelection:selection]) {
                    477:        PSsetgray(NX_LTGRAY);
                    478:        NXFrameRectWithWidth(&linkBounds, 2.0);
                    479:        *newInvalidRect = linkBounds;
                    480:        graphics = [self findGraphicsInSelection:selection];
                    481:        if (graphics) {
                    482:            [self getBBox:&sBounds of:graphics];
                    483:            NXUnionRect(&sBounds, newInvalidRect);
                    484:        } else {
                    485:            invalidRect = newInvalidRect;
                    486:            [self scrollRectToVisible:invalidRect];
                    487:            [window flushWindow];
                    488:            retval = nil;
                    489:        }
                    490:     } else {
                    491:        graphics = [self findGraphicsInSelection:selection];
                    492:        if (graphics) {
                    493:            [self getBBox:&sBounds of:graphics];
                    494:            *newInvalidRect = sBounds;
                    495:        } else {
                    496:            retval = nil;
                    497:        }
                    498:     }
                    499: 
                    500:     if (retval) {
                    501:        NXFrameLinkRect(&sBounds, NO);
                    502:        invalidRect = newInvalidRect;
                    503:        NXInsetRect(invalidRect, -NXLinkFrameThickness(), -NXLinkFrameThickness());
                    504:        [self scrollRectToVisible:invalidRect];
                    505:        [window flushWindow];
                    506:     }
                    507: 
                    508:     [self unlockFocus];
                    509:     [graphics free];
                    510: 
                    511:     return retval;
                    512: }
                    513: 
                    514: /*
                    515:  * Called when the Show Links button in the Link Inspector panel is clicked
                    516:  * (the link argument will be nil in this case), or when a link is broken
                    517:  * (the link argument will be the link that was broken).
                    518:  */
                    519: 
                    520: - breakLinkAndRedrawOutlines:(NXDataLink *)link
                    521: {
                    522:     int i;
                    523:     Graphic *graphic;
                    524:     BOOL gotOne = NO;
                    525:     NXRect eBounds, recacheBounds;
                    526: 
                    527:     for (i = [glist count]-1; i >= 0; i--) {
                    528:        graphic = [glist objectAt:i];
                    529:        if (graphic = [graphic graphicLinkedBy:link]) {
                    530:            if (link && ([graphic link] == link) &&
                    531:                ([link updateMode] == NX_UpdateNever)) {
                    532:                    [self removeGraphic:graphic];
                    533:            }
                    534:            if (!link || [linkManager areLinkOutlinesVisible]) {
                    535:                [graphic getExtendedBounds:&eBounds];
                    536:                if (gotOne) {
                    537:                    NXUnionRect(&eBounds, &recacheBounds);
                    538:                } else {
                    539:                    recacheBounds = eBounds;
                    540:                    gotOne = YES;
                    541:                }
                    542:            }
                    543:        }
                    544:     }
                    545:     if (gotOne) {
                    546:        [self cache:&recacheBounds andUpdateLinks:NO];
                    547:        [window flushWindow];
                    548:     }
                    549: 
                    550:     return self;
                    551: }
                    552: 
                    553: /*
                    554:  * Tracking Link Changes.
                    555:  *
                    556:  * This is how we get "Continuous" updating links.
                    557:  *
                    558:  * We simply assume that a thing someone is linked to in our document
                    559:  * changes whenever we have to redraw any rectangle in the GraphicView
                    560:  * which intersects the linked-to rectangle.  See cache:andUpdateLinks:
                    561:  * in GraphicView.m.
                    562:  */
                    563: 
                    564: typedef struct {
                    565:     NXRect linkRect;
                    566:     NXDataLink *link;
                    567:     BOOL dragged, all;
                    568: } LinkRect;
                    569: 
                    570: - updateTrackedLinks:(const NXRect *)sRect
                    571: {
                    572:     int i;
                    573:     LinkRect *lr;
                    574:     List *graphics;
                    575:     NXSelection *selection;
                    576:     NXRect *lRect, newRect;
                    577: 
                    578:     for (i = [linkTrackingRects count]-1; i >= 0; i--) {
                    579:        if (NXIntersectsRect(sRect, (NXRect *)[linkTrackingRects elementAt:i])) {
                    580:            lr = ((LinkRect *)[linkTrackingRects elementAt:i]);
                    581:            [lr->link sourceEdited];
                    582:            lRect = (NXRect *)[linkTrackingRects elementAt:i];
                    583:            if (!lr->dragged && !lr->all && !NXContainsRect(lRect, sRect)) {
                    584:                selection = [lr->link sourceSelection];
                    585:                if (graphics = [self findGraphicsInSelection:selection]) {
                    586:                    [self getBBox:&newRect of:graphics];
                    587:                    *lRect = newRect;
                    588:                    [graphics free];
                    589:                }
                    590:            }
                    591:        }
                    592:     }
                    593: 
                    594:     return self;
                    595: }
                    596: 
                    597: /* Add to linkTrackingRects. */
                    598: 
                    599: - startTrackingLink:(NXDataLink *)link
                    600: {
                    601:     LinkRect trackRect;
                    602:     List *graphics = nil;
                    603:     NXSelection *selection;
                    604:     BOOL all = NO, dragged = NO, piecemeal = NO;
                    605: 
                    606:     selection = [link sourceSelection];
                    607:     if ([selection isEqual:[NXSelection allSelection]]) {
                    608:        all = YES;
                    609:        trackRect.linkRect = bounds;
                    610:     } else if ([self getRect:&trackRect.linkRect forSelection:selection]) {
                    611:        dragged = YES;
                    612:     } else if (graphics = [self findGraphicsInSelection:selection]) {
                    613:        [self getBBox:&trackRect.linkRect of:graphics];
                    614:        piecemeal = YES;
                    615:        [graphics free];
                    616:     } else {
                    617:        return nil;
                    618:     }
                    619: 
                    620:     if (all || dragged || piecemeal) {
                    621:        if (!linkTrackingRects) {
                    622:            linkTrackingRects = [[Storage allocFromZone:[self zone]] initCount:1 elementSize:sizeof(LinkRect) description:"{ffff@}"];
                    623:        }
                    624:        [self stopTrackingLink:link];
                    625:        trackRect.link = link;
                    626:        trackRect.dragged = dragged;
                    627:        trackRect.all = all;
                    628:        [linkTrackingRects addElement:&trackRect];
                    629:     }
                    630: 
                    631:     return nil;
                    632: }
                    633: 
                    634: /* Remove from linkTrackingRects. */
                    635: 
                    636: - stopTrackingLink:(NXDataLink *)link
                    637: {
                    638:     int i;
                    639: 
                    640:     for (i = [linkTrackingRects count]-1; i >= 0; i--) {
                    641:        if (((LinkRect *)[linkTrackingRects elementAt:i])->link == link) {
                    642:            [linkTrackingRects removeElementAt:i];
                    643:            return self;
                    644:        }
                    645:     }
                    646: 
                    647:     return nil;
                    648: }
                    649: 
                    650: @end

unix.superglobalmegacorp.com

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