Re: drag & drop objects
Re: drag & drop objects
- Subject: Re: drag & drop objects
- From: Jerry Krinock <email@hidden>
- Date: Tue, 3 Jul 2007 14:35:31 -0700
On 2007 Jul, 03, at 7:16, Ken Tozier wrote:
On Jul 3, 2007, at 10:06 AM, Joe Wildish wrote:
Hi Ken,
If I'm doing drag-and-drop within the same application, I often
have some kind of instance variable somewhere that stores
reference to the item being dragged. Once the drag is complete, I
have the method query the instance variable, rather than the
pasteboard. That way I can avoid the pasteboard all together.
How do you avoid the pasteboard?
See code below
The "dragImage:at:offset:event:pasteboard:source:slideBack:" method
requires a pasteboard. Do you just create a dummy one and ignore it?
My implementation does not use a custom icon, so I didn't run into
this issue, but yes that's what I would do.
I would think that, at the very least, the drag target would need
to know what type of data is being dropped so it highlights
correctly and can decide to handle the drop or not...
Yes, it knows what's being dragged because it's your got your "behind
the scenes pasteboard".
Here is the drag-and-drop code from my NSOutlineView's data source,
written for Jaguar/Panther.  My "behind the scenes pasteboard" is
[[NSApp delegate] intraAppDragArray].  You should be able to see it
works.  Note in particular the comment at line 17...some types of
data are not serializable, and so the "behind the scenes pasteboard"
may be your only choice.
// ***** Dragging and Dropping (These must be here, in a NSTable/
OutlineView's dataSource!!) ***** //
// Dragging Source: Writing TO the System Dragging Pasteboard
- (BOOL)outlineView:(NSOutlineView*)olv
         writeItems:(NSArray*)items
       toPasteboard:(NSPasteboard*)pasteboard
{
    NSArray* acceptableDragTypes
    = [NSArray arrayWithObjects:
        SSBookmarkPboardType,
        NSStringPboardType,
        //@"NeXT plain ascii pasteboard type",
        //NSFilenamesPboardType,
        //NSURLPboardType,
        nil];
    [pasteboard declareTypes:acceptableDragTypes owner:self];
    // The following does not work because of the @"Parent" key in
each item, which is an NSValue.
    // success1 = [pboard setPropertyList:writeItems
forType:SSBookmarkPboardType] ;
    // NSValues are not supported for serialization.  Therefore,
even though setPropertyLost:forType will return YES,
    // it is in fact not successful.  The pasteboard will contain
NULL for type SSBookmarkPboardType
    // So, we do this instead
    [[NSApp delegate] setIntraAppDragArray:items] ;
    // Now, we set the urls onto the pasteboard for other apps
    // Set NSStringPBoardType data onto pasteboard
    NSString* urls = [items urlsFormattedAsList] ;
    if (urls) {
        [pasteboard setString:urls forType:NSStringPboardType];
    }
    return YES ;
}
/* // Here is an implementation (from Hilleglass) for doing the same
thing/
   // if this were a table view instead of an outline view.
- (BOOL)tableView:(NSTableView *)tv writeRows:(NSArray*)rows
     toPasteboard:(NSPasteboard*)pb
{
    NSMutableArray *rowArray = [[NSMutableArray alloc] init];
    NSEnumerator *enumerator = [rows objectEnumerator];
    id object;
    NSData *rowData;
    while (object = [enumerator nextObject]) {
        int theRow = [object intValue];
        NSMutableDictionary *rowRecord = [[self model]
recordForRow:theRow];
        [rowArray addObject:rowRecord];
    }
    rowData = [self encodeDataRepresentationForObjects:rowArray];
    [pb declareTypes:[NSArray arrayWithObjects:MY_DRAG_TYPE, nil]
owner:self];
    return [pb setData:rowData forType:MY_DRAG_TYPE];
}
*/
// This is to OK the proposed drop before it happens
- (NSDragOperation)outlineView:(NSOutlineView*)outlineView
                  validateDrop:(id <NSDraggingInfo>)info  //
contains payload item(s)
                  proposedItem:(id)proposedTarget
            proposedChildIndex:(int)proposedIndex         //
location within target item
{
    NSPasteboard* pboard = [info draggingPasteboard];
    NSDragOperation output = NSDragOperationMove |
NSDragOperationCopy ; // Start by assuming it will work
    BmLocation* target = [[BmLocation alloc]
initWithParent:proposedTarget index:proposedIndex] ;
    // NSLog(@"************ VALIDATE *******************") ;
    //  1. Disallow drops onto empty lines at end of table
    {
        if(!proposedTarget)
            output = NSDragOperationNone;
    }
    //  2. Disallow drops which depend on the Pboard type
    if (output != NSDragOperationNone) {
        if([pboard availableTypeFromArray:[NSArray
arrayWithObjects:SSBookmarkPboardType, NSFilenamesPboardType, nil]]) {
            //            //  a.  Disallow drops of bookmarks,
containers or files onto bookmarks
            //            SSLog(5, "considering validating of drop
of SSBookmarkPboardType or NSFilenames PboardType") ;
            //            if ([proposedTarget nodeType] ==
SSBookmark) {
            //                output = NSDragOperationNone ;
            //            }
        }
        else if([pboard availableTypeFromArray:[NSArray
arrayWithObject:NSStringPboardType]]) {
            //  b.  Disallow drops of text strings onto folders or
separators; drops onto bookmarks are OK
            SSLog(5, "considering validating drop of NS plain ascii
pasteboard type") ;
            if (![proposedTarget nodeType] == SSBookmark)  {
                output =  NSDragOperationNone ;
            }
        }
        else
        {
            //  c.  Disallow drops of unknown types!
            SSLog(4, "This app does not take drops of these types: %
@", [pboard types]) ;
            output = NSDragOperationNone ;
        }
    }
    //  3. Check if OK to insert proposed items at proposed location
    if (output != NSDragOperationNone) {
        if (![[NSApp delegate] checkOKToInsertItems:[[NSApp
delegate] intraAppDragArray] atBmLocation:target]) {
            output = NSDragOperationNone ;
        }
    }
    //  4. Now see if we want to retarget it
    //     Here, we only do retargetting which does not depend on
the payloadItem.
    //     In outlineView:acceptDrop:item:childIndex, we may do
additional retargetting per payload item.
    if (output != NSDragOperationNone) {
        [target retargetIfNeededCheckRange:YES] ;
        // We send a message to the outline view to do the
retargetting (this seems strange, but it works).
        [[[[self doc] mainWindowController] bookmarksOutlineView]
setDropItem:[target parent] dropChildIndex:[target index]] ;
        // Note: -retargetIfNeededCheckRange: will be invoked again
later, when outlineView:acceptDrop:item:childIndex sends
        // -[ApplicationController
parentingAction:items:toParents:targetItem:atIndexes:] because this
method
        // does it for clipboard copies and contextual menu Copy To
and Move To items.  But we also "pre-do" it
        // in this case of drag/dropping, to give visual feedback to
the user.  Also, in the later case we do
        // not CheckRange
    }
    [target release] ;
    return output ;
}
// This is to actually accept the drop
- (BOOL)outlineView:(NSOutlineView *)outlineView
         acceptDrop:(id <NSDraggingInfo>)info
                 item:(id)targetItem
         childIndex:(int)proposedIndex
{
    SSLog(5, "outlineView:acceptDrop") ;
    NSPasteboard *pboard = [info draggingPasteboard];
    NSDragOperation dragOperation = [info
draggingSourceOperationMask] ;
    BOOL result ;
    enum SSParentingAction action ;
    if ((dragOperation & NSDragOperationMove) > 0)
    {
        action = SSParentingMove ;
    }
    else
    {
        action = SSParentingCopy ;
    }
    if([pboard availableTypeFromArray:[NSArray
arrayWithObject:SSBookmarkPboardType]])
    {
        SSLog(5, "Got a drop of type SSBookmarkPboardType") ;
        NSArray *payloadItems = [[NSApp delegate] intraAppDragArray] ;
        [[NSApp delegate] parentingAction:action
                                    items:payloadItems
                                toParents:targetItem
                                atIndexes:[NSNumber
numberWithInt:proposedIndex]] ;
        result = YES ;
    }
    else if([pboard availableTypeFromArray:[NSArray
arrayWithObjects:NSFilenamesPboardType, nil]])
        // Important: We have to test for this before
NSStringPboardType because a .webloc file
        // generated by Safari in Jaguar seems to have the
NSStringPboardType also.
    {
        NSArray *paths = [pboard
propertyListForType:NSFilenamesPboardType];
        if (gLogging >=5)
        {
            SSLog(5, "Got a drop of %i files with paths:", [paths
count]) ;
            NSEnumerator* e1 = [paths objectEnumerator] ;
            NSString* path ;
            while ((path = [e1 nextObject]))
            {
                SSLog(5, "   PATH:\"%@\"", path) ;
            }
            SSLog(5, "\n") ;
        }
        NSArray* filenamesAndURLs ;
        if (( filenamesAndURLs = SSWeblocFilenamesAndURLs(paths) ))
        {
            SSLog(5, "got filenamesAndURLs:\n%@", filenamesAndURLs) ;
            NSEnumerator *e = [filenamesAndURLs objectEnumerator] ;
            NSDictionary* filenameAndURL ;
            BmItem* newBookmark ;
            NSMutableArray* newBookmarks = [[NSMutableArray alloc]
init] ;
            while ((filenameAndURL = [e nextObject]))
            {
                // Low-level methods which create a temporary bookmark:
                newBookmark = [[BmItem alloc]
initWithNodeType:SSBookmark] ;
                [newBookmark setName:[filenameAndURL
objectForKey:@"filename"]] ;
                [newBookmark setUrl:[filenameAndURL
objectForKey:@"url"]] ;
                [newBookmarks addObject:newBookmark] ;
                [newBookmark release] ;
            }
            // High-level method which adds them to the tree.
Undoable, Redoable, Shows, Tells:
            [[NSApp delegate] parentingAction:SSParentingAdd
                                        items:newBookmarks
                                    toParents:targetItem
                                    atIndexes:[NSNumber
numberWithInt:proposedIndex]] ;
            [newBookmarks release] ;
            [NSApp activateIgnoringOtherApps:YES] ;
            result = YES ;
        }
        else {
            result = NO ;
        }
    }
    else if([pboard availableTypeFromArray:[NSArray
arrayWithObject:NSStringPboardType]])
    {
        SSLog(5, "Got a drop of type NeXT plain ascii pasteboard
type") ;
        NSString* newURL = [pboard stringForType:NSStringPboardType] ;
        if (newURL) {
            // High-level method which provides Undoable, Redo, Show
and Tell:
            [[NSApp delegate] changeObjectProperty:KEY_URL
                                            ofItem:targetItem
                                          toObject:newURL] ;
        }
        [NSApp activateIgnoringOtherApps:YES] ;
        result = YES ;
    }
    else {
        SSLog(3, "Sorry, got a drop of a type we cannot handle.") ;
        result = NO ;
    }
    return result;
}
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden