This Bugzilla instance is deprecated, and most Eclipse projects now use GitHub or Eclipse GitLab. Please see the deprecation plan for details.
Bug 408523 - [dnd] Drag and Drop of Project deletes files
Summary: [dnd] Drag and Drop of Project deletes files
Status: VERIFIED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.5   Edit
Hardware: All All
: P3 critical (vote)
Target Milestone: 4.4 M1   Edit
Assignee: Markus Keller CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on: 358407
Blocks: 413644
  Show dependency tree
 
Reported: 2013-05-20 17:59 EDT by Patrick Costello CLA
Modified: 2014-05-30 08:30 EDT (History)
5 users (show)

See Also:


Attachments
Fix (1.75 KB, patch)
2013-05-28 13:49 EDT, Markus Keller CLA
no flags Details | Diff
Fix for 4.3.1 (or 4.3) (743 bytes, patch)
2013-05-28 14:00 EDT, Markus Keller CLA
daniel_megert: review+
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Patrick Costello CLA 2013-05-20 17:59:44 EDT
Perhaps similar to bug 34658, but on a different platform / later Eclipse version. 
Dragging the project folder from Package Explorer to a Drag and Drop location (tested in Safari), results in the entire folder being deleted from the Hard Disk.

This can be recreated by creating a new project, then going to http://yuilibrary.com/yui/docs/uploader/uploader-dd.html (just a random uploader I found online) in Safari, and try to drag the project into it. Dragging individual files results in them properly uploading, but dragging the project causes it to disappear from the Package Explorer and to be deleted from the hard drive. 

This has been reproduced on multiple machines running OS X 10.8 and 10.7. It doesn't seem to have the problem with other browsers (Chrome or Firefox), but does have the problem with Safari. 

While the likelihood of users running into this problem is low, I marked it at a major error as it does permanently delete the users work.

Thanks!
Comment 1 Francis Upton IV CLA 2013-05-22 13:52:12 EDT
This is the Package Explorer (not the Project Explorer, right)? If so, then shouldn't it go to JDT UI?
Comment 2 Patrick Costello CLA 2013-05-22 15:53:01 EDT
Ah yes, that makes sense. I will change it. Thanks!
Comment 3 Dani Megert CLA 2013-05-23 11:46:44 EDT
Broken since 3.5. Before 3.5 it did also not copy the project into the drop location, but at least it did not delete the stuff.

This works in the Project Explorer.

It also deletes the project when attaching it to a Thunderbird e-mail.
Comment 4 Markus Keller CLA 2013-05-23 15:00:46 EDT
The problem is the handling of DND.DROP_MOVE in 
org.eclipse.jdt.internal.ui.dnd.ResourceTransferDragAdapter#dragFinished(DragSourceEvent).

In org.eclipse.jdt.internal.ui.packageview.FileTransferDragAdapter#dragFinished(DragSourceEvent), we've commented this out due to bug 30543. See also bug 358407 and the discussions in bug 277454.


But why is the ResourceTransferDragAdapter informed about dragFinished in this case? If I drag a folder from the Package Explorer, then nothing bad happens.

The difference is that FileTransferDragAdapter#isDragable(..) says it doesn't support projects, but it supports folders.

In the folder case, the DelegatingDragAdapter#updateCurrentListener(..) method sets the currentListener to the FileTransferDragAdapter, and eventually, on DelegatingDragAdapter#dragFinished(..), calls only FileTransferDragAdapter#dragFinished(..).

In the project case, updateCurrentListener(..) doesn't find any listener that is capable of dragging a project, so currentListener stays null. In the end, DelegatingDragAdapter#dragFinished(..) calls dragFinished(..) on *all* activeListeners, and ResourceTransferDragAdapter#dragFinished erroneously deletes the whole projects.


The bug is in the implementation of DelegatingDragAdapter#dragFinished(..). The protocol in DragSourceListener specifies that dragFinished(..) is sent no matter whether the DND operation was successful or not. But sending it to all activeListeners iff currentListener == null is definitely wrong. We either have to remove that, or always send it to all activeListeners, but only have event.doit set to true for the currentListener.
Comment 5 Martin Mathew CLA 2013-05-28 06:13:28 EDT
Thanks Markus for the detailed investigation of the bug.
I tested using Chrome Version 27.0.1453.94 m, Firefox Version 27.0.1453.94 m, Internet Explorer Version 8.0.7601.17514 and Opera Version: 12.14. Out of the above browsers, the issue was reproducible only in Firefox. When a package or project is DnD out of Eclipse, then the corresponding resource is deleted from the hard disk. It works fine when a file or folder is DnD outside Eclipse. I could not test this bug in Safari, Thunderbird and Netscape. 

Firefox reports the package and project DnD event as a 'DND.DROP_MOVE' where as Chrome reports the same event as 'DND.DROP_COPY' and IE & Opera reports the event as 'DND.DROP_NONE'. The event is handled by ResourceTransferDragAdapter#dragFinished(DragSourceEvent), where the resource is deleted when the event.detail == DND.DROP_MOVE.
As mentioned in https://bugs.eclipse.org/bugs/show_bug.cgi?id=30543#c2, Firefox reports the event as a MOVE which prompts Eclipse to delete the corresponding resource. There exists an open bug to track this issue in mozilla: http://bugzilla.mozilla.org/show_bug.cgi?id=191400

File and folder DnD is handled by FileTransferDragAdapter, where if event.detail == DND.DROP_MOVE, then it is ignored as part of bug 30543. We may adopt this approach in ResourceTransferDragAdapter also, but this is kind of crippling the existing functionality as we will be incapable of handling a genuine MOVE event.

So as Markus sugested modifying the implementation of DelegatingDragAdapter#dragFinished(..) seems to be the right solution.
Send the event to all active listeners after setting event.doit==false
The problem with this approach is that when currentListener!=null, then among the active listeners there are some listeners which do not check the status of 'event.doit' before processing it and this can lead to unforseen issues. e.g. EditorInputTransferDragAdapter#dragFinished(DragSourceEvent). Hence i would suggest that we modify the code such that, if currentListener==null, then set event.doit==false and invoke all the active listeners to handle the event.
Comment 6 Markus Keller CLA 2013-05-28 13:49:33 EDT
Created attachment 231644 [details]
Fix

I think this is the right way to fix the problem, but the fix needs more testing. It's based on the protocols defined in the Javadoc of DragSourceListener, DragSourceListener#dragFinished(DragSourceEvent), and DragSourceEvent#doit. The DelegatingDragAdapter has to simulate "cancelled" events for all DragSourceListeners that didn't become the currentListener.

Before releasing this, make a pass over all implementations of DragSourceListener#dragFinished(..) to make sure they handle "doit == false" correctly.

Note that the scenario at hand is so weird because Firefox, Thunderbird, and Safari don't implement the DND protocol correctly.
Comment 7 Markus Keller CLA 2013-05-28 14:00:43 EDT
Created attachment 231646 [details]
Fix for 4.3.1 (or 4.3)

(In reply to comment #5)
> So as Markus sugested modifying the implementation of
> DelegatingDragAdapter#dragFinished(..) seems to be the right solution.
> Send the event to all active listeners after setting event.doit==false
> The problem with this approach is that when currentListener!=null, then
> among the active listeners there are some listeners which do not check the
> status of 'event.doit' before processing it and this can lead to unforseen
> issues. e.g. EditorInputTransferDragAdapter#dragFinished(DragSourceEvent).
> Hence i would suggest that we modify the code such that, if
> currentListener==null, then set event.doit==false and invoke all the active
> listeners to handle the event.

Yes, this is probably the safest fix for 4.3.1.

I would even release this for 4.3 RC3. Dani, +1?
Comment 8 Dani Megert CLA 2013-05-28 14:12:34 EDT
(In reply to comment #7)
> Created attachment 231646 [details] [diff]
> Fix for 4.3.1 (or 4.3)
> 
> (In reply to comment #5)
> > So as Markus sugested modifying the implementation of
> > DelegatingDragAdapter#dragFinished(..) seems to be the right solution.
> > Send the event to all active listeners after setting event.doit==false
> > The problem with this approach is that when currentListener!=null, then
> > among the active listeners there are some listeners which do not check the
> > status of 'event.doit' before processing it and this can lead to unforseen
> > issues. e.g. EditorInputTransferDragAdapter#dragFinished(DragSourceEvent).
> > Hence i would suggest that we modify the code such that, if
> > currentListener==null, then set event.doit==false and invoke all the active
> > listeners to handle the event.
> 
> Yes, this is probably the safest fix for 4.3.1.
> 
> I would even release this for 4.3 RC3. Dani, +1?

I don't see the urgency to squeeze this into RC3.
Comment 9 Dani Megert CLA 2013-05-28 14:13:21 EDT
Comment on attachment 231646 [details]
Fix for 4.3.1 (or 4.3)

The fix looks good, but too late to take the risk for 4.3.
Comment 10 Dani Megert CLA 2013-07-24 10:05:00 EDT
For now we'll fix this in 4.4 and 4.3.1 with the safe fix from comment 7. Filed bug 413647 for the more complex fix proposed in comment 6.

Fixed with http://git.eclipse.org/c/platform/eclipse.platform.ui.git/commit/?id=9bd76f68af3f87aad0c99de0fd623b79eba5ae16

Filed bug 413644 for the backport to 4.3.1.
Comment 11 Wojciech Sudol CLA 2014-05-30 08:30:01 EDT
Verified in I20140528-2000 with Chrome and Firefox on Windows 7.