home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Examples / AppKit / Draw / gvDrag.m < prev    next >
Text File  |  1996-02-16  |  12KB  |  353 lines

  1. #import "draw.h"
  2.  
  3. /* See the Dragging.rtf for overview of Dragging in Draw. */
  4.  
  5. #define ERROR (-1)
  6.  
  7. @implementation GraphicView(Drag)
  8.  
  9. /*
  10.  * Determines whether there is a Graphic at the specified point that is
  11.  * willing to accept a dragged color.  If color is non-NULL, then the
  12.  * color is actually set in that Graphic (i.e. you can find out if any
  13.  * Graphics is "willing" to accept a color by calling this with
  14.  * color == NULL).
  15.  *
  16.  * We use the mechanism of sending a Graphic the message colorAcceptorAt:
  17.  * and letting it return a Graphic (rather than just asking each Graphic
  18.  * doYouAcceptAColorAt:) so that Group's of Graphics can return one of
  19.  * the Graphic's inside itself as the one to handle a dropped color.
  20.  */
  21.  
  22. - (BOOL)acceptsColor:(NSColor *)color atPoint:(NSPoint)point
  23. {
  24.     id change;
  25.     NSRect gbounds;
  26.     Graphic *graphic;
  27.     int i, count = [glist count];
  28.  
  29.     for (i = 0; i < count; i++) {
  30.     graphic = [glist objectAtIndex:i];
  31.     if ((graphic = [graphic colorAcceptorAt:point])) {
  32.         if (color) {
  33.         gbounds = [graphic extendedBounds];
  34.         change = [[FillGraphicsChange alloc] initGraphicView:self forChangeToGraphic:graphic];
  35.         [change startChange];
  36.             [graphic setFillColor:color];
  37.             [self cache:gbounds];        // acceptsColor:atPoint:
  38.             [[self window] flushWindow];
  39.         [change endChange];
  40.         return YES;
  41.         } else {
  42.         return YES;
  43.         }
  44.     }
  45.     }
  46.  
  47.     return NO;
  48. }
  49.  
  50. /*
  51.  * Registers the view with the Workspace Manager so that when the
  52.  * user picks up an icon in the Workspace and drags it over our view
  53.  * and lets go, dragging messages will be sent to our view.
  54.  * We register for NSFilenamesPboardType because we handle data link
  55.  * files and NSImage and Text files dragged into draw as well as any
  56.  * random file when the Control key is depressed (indicating a link
  57.  * operation) during the drag.  We also accept anything that NSImage
  58.  * is able to handle (even if it's not in a file, i.e., it's directly
  59.  * in the dragged Pasteboard--unusual, but we can handle it, so why
  60.  * not?).
  61.  */
  62.  
  63. - (void)registerForDragging
  64. {
  65.     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSFilenamesPboardType, nil]];
  66.     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSColorPboardType, nil]];
  67.     [self registerForDraggedTypes:[NSImage imagePasteboardTypes]]; 
  68. }
  69.  
  70. /*
  71.  * This is where we determine whether the contents of the dragging Pasteboard
  72.  * is acceptable to Draw.  The gvFlags.drag*Ok flags say whether we can accept
  73.  * the dragged information as a result of a copy or link (or both) operation.
  74.  * If NSImage can handle the Pasteboard, then we know we can do copy.  We
  75.  * always know we can do link as long as we have a linkManager.  We cache as
  76.  * much of the answer around as we can so that draggingUpdated: will be fast.
  77.  * Of course, we can't cache the part of the answer which is dependent upon
  78.  * the position inside our view (important for colors).
  79.  */
  80.  
  81. - (unsigned int)draggingEntered:(id <NSDraggingInfo>)sender
  82. {
  83.     NSPasteboard *pboard;
  84.     unsigned int sourceMask;
  85.  
  86.     gvFlags.dragCopyOk = NO;
  87.     gvFlags.dragLinkOk = NO;
  88.  
  89.     sourceMask = [sender draggingSourceOperationMask];
  90.     pboard = [sender draggingPasteboard];
  91.  
  92.     if (IncludesType([pboard types], NSColorPboardType)) {
  93.     NSPoint p = [sender draggingLocation];
  94.     p = [self convertPoint:p fromView:nil];
  95.     if ([self acceptsColor:nil atPoint:p]) return NSDragOperationGeneric;
  96.     } else if (sourceMask & NSDragOperationCopy) {
  97. //    if ([NSImage canInitWithPasteboard:pboard]) {
  98. //        gvFlags.dragCopyOk = YES;
  99. //    } else
  100. // should also make sure its either EPS or TIFF until ObjectLinks is working again
  101.     if (IncludesType([pboard types], NSFilenamesPboardType)) {
  102.         gvFlags.dragCopyOk = YES;
  103.     }
  104.     }
  105.  
  106.     if (linkManager) gvFlags.dragLinkOk = YES;
  107.  
  108.     if (sourceMask & NSDragOperationCopy) {
  109.     if (gvFlags.dragCopyOk) return NSDragOperationCopy;
  110.     } else if (sourceMask & NSDragOperationLink) {
  111.     if (gvFlags.dragLinkOk) return NSDragOperationLink;
  112.     }
  113.  
  114.     return NSDragOperationNone;
  115. }
  116.  
  117. /*
  118.  * This is basically the same as draggingEntered: but, instead of being
  119.  * called when the dragging enters our view, it is called every time the
  120.  * mouse moves while dragging inside our view.
  121.  */
  122.  
  123. - (unsigned int)draggingUpdated:(id <NSDraggingInfo>)sender
  124. {
  125.     unsigned int sourceMask = [sender draggingSourceOperationMask];
  126.     if (IncludesType([[sender draggingPasteboard] types], NSColorPboardType)) {
  127.     NSPoint p = [sender draggingLocation];
  128.     p = [self convertPoint:p fromView:nil];
  129.     if ([self acceptsColor:nil atPoint:p]) return NSDragOperationGeneric;
  130.     } else if (sourceMask & NSDragOperationCopy) {
  131.     if (gvFlags.dragCopyOk) return NSDragOperationCopy;
  132.     } else if (sourceMask & NSDragOperationLink) {
  133.     if (gvFlags.dragLinkOk) return NSDragOperationLink;
  134.     }
  135.     return NSDragOperationNone;
  136. }
  137.  
  138. /*
  139.  * Takes the name of a saved link (.objlink) file and incorporates
  140.  * the "linked thing" into the view.  This is really just some glue between
  141.  * the dragging mechanism and the addLink:toGraphic:at:update: method
  142.  * which does all the work of actually incorporating the linked stuff
  143.  * into the view.
  144.  */
  145.  
  146. - (int)createGraphicForDraggedLink:(NSString *)file at:(NSPoint)p
  147. {
  148.     NSDataLink *link;
  149.     Graphic *graphic = nil;
  150.  
  151.     if (linkManager) {
  152.     link = [[[NSDataLink alloc] initWithContentsOfFile:file] autorelease];
  153.     if ([self addLink:link toGraphic:graphic at:p update:UPDATE_IMMEDIATELY]) {
  154.         return YES;
  155.     } else {
  156.         NSRunAlertPanel(nil, BAD_IMAGE, nil, nil, nil);
  157.         return ERROR;
  158.     }
  159.     }
  160.  
  161.     return NO;
  162. }
  163.  
  164. /* A couple of convenience methods to determine what kind of file we have. */
  165.  
  166. static BOOL isNSImageFile(NSString * file)
  167. {
  168.     NSString * extension = [file pathExtension];
  169.     
  170.     return ([NSImageRep imageRepClassForFileType:extension]) ? YES : NO;
  171. }
  172.  
  173. static BOOL isRTFFile(NSString * file)
  174. {
  175.     NSString * extension = [file pathExtension];
  176.     
  177.     return ([extension isEqual:@"rtf"]) ? YES : NO;
  178. }
  179.  
  180. /*
  181.  * Creates a Graphic from a file NSImage or the Text object can handle
  182.  * (or just allows linking it if NSImage nor Text can handle the file).
  183.  * It links to it if the doLink is YES.
  184.  *
  185.  * If we are linking, then we ask the user if she wants the file's icon,
  186.  * a link button, or (if we can do so) the actually contents of the file
  187.  * to appear in the view.
  188.  *
  189.  * Note the use of the workspace protocol object to get information about
  190.  * the file.  We know that we cannot import the contents of a WriteNow or
  191.  * other known document format into Draw, so we don't even give the user
  192.  * the option of trying to do so.
  193.  *
  194.  * Again, if it ends up that we are linking, we just call the all-powerful
  195.  * addLink:toGraphic:at:update: method in gvLinks.m, otherwise, we just
  196.  * call placeGraphic:at:.
  197.  */
  198.  
  199. - (int)createGraphicForDraggedFile:(NSString *)file withIcon:(NSImage *)icon at:(NSPoint)p andLink:(BOOL)doLink
  200. {
  201.     NSString *fileType;
  202.     Graphic *graphic;
  203.     NSDataLink *link;
  204.     int choice, updateMode = UPDATE_NORMALLY;
  205.     BOOL isImportable;
  206.  
  207.     isImportable = isNSImageFile(file) || isRTFFile(file);
  208.     if (!isImportable && [[NSWorkspace sharedWorkspace] getInfoForFile:file application:NULL type:&fileType]) {
  209.     isImportable = ([fileType isEqual:NSPlainFileType]);
  210.     }
  211.  
  212.     if (!linkManager) doLink = NO;
  213.  
  214.     if (doLink) {
  215.     if (isImportable) {
  216.         choice = NSRunAlertPanel(nil, FILE_CONTENTS_OR_ICON_OR_LINK_BUTTON, FILE_CONTENTS, FILE_ICON, LINK_BUTTON);
  217.     } else {
  218.         choice = NSRunAlertPanel(nil, FILE_ICON_OR_LINK_BUTTON, FILE_ICON, LINK_BUTTON, nil);
  219.         if (choice == NSAlertDefaultReturn) {
  220.         choice = NSAlertAlternateReturn;
  221.         } else if (choice == NSAlertAlternateReturn) {
  222.         choice = NSAlertOtherReturn;
  223.         }
  224.     }
  225.     } else if (isImportable) {
  226.     choice = NSAlertDefaultReturn;
  227.     } else {
  228.     return NO;
  229.     }
  230.  
  231.     if (choice == NSAlertDefaultReturn) {        // import the contents of the file
  232.     if (isNSImageFile(file)) {
  233.         graphic = [[Image allocWithZone:(NSZone *)[self zone]] initWithFile:file];
  234.     } else {
  235.         graphic = [[TextGraphic allocWithZone:(NSZone *)[self zone]] initWithFile:file];
  236.     }
  237.     updateMode = UPDATE_NORMALLY;
  238.     } else if (choice == NSAlertAlternateReturn) {    // show the file's icon
  239.     graphic = [[Image allocWithZone:(NSZone *)[self zone]] initFromIcon:icon];
  240.     updateMode = UPDATE_NEVER;
  241.     } else {                            // show a link button
  242.     graphic = [[Image allocWithZone:(NSZone *)[self zone]] initWithLinkButton];
  243.     updateMode = UPDATE_NEVER;
  244.     }
  245.  
  246.     if (graphic) {
  247.     if (doLink) {
  248.         link = [[[NSDataLink alloc] initLinkedToFile:file] autorelease];
  249.         if ([self addLink:link toGraphic:graphic at:p update:UPDATE_NORMALLY]) return YES;
  250.     } else {
  251.         if ([self placeGraphic:graphic at:&p]) return YES;
  252.     }
  253.     }
  254.  
  255.     NSRunAlertPanel(nil, nil, BAD_IMAGE, nil, nil, nil);
  256.  
  257.     return ERROR;
  258. }
  259.  
  260. /*
  261.  * If we get this far, we are pretty sure we can succeed (though we're
  262.  * not 100% sure because it might be, for example, a WriteNow file
  263.  * without the link button down).
  264.  *
  265.  * We return YES here and do the work in conclude so that we don't
  266.  * timeout if we are dragging in a big image or something that will
  267.  * take a long time to import (or if we have to ask the user a question
  268.  * to figure out how to import the dragged thing).  The bummer here
  269.  * is that if creating the image should fail for some reason, we can't
  270.  * give the slide-back feedback because it's too late to do so in
  271.  * concludeDragOperation:.
  272.  */
  273.  
  274. - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
  275. {
  276.     NSPasteboard *pboard = [sender draggingPasteboard];
  277.  
  278.     if (IncludesType([pboard types], NSColorPboardType)) {
  279.     BOOL retval = NO;
  280.     NSColor *color = [NSColor colorFromPasteboard:pboard] /* ??? CHECK THIS: retain? */;
  281.     NSPoint p = [sender draggingLocation];
  282.     p = [self convertPoint:p fromView:nil];
  283.     retval = [self acceptsColor:color atPoint:p];
  284.     [NSApp updateWindows];    // reflect color change in Inspector, et. al.
  285.     return retval;
  286.     }
  287.  
  288.     return YES;
  289. }
  290.  
  291. /* Another convenience method for identifying .objlink files. */
  292.  
  293. static BOOL isLinkFile(NSString * file)
  294. {
  295.     NSString * extension = [file pathExtension];
  296.     return ([extension isEqual:NSDataLinkFilenameExtension]) ? YES : NO;
  297. }
  298.  
  299. /*
  300.  * Actually do the "drop" of the drag here.
  301.  *
  302.  * Note that if we successfully dropped, we bring the window
  303.  * we dropped into to the front and activate ourselves.  We also
  304.  * update our inspectors, etc. (this is especially important for
  305.  * the LinkInspector window!) by calling updateWindows.
  306.  */
  307.  
  308. - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
  309. {
  310.     NSPoint p;
  311.     NSPasteboard *pboard;
  312.     NSArray * filenameArray;
  313.     int foundOne = NO;
  314.     BOOL doLink;
  315.  
  316.     p = [sender draggingLocation];
  317.     p = [self convertPoint:p fromView:nil];
  318.  
  319.     doLink = ([self draggingUpdated:sender] == NSDragOperationLink);
  320.     pboard = [sender draggingPasteboard];
  321.  
  322.     if (IncludesType([pboard types], NSColorPboardType)) foundOne = YES;
  323.  
  324.     if (!foundOne && IncludesType([pboard types], NSFilenamesPboardType)) {
  325.         int nameCount;
  326.     int index = 0;
  327.     
  328.     filenameArray = [pboard propertyListForType:NSFilenamesPboardType];
  329.     nameCount = [filenameArray count];
  330.     
  331.     while (index < nameCount) {
  332.         NSString * currFile = [filenameArray objectAtIndex:index];
  333.         
  334.         if (isLinkFile(currFile)) {
  335.         foundOne = [self createGraphicForDraggedLink:currFile at:p] || foundOne;
  336.         } else {
  337.         foundOne = [self createGraphicForDraggedFile:currFile withIcon:[sender draggedImage] at:p andLink:doLink] || foundOne;
  338.         }
  339.         ++index;
  340.     }
  341.     }
  342.  
  343.     if (!foundOne) foundOne = [self pasteForeignDataFromPasteboard:pboard andLink:doLink at:p];
  344.     
  345.     if (foundOne > 0) {
  346.     [NSApp activateIgnoringOtherApps:YES];
  347.     [[self window] makeKeyAndOrderFront:self];
  348.     [NSApp updateWindows];
  349.     }
  350. }
  351.  
  352. @end
  353.