Bug 196176 - [DND] Need API for deferred transfer of remote files to Windows Explorer through drag&drop
Summary: [DND] Need API for deferred transfer of remote files to Windows Explorer thro...
Status: NEW
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 3.3   Edit
Hardware: All All
: P3 enhancement with 5 votes (vote)
Target Milestone: ---   Edit
Assignee: Platform-SWT-Inbox CLA
QA Contact: Kevin Barnes CLA
URL:
Whiteboard:
Keywords: api, helpwanted, triaged
: 301007 (view as bug list)
Depends on:
Blocks: 153652 181458
  Show dependency tree
 
Reported: 2007-07-11 11:31 EDT by Martin Oberhuber CLA
Modified: 2017-06-30 12:00 EDT (History)
20 users (show)

See Also:


Attachments
StreamTransfer (7.25 KB, text/x-java)
2008-06-04 11:55 EDT, Radoslav Gerganov CLA
no flags Details
Replace dialog for virtual file (17.30 KB, image/jpeg)
2008-06-05 04:33 EDT, Radoslav Gerganov CLA
no flags Details
Proof-of-concept patch for doing async drag&drop (17.88 KB, patch)
2008-06-18 05:36 EDT, Radoslav Gerganov CLA
no flags Details | Diff
FileStreamTransfer and DND.ASYNC (24.70 KB, patch)
2009-03-03 10:10 EST, Radoslav Gerganov CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Martin Oberhuber CLA 2007-07-11 11:31:24 EDT
+++ This bug was initially created as a clone of Bug #181458 +++

As documented in bug #181458, we have a requirement to select remote files in our UI and drag&drop them to Windows Explorer.

Currently, FileTransfer is the only transfer type supported in order to drag files outside Eclipse. But FileTransfer requires the file to exist on the local hard disk at the time the drag is initiated.

We cannot do this with remote files. What we need instead, is store some reference to the remote file on drag, and initiate an actual download / copy by means of a callback in our code at the time the drop is done. Note that since the introduction of Eclipse Filesystem (EFS), any resource in the Resource Navigator or Project Explorer can actually be a remote file which does not exist locally, but for which only a Stream can be opened in order to download it. I thus think that enhanced drag&drop functionality for files as requested is important for the Platform as a whole.

We know from other Windows applications like WinSCP that such a callback on drag&drop is possible. We'd like to get this through SWT as well.
Comment 1 Martin Oberhuber CLA 2007-07-11 11:46:00 EDT
I think this is actually a duplicate of bug #134247, which has no comments.
Could we get a statement from the SWT team?
Comment 2 John Arthorne CLA 2007-07-11 12:16:41 EDT
(bug 157632 is somewhat related)
Comment 3 Martin Oberhuber CLA 2007-07-11 12:27:53 EDT
Perhaps what we need is a FileReferenceTransfer, using URIs instead of local paths? The problem might be that different applications have a different idea of how the URI should be constructed, but still this might end up in a solution for bug #157632 as well (just an idea).
Comment 4 Eric Zimmerman CLA 2007-07-11 13:04:32 EDT
I have looked into this in the past.  The biggest issue is that Windows does not support this type of operation directly.  

It looks like WinSCP added some external shell trickery to monitor drop operations externally and somehow notify the application of the paths.  It takes a reboot of your machine after installing WinSCP to even make this work.

"Promised" files are supported on the Mac OSX platform natively, not sure about Linux.
Comment 5 Martin Oberhuber CLA 2007-07-12 07:33:21 EDT
I googled for "windows drop callback" and found this in the Sun Java BugParade:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6429556
This is an excellent description of what we want to achieve. 

It has been resolved by Sun as a duplicate of this:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4808793
which is a great description of a slightly more generic request, including discussions (note: the sample code provided does not work properly. Apparently the JDK also still fails to support delayed copy). One comment states: 

"Please read my problem statement and then read up on the windows HDROP type and using the COLEDataSource's delayed rendering methods (there are other analogies on the other platforms as well, e.g., promise data flavors on OS X, but this is the most clear)." - which seems to indicate to me that Windows API does have some support for delayed copy.

Other comments are also clear that native appliations on Windows do support delayed download on drop. Another comment says: "A reasonable workaround may be to offload the drop completion to native application to a separate thread. This drop finalizer thread could then perform the copy of the data and display some form of progress bar."

Following that discussion, it looks like this could be an excellent opportunitz for SWT to provide better functionality and Native Platform integration that JDK/Swing/NetBeans. Want to go for it?
Comment 6 Martin Oberhuber CLA 2007-07-12 07:50:30 EDT
Following yet another link, I was wondering if the following would work:
http://help.eclipse.org/help32/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/dnd/DragSourceListener.html

class DeferredCopyDragSourceListener implements DragSourceListener {
   public void dragStart(DragSourceEvent event) {}
   public void dragSetData(DragSourceEvent event) {
     //create a local EMPTY file in tmp dir with same name as real file
     //return the local EMPTY file (placeholder) via FileTransfer
   }
   public void dragFinished(DragSourceEvent event) {
     //delete the local EMPTY tmp placeholder
     //If dnd was not canceled: create a new Job to do the actual data transfer
     //The problem here is, that we are not informed about the target location
     //where the file should be dropped. Getting this information from
     //event.detail would perhaps already suffice to get this fixed.
   }
};

One drawback of this kind of solution would be that in case the file to be transferred already exists in the target directory, Windows shows a dialog on drop ("File foo already exists: do you want to overwrite?"). This dialog also shows file size and timestamp of source and destination. Since at this time, Windows only has the empty temp placeholder, users would think that a 0-byte-file is about to be overwritten - although the real file might be much larger but to be transferred after that dialog.

Because of this, I'd think that new API specific to the kinds of callback the native OS supports would be preferrable to that workaround solution.
Comment 7 Martin Oberhuber CLA 2007-07-12 07:55:04 EDT
BTW, at Sun this request has been open against the JDK since January 2003, it currently has 53 votes, and it is labelled as "in progress, enhancement".
Comment 8 Eric Zimmerman CLA 2007-07-12 12:16:33 EDT
Regarding the end of comment #6

Most applications that take this approach, use a very unique filename that would theoretically not be a duplicate.  This has two advantages of both avoiding the duplicate name issue, and letting the user know that the file is NOT available to use yet.  Once the download is complete, it then just renames the file.

As you say though, the issue with using this workaround right now is that you don't really get the final drop path(IIRC).
Comment 9 Grant Gayed CLA 2007-07-17 12:30:17 EDT
Duong/Steve, any wisdom?
Comment 10 Steve Northover CLA 2007-08-14 12:59:10 EDT
Just seeing this now (Bugzilla burning me?).  Duong to construct a simple test case that shows the problem.  Without getting into too many details, it is possible to offload the copy to another thread.  I have done this in sample code somewhere but can't find it.  Not sure if this is good enough to solve the problem.
Comment 11 Duong Nguyen CLA 2007-08-15 13:59:10 EDT
There are two sections from an MSDN link MSDN that's worth reading:
   http://msdn2.microsoft.com/en-us/library/aa969396.aspx#transferring_virtual
   http://msdn2.microsoft.com/en-us/library/aa969396.aspx#async

I'm going to investigate a bit more.
Comment 12 Martin Oberhuber CLA 2007-08-16 06:32:30 EDT
The virtual folder thing with CFSTR_FILEDESCRIPTOR / CFSTR_FILECONTENTS / IStream looks very promising, though I cannot currently see how this could translate into an SWT API. Perhaps it could translate into the FileReferenceTransfer type I have mentioned in comment #3, but embedding an actual Java Stream rather than an URI?

IAsyncOperation seems a very generic concept that might translate well into an API, but the documentation does not indicate whether Windows would support this for files (which this bug is about).

Thanks for your investigations, I'm looking forward to more! Is there anybody who knows how GTK or Mac do such kinds of deferred file operations?
Comment 13 Duong Nguyen CLA 2007-08-16 11:26:07 EDT
I'm hacking up a virtual folder example now to see if I can even do it in Java and to learn how it all works in Windows. I don't whether the other platforms have something equivalent.

I was thinking of a StreamTransfer class and the object that you're transferring or receiving is a Java Stream. However, this still doesn't solve the problem that the main thread (UI) appears to hang if the reading and writing of the stream is still happening inside the drag-and-drop. If the source starts writing into the stream on dragStart and the drop target starts reading from the stream on drop then we haven't solved anything.

The source must create a background thread to write into the stream on dragFinish and the target must create a background thread to read from the stream on drop.

That's just my thought. There's no commitment for any new SWT API since I'm still investigating.
Comment 14 Duong Nguyen CLA 2007-09-17 14:00:06 EDT
Martin Oberhuber:
Would you consider putting this note on Bugzilla such that others
watching the bug could chime in?

> Duong Nguyen: 
> I worked on this for a few days and I just couldn't get it to work. I'm still
> not clear how the windows api works. 
>
> The windows api doesn't appear to work the way I thought so the 
> StreamTransfer will not work. I had to leave it and move on to something else.
Comment 15 Martin Oberhuber CLA 2007-11-21 15:12:53 EST
Windows API wizards... could anyone help out here? This bug is really a great chance for getting famous!

Or are all the freaky geeks just blowing their minds out on Mac/Cocoa (http://eclipse.pookzilla.net/2007/11/you-heard-man-blow-your-brains-out.php)?
Comment 16 Radoslav Gerganov CLA 2008-06-04 11:55:09 EDT
Created attachment 103583 [details]
StreamTransfer

I have implemented a StreamTransfer class using the CFSTR_FILEDESCRIPTOR/CFSTR_FILECONTENTS/IStream approach. It works only one way for now, i.e. you can drag&drop virtual files from your java application to native apps. Here is how it works: you need to register one CFSTR_FILEDESCRIPTOR type for all files and one CFSTR_FILECONTENTS for each file that is going to be transfered. When CFSTR_FILEDESCRIPTOR is requested you need to provide one FILEGROUPDESCRIPTOR which describes all files that will be dragged. When CFSTR_FILECONTENTS is requested you need to provide an IStream to the corresponding virtual file using the specified index. My implementation of IStream (MyIStream) is reading data from the java.io.InputStream specified in DragSourceListener#dragSetData. The FILEGROUPDESCRIPTOR is hardcoded for now but it can also be specified in DragSourceListener#dragSetData.
The problem with this solution is that MyIStream#Read is called in the UI thread and can potentially block the UI. However it can be offloaded using the approach described here: http://msdn.microsoft.com/en-us/library/bb776904.aspx#async

Martin, do you think this is what we need for RSE?
Comment 17 Martin Oberhuber CLA 2008-06-04 12:01:09 EDT
This sounds awsome. I can't believe you can do this without any native DLL! Yes, this sounds like exactly what we need and might be fixing a long-standing problem.

I don't understand all the details yet, but it seems like you're going to become a hero with this... please continue investigations in this direction, unless others on this bug think that they see potential issues. We could run it as prototype inside RSE and have it contributed to SWT in the next year if it works out.

Just wondering, do you think that this basic concept might also translate for deferred drag and drop on other systems like GTK or MacOS?
Comment 18 Radoslav Gerganov CLA 2008-06-05 04:33:00 EDT
Created attachment 103704 [details]
Replace dialog for virtual file

In my example of StreamTransfer only the filename is specified in the FILEGROUPDESCRIPTOR, so it is interesting what happens if the file already exists in the drop target. It turns out that Windows handles this properly and displays a dialog asking to replace the existing file with another one having unknown date and size (see the attached image).
Comment 19 Radoslav Gerganov CLA 2008-06-09 13:22:46 EDT
(In reply to comment #17)
> Just wondering, do you think that this basic concept might also translate for
> deferred drag and drop on other systems like GTK or MacOS?
> 

I don't know, the idea of creating StreamTransfer looks generic but I am not familiar with GTK/MacOS to be sure.

I have implemented IAsyncOperation for the data object in DragSource and now DoDragDrop returns immediately. However my IStream is called back in the UI thread:

StreamTransfer$MyIStream.Read(int, int, int) line: 152	
StreamTransfer$MyIStream.access$3(StreamTransfer$MyIStream, int, int, int) line: 151	
StreamTransfer$MyIStream$1.method3(int[]) line: 120	
COMObject.callback3(int[]) line: 92	
OS.DispatchMessageW(MSG) line: not available [native method]	
OS.DispatchMessage(MSG) line: 2370	
Display.readAndDispatch() line: 3418	
StreamTransfer.main(String[]) line: 200	

I guess that I have to start another thread with a message loop and call DoDragDrop there. Any thoughts?
Comment 20 Martin Oberhuber CLA 2008-06-09 17:20:19 EDT
What's so bad about getting the Stream.read() called on the UI thread?

Important point is that the UI thread which calls you, calls read() only when avaialble() returns true, in order to avoid blocking call on the UI thread. As long as the read calls into the Stream are not blocking, I see no problem with running on the UI thread.
Comment 21 Radoslav Gerganov CLA 2008-06-10 03:33:38 EDT
(In reply to comment #20)
> What's so bad about getting the Stream.read() called on the UI thread?
> 
> Important point is that the UI thread which calls you, calls read() only when
> avaialble() returns true, in order to avoid blocking call on the UI thread. As
> long as the read calls into the Stream are not blocking, I see no problem with
> running on the UI thread.
> 

OK, but what I am supposed to return in MyIStream#ReadData() if no data is available and blocking read() must be made? If I return 0 bytes read, this means that end-of-stream has been reached. The IStream interface doesn't provide method to query if there is available data in the stream.
Comment 22 Martin Oberhuber CLA 2008-06-10 03:36:57 EDT
Yuck! Apparently I have mixed up IStream with InputStream. Hm, so I'm clueless...
Comment 23 Radoslav Gerganov CLA 2008-06-10 03:41:38 EDT
(In reply to comment #22)
> Yuck! Apparently I have mixed up IStream with InputStream. Hm, so I'm
> clueless...
> 

Well, we could run the UI event loop in MyIStream#ReadData() until data becomes available or timeout occurs :) But this sounds more like a hack rather than a solution ...
Comment 24 Radoslav Gerganov CLA 2008-06-18 05:36:05 EDT
Created attachment 105266 [details]
Proof-of-concept patch for doing async drag&drop

Reading from the IStream could be offloaded if DoDragDrop is called in another thread. The background thread must attach it's input to the UI thread using AttachThreadInput and it must run a message pump in order to dispatch the COM callbacks (STA thread). From now on, each call to IStream#Read is made in the background thread. When all data is extracted from the IStream, the drop target calls IAsyncOperation#EndOperation and we can terminate the background thread and send DragEnd event to all listeners. 
During the drag&drop our drag source is queried for two data types - CFSTR_FILEDESCRIPTOR and CFSTR_FILECONTENTS. We must provide FILEGROUPDESCRIPTOR  for the first type and IStream for the second type in dragSetData(). Here comes the problem - during the drag we could be queried for CFSTR_FILEDESCRIPTOR many times while moving the mouse over different folders in the Explorer but we want to open an input stream to the remote file only when the "drop" happens (the mouse button is released and transfer must be performed). In other words we want to create an input stream only when CFSTR_FILECONTENTS is requested. Providing file descriptors is not an issue because it is just a simple data structure containing file properties but providing an input stream could be expensive operation (like in the RSE case). So I have added another public method FileStreamTransfer#isContentType() in order to differentiate between CFSTR_FILEDESCRIPTOR and CFSTR_FILECONTENTS. The implementation of DragSourceListener#dragSetData() becomes:

public void dragSetData(DragSourceEvent event) {
  if (FileStreamTransfer.getInstance().isSupportedType(event.dataType)) {
    // provide descriptor
    if (FileStreamTransfer.getInstance().isContentType(event.dataType)) {
      // provide descriptor + input stream
    }
}

Note that checking only for isSupportedType() will also work but it may lead to creating unneeded input streams. So we want to open the input stream only if we know for sure that the file is dropped and transfer will occur.
FileStreamTransfer has a main method so you can play with to see the events sequence. It works only for one file but it can be easily extended to support multiple files by passing an array of file descriptors instead of single object. I will also provide a patch for RSE in bug 181458 for DND of remote files.
Comment 25 Radoslav Gerganov CLA 2008-11-06 04:33:29 EST
Some information about D&D of virtual files using the IStream interface can be found here: http://blogs.msdn.com/oldnewthing/archive/2008/03/19/8080215.aspx
Basically, I have implemented the same approach plus offloading the reading of the stream in another thread.
Comment 26 Martin Oberhuber CLA 2009-03-02 13:23:24 EST
The Eclipse 3.5 API freeze is coming near, and on this bug we have some working code for a fantastic new feature, which would put SWT further ahead of Swing in terms of Platform integration.

All we need at this point is some review and feedback from the SWT committers... could anybody here have a look? Rado is willing to contribute more work in this if you folks could just give us some pointers what you like or not...

Actually, the only new API here is

   public class org.eclipse.swt.dnd.FileStreamTransfer

which seems to make a lot of sense to me, even when thinking multi-platform... 

Thanks!
Comment 27 Martin Oberhuber CLA 2009-03-02 13:36:30 EST
PS at the moment, the "Proof-of-concept" patch applies with a fuzz factor of 2.
Comment 28 Kevin Barnes CLA 2009-03-02 15:01:16 EST
Next week is the milestone week and the API freeze for 3.5. We cannot commit to API without implementing it on all of our supported platforms and we're not going to have time to do that this week. Sorry, it's just too late to get this into 3.5 now.
Comment 29 Radoslav Gerganov CLA 2009-03-03 06:39:05 EST
We could introduce only a new hint (e.g. DND.ASYNC) as public API for offloading the D&D in a background thread and keep the FileStreamTransfer as internal RSE class until we make it stable and then release it in SWT.
For now this hint will work only for Win32 and will do nothing on other platforms.
Comment 30 Martin Oberhuber CLA 2009-03-03 07:51:26 EST
(In reply to comment #28)
> We cannot commit to API without implementing it on all of our supported

Hi Kevin, many thanks for looking at this. I don't want to interfere with SWT policies that have proven to be useful.

But I don't quite understand your argument yet... in my understanding, clients can request / provide a kind of DND tranfer, but if the OS (or SWT integration) doesn't support it, the application must be prepared for that case anyways. It's part of the DND negotiation protocol. So I cannot quite see why an API for this would require implementation on all Platforms? Some platforms might not even support that concept.

Supporting asynchronous drag and drop is, to me, a matter of modeling the reality. To that end, the question is whether the proposed API does model reality in a useful way. And given that Java Streams have successfully been applied almost universally, I am very confident that the proposed patch does model reality in the right way.

Just to recap the original requirement: given some file-like data in a remote location that's not accessible to FileTransfer (but accessible as a Stream), make it possible to have that file-like data transferred by drag and drop and materialized as a file locally (in Windows Explorer, for instance). Windows provides API for that, and FileStreamTransfer models that reality.

The new proposal of just having a "hint" whether the transfer is expected to happen synchronously or asynchronously also seems to address this. Rado, could you illustrate your new proposal with a patch?
Comment 31 Radoslav Gerganov CLA 2009-03-03 10:10:11 EST
Created attachment 127326 [details]
FileStreamTransfer and DND.ASYNC

Here is the updated version of the patch (thanks to Martin for helping with the javadoc). Basically, the problem consists of two parts:
1. Implementing a new transfer type for doing D&D using streams - that is FileStreamTransfer which provides an implementation of the native IStream. It can be considered as custom transfer type for Win32 as the one in Snippet79, however I think it is best to be included in the SWT internal packages for Win32.
2. Adding support for offloading the D&D in a background thread in order to avoid blocking the UI thread. Of course, we don't want to offload every D&D operation, so we need some API to specify this behaviour. I am proposing a new flag - DND.ASYNC - for this purpose. My patch for DragSource is to take DND.ASYNC into account. I believe the same could be done for DropTarget as well.

You can experiment with the new APIs using the attached SnippetFST. For example put a breakpoint in FileStreamTransfer.MyIStram#Read and see in which thread it is called depending on the DND.ASYNC flag.
Comment 32 Martin Oberhuber CLA 2009-10-13 18:35:19 EDT
I would like to revive this discussion.
Is it possible to get our patch accepted now, into early 3.6 ?
Comment 33 Damjan Jovanovic CLA 2009-12-14 15:22:08 EST
Hi

I've made a patch for OpenJDK7's java.awt that implements this feature on Windows and X11.

The bug with my patch is at https://bugs.openjdk.java.net/show_bug.cgi?id=100124 and the email linked to from that bug (or directly at http://mail.openjdk.java.net/pipermail/awt-dev/2009-December/001043.html) explains the approach I took.

Anyway, feel free to port it to SWT. Christmas comes early this year :-).
Comment 34 Martin Oberhuber CLA 2009-12-15 06:41:25 EST
(In reply to comment #33)
> Anyway, feel free to port it to SWT. Christmas comes early this year :-).

Thanks Damjan :)

Now before anybody moves forward and starts reading your code... can you confirm that you would contribute that patch under the EPL license, that your employer is OK with you doing so, and that you wrote that patch yourself without referencing any material except under EPL?

This is a rare situation where we are asked to review code that originates from elsewhere (outside the Eclipse universe). We must make sure not to accidentally introduce GPL to Eclipse (OpenJDK is under GPLv2). 

I think I'd feel better if you could attach your patch here on bugzilla with a confirmation that you are contributing under EPL. Ideally, make your attchment such that it only includes *your* code and not any (removed) original JDK lines. Or just talk about the concepts/ideas/APIs/added by you. I might seem paranoid here, but this is really a sensitive thing to do.
Comment 35 Martin Oberhuber CLA 2010-01-27 10:51:48 EST
Ping - what do people think is missing to get this accepted into Eclipse?

The patch has a working implementation of asynchronous drag-and-drop for Windows, along with a Snippet to test/demonstrate the feature. It has Javadoc. It does what we need.

As per comment 29, there is also the possibility to reduce the patch to a single new API constant (DND.ASYNC) as the least common denominator in terms of API. So... what is missing?
Comment 36 Luzius Meisser CLA 2010-01-27 11:26:31 EST
*** Bug 301007 has been marked as a duplicate of this bug. ***
Comment 37 Kevin Barnes CLA 2010-01-27 11:33:52 EST
> what is missing?

1) implementations for gtk, cocoa, carbon and motif
2) resources - This item is not on the plan for 3.6 and we are busy working on committed items.
Comment 38 Martin Oberhuber CLA 2010-01-27 11:54:19 EST
(In reply to comment #37)
Hm.

> 1) implementations for gtk, cocoa, carbon and motif

Is there a policy to only allow new features when there are complete implementations on all major Platforms? Even if all we are asking (in the simple case) is adding an API constant with clearly defined semantics? What about other features that are available on only specific Platforms, like the SWT.SHEET constant specific to Mac Cocoa and added in 3.5?

Note that as per the final paragraph on http://mail.openjdk.java.net/pipermail/awt-dev/2009-December/001043.html there is no GTK API for the feature, I'd be surprised if Motif had it (plus Motif and Carbon are declining in importance).

> 2) resources - This item is not on the plan for 3.6 and we are busy 

I do understand that reviewing and applying a patch does not come for free and does take some resources. On the other hand I find it frustrating that we've been working on this since more than two years, I pinged the SWT team EARLY in 3.6 and still there is no time for this even if bulk of the work is contributed by us.
Comment 39 Tobias Fink CLA 2012-02-09 09:49:37 EST
*ping*
Is there any new development on this? I found a solution here for win32 platforms, but it'd be cool to have something at least supporting win x64 too.
Comment 40 Pavanesh Netrakar CLA 2012-03-07 13:58:30 EST
Hi I have downloaded StreamTransfer and try to drag the text from the label to windows explorer..nothing is happening.

I am working on Windows XP with Eclispe 3.7 .

Can any one of you please suggest me if anything I am missing?

Thanks and regards
-Pavanesh
Comment 41 Eric Williams CLA 2017-06-30 12:00:09 EDT
Bug triaged, visit https://wiki.eclipse.org/SWT/Devel/Triage for more
inforamation.