Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 119014

Summary: [DnD] ViewerDropAdapter disallows all drops
Product: [Eclipse Project] Platform Reporter: Paul E. Keyser <rolarenfan>
Component: UIAssignee: Eric Moffatt <emoffatt>
Status: RESOLVED DUPLICATE QA Contact:
Severity: normal    
Priority: P3 CC: clg-business, cps, digga1404, rob
Version: 3.1.1Keywords: helpwanted
Target Milestone: 3.5   
Hardware: PC   
OS: Windows XP   
Whiteboard:

Description Paul E. Keyser CLA 2005-12-02 05:26:39 EST
I have read the article http://www.eclipse.org/articles/Article-Workbench-DND/drag_drop.html 

There are two use cases: 
A) Extend ViewerDropAdapter, and attach to a TreeViewer (i.e., to allow drags among some items in the Tree): See the eclipse.platform newsgroup, thread "ViewerDropAdapter validateDrop()". 

B) Extend ViewerDropAdapter, in two separate classes, and attach to two separate TreeViewers, to allow drags from TreeViewer-1 to TreeViewer-2: this is my use-case, as I describe below. 

I extend ViewerDropAdapter per the article and javadocs; I also have an implementation of DragSourceListener. My implementation of DragSourceListener#dragStart() sets event.doit = true (as per the example in the article). My implementation of DragSourceListener#dragSetData() sets the event.data (per the example in the article). 

When I run the code, no drop is ever allowed! 

Adding much printf-style tracing, and performing static debuggery, shows that in ViewerDropAdapter, the private fields currentOperation and lastValidOperation are initialised to DND.DROP_NONE. Thus, in either use-case, the private method doDropValidation() of ViewerDropAdapter can never set the event.detail to anything other than DND.DROP_NONE. 

The class ViewerDropAdapter provides no apparent way to set event.detail to the intended value, even if the user rolls the mouse over a *valid* drop-target. 
Nor does the JFace example in the article explain how to do this, and none of the classes Gadget*DropAdapter accesses the event.detail or override/extend the method dragEnter(), which as far as I can tell (esp. from the SWT example) is the only chance for client code to set the value of event.detail. 

There is a workaround, which only allows *one* type of operation, by extending dragEnter() as follows: 

	public void dragEnter(DropTargetEvent event) {
		super.dragEnter(event);
		event.detail = DND.DROP_COPY; // before or after call to super 
	}

I'm not sure what to suggest, but something is clearly amiss. Maybe the problem is solely in the docs, which make some unstated assumption that I am somehow violating?
Comment 1 Paul E. Keyser CLA 2005-12-28 15:03:41 EST
(In reply to comment #0)

I discovered that things seem to work if I do all of the following (not sure which part(s) are critical, as I only realised it worked after I had done it all): 

*dragStart()*: set event.doit to true (perhaps under some condition) 

*dragSetData()*: if event.dataType is OK, set event.data to the YourData[] to be dragged 

Then, override the following two methods as indicated: 

	public void dragEnter(final DropTargetEvent event) {
		selectDefault(event);
		super.dragEnter(event);
	}
	public void dragOperationChanged(final DropTargetEvent event) {
		selectDefault(event);
		super.dragOperationChanged(event);
	}

And here's the method selectDefault(): 

	protected void selectDefault(DropTargetEvent event) {
		if (maskEquals(event.detail, DND.DROP_DEFAULT)) {
			event.detail = DEFAULT_OP; 
		}
	}

I have this one in a module of useful utilities: 
	public static boolean maskEquals(int mask, int value) {
		return (mask & value) != 0;
	}

Can others verify that this works, or is a sensible way to proceed? 
Comment 2 Eric Moffatt CLA 2007-06-25 10:09:25 EDT
I'll tag this for a look in 3.4 since there seem to be a fair number of gliches in the ViewDropAdapter...
Comment 3 Paul E. Keyser CLA 2007-06-26 13:49:34 EDT
(In reply to comment #2)
> I'll tag this for a look in 3.4 since there seem to be a fair number of gliches
> in the ViewDropAdapter...
> 
Good to hear -- I am still interested in this bug, as we use DnD often, and for each implementation I must revisit all this. Thanks.
Comment 4 Eric Moffatt CLA 2007-06-27 09:09:05 EDT
Dnd is near and dear to my heart...;-)
Comment 5 C. Lamont Gilbert CLA 2007-07-11 16:25:50 EDT
Eclipse 3.2.2

I have a similar problem so rather than post a new bug, I'll ask here first if it is related.

I want to drop from one tree item onto another.  But the ViewerDropAdapter is configured such that it only recognizes the tree as a whole and not individual items.  So the second you hit a bad drop, the drop will stay bad until you leave and reenter the tree.  I want the drop to be reevaluated for each tree item.  I say this could be related because if you start your DND operation, and the first thing the system sees is you trying to drop an item ontop of itself, and you have disallowed items dropping on top of themselves, then the system will forbid the drop.  And as stated, once a drop is forbidden, it is permanently forbidden until you exit and reenter the tree.

My solution was to make a change which I think is proper.


private void doDropValidation(DropTargetEvent event) {
        //update last valid operation
        if (event.detail != DND.DROP_NONE) {
            lastValidOperation = event.detail;
        }
        //valid drop and set event detail accordingly
        if (validateDrop(currentTarget, event.operations, event.currentDataType)) {
            currentOperation = lastValidOperation;
        } else {
            currentOperation = DND.DROP_NONE;
        }
        event.detail = currentOperation;
    }


In the above method I have changed 

validateDrop(currentTarget, event.detail, event.currentDataType)

to

validateDrop(currentTarget, event.operations, event.currentDataType)

This gives the user an opportunity to indicate the drop is valid again.  If you use event.detail, once event.detail becomes DND.DROP_NONE, then it stays DND.DROP_NONE and the validator will always see DND.DROP_NONE and will never be able to reevaluate based on the actual drop target being over a different tree item.  Since he no longer knows the true requested drop operation.
Comment 6 C. Lamont Gilbert CLA 2007-07-11 16:40:15 EDT
Patch is not so pretty so I just paste it here.  I don't have the project installed to create a proper patch.

--- C:\ViewerDropAdapter.java	2007-07-11 16:33:44.000000000 -0400
+++ C:\ViewerDropAdapter.java	2007-07-11 16:35:52.000000000 -0400
@@ -169,13 +169,13 @@
     private void doDropValidation(DropTargetEvent event) {
         //update last valid operation
         if (event.detail != DND.DROP_NONE) {
             lastValidOperation = event.detail;
         }
         //valid drop and set event detail accordingly
-        if (validateDrop(currentTarget, event.detail, event.currentDataType)) {
+        if (validateDrop(currentTarget, event.operations, event.currentDataType)) 

{
             currentOperation = lastValidOperation;
         } else {
             currentOperation = DND.DROP_NONE;
         }
         event.detail = currentOperation;
     }


Comment 7 Eric Moffatt CLA 2008-06-09 10:52:57 EDT
*** Bug 92802 has been marked as a duplicate of this bug. ***
Comment 8 Chris Simmons CLA 2008-06-10 09:06:51 EDT
Note that the suggested fix in bug 92802 is different.  It suggests to use lastValidOperation in validate drop.  This makes sense since we should be re-evaluating the validation for last (non-DND.DROP_NONE) operation on the current tree node.

I can't see how using event.operations makes any sense, this is isn't even a unique value since its the bitwise or of all supported operations.  It might appear to do the right thing if you have only set one operation but for the wrong reason.

eg in our tree we have all operations supported so

event.operations == DND.DROP_COPY | DND.DROP_MOVE | DND.DROP_DEFAULT | DND.DROP_LINK
Comment 9 Eric Moffatt CLA 2008-06-10 14:55:32 EDT
Chris, for my money I think that 'validateDrop' should -return- the event.detail value rather than a boolean, making 'lastValidOperation'...umm...invalid...;-).

In any case I hope that the some flavor of the work around will help...
Comment 10 Eric Moffatt CLA 2009-03-05 11:40:46 EST
Bug 263845 adds the ability to set the event.detail in 'validateDrop'. Try this out and re-open if there are issues that still cannot be solved.


*** This bug has been marked as a duplicate of bug 263845 ***