Path: news.mathworks.com!not-for-mail
From: <HIDDEN>
Newsgroups: comp.soft-sys.matlab
Subject: Re: Java drag & drop
Date: Sat, 4 Apr 2009 19:22:01 +0000 (UTC)
Organization: TACT Computer Systems Ltd
Lines: 74
Message-ID: <gr8c0p$t5r$1@fred.mathworks.com>
References: <fahm1i$5e7$1@fred.mathworks.com> <fc6889$n5i$1@fred.mathworks.com> <fc91jd$2uu$1@fred.mathworks.com> <fc93qh$d7j$1@fred.mathworks.com> <gfvdhq$13l$1@fred.mathworks.com> <gg1bn6$up$1@fred.mathworks.com> <gg46ub$o63$1@fred.mathworks.com> <gr55hd$26l$1@fred.mathworks.com>
Reply-To: <HIDDEN>
NNTP-Posting-Host: webapp-03-blr.mathworks.com
Content-Type: text/plain; charset="ISO-8859-1"
Content-Transfer-Encoding: 8bit
X-Trace: fred.mathworks.com 1238872921 29883 172.30.248.38 (4 Apr 2009 19:22:01 GMT)
X-Complaints-To: news@mathworks.com
NNTP-Posting-Date: Sat, 4 Apr 2009 19:22:01 +0000 (UTC)
X-Newsreader: MATLAB Central Newsreader 642467
Xref: news.mathworks.com comp.soft-sys.matlab:530329


> I couldn't pinpoint the exact source of this problem either but do could locate it somewhere within Mathworks DropTargetListener which seems to pass the DropTargetDropEvent (dtde) to the Matlab callback function without accepting the drop before, so dtde.getTransferable() fails.
> Since I wasn't able to solve that problem directly, I wrote a new DropTarget class "DropTargetList" which accepts the drop and stores transferable data as java.util.List in a new field. Matlab passes the DropTargetList object to the callback function as first argument: [snip...]

I'm afraid the acceptDrop() hunch is incorrect, since if you call dtde.acceptDrop() in the Matlab callback it still does not prevent an InvalidDnDOperationException being thrown from dtde.getTransferable(). 

I've tried to implement a Matlab-only approach that uses Java, but which does not require compiling a new Java class. I was successful to a point - perhaps others on this thread will have an idea how to proceed:

The basic idea is to use a list of plot command strings as drag source, and drop its items onto Matlab axes that will plot the requested command. Here's the setup:

% Set-up a figure with draggable list-box and 2 droppable axes
hFig = figure('name','DND example','numbertitle','off');
plotNames = {'surfc(peaks)','contour(peaks)','contourf(peaks)', ...
             'surf(membrane)','contour(membrane)','contourf(membrane)'};
jListbox = javax.swing.JList(plotNames);
[hjList,hcList] = javacomponent(jListbox,[10,10,100,200],hFig);
set(hcList,'units','norm','position',[.05,.05,.3,.6]);
hAx1 = axes('position',[.5,.1,.45,.35]);
hAx2 = axes('position',[.5,.55,.45,.35]);
jListbox.setDragEnabled(1);

% Enable drop on the figure axes
dnd = handle(java.awt.dnd.DropTarget(),'callbackProperties');
jFrame = get(hFig,'JavaFrame');
jAxis = jFrame.getAxisComponent;
jAxis.setDropTarget(dnd);
set(dnd,'DropCallback',{@dndCallbackFcn,hFig});
set(dnd,'DragOverCallback',@dndCallbackFcn);

Now the callback. I'm using a persistent transferable to overcome the intermittent behavior of the transferable object - sometime during the drag a valid transferable is available and them I'm grabbing it for reuse during the drop:

% The callback function
function dndCallbackFcn(varargin)
   persistent transferable
   eventData = varargin{2};
   if eventData.isa('java.awt.dnd.DropTargetDropEvent')  %nargin>2
       hFig = get(0,'PointerWindow');  %varargin{3};
       hAxes = overobj('axes');
       if ~isempty(hAxes)
           try transferable = eventData.getTransferable; catch, end
           dataFlavorStr = 'text/plain; class=java.lang.String';
           dataFlavor = java.awt.datatransfer.DataFlavor(dataFlavorStr);
           dataStr = transferable.getTransferData(dataFlavor);
           eventData.acceptDrop(eventData.getDropAction);
           axes(hAxes(1));
           set(hFig,'pointer','watch');
           eval(dataStr);
           %obj.getComponent.repaint;  % not really necessary
           eventData.dropComplete(true);
           set(hFig,'pointer','arrow');
       else
           eventData.rejectDrop();
       end
       eventData.dropComplete(true);
   elseif eventData.isa('java.awt.dnd.DropTargetDragEvent')
       try transferable = eventData.getTransferable; catch, end
       hAxes = overobj('axes');
       if isempty(hAxes)
           eventData.rejectDrag;
       else
           eventData.acceptDrag(eventData.getDropAction);
       end
   end

This works with 2 problems - Any ideas anyone?
1) after several drag-&-drops the figure stops accepting drags. It's not a source but a target problem, since DND from the list onto the editor still works.
2) the above does not work with a Matlab uicontrol('style','listbox') - setDragEnabled(1) on the underlying com.mathworks.hg.peer.ListboxPeer$UicontrolList is not enough to make the listbox draggable.

> Note to Yair Altman's suggestion to override the default drop target's TransferHandler(): I tried it and this also works but is much more difficult because one has to use JMI to call Matlab from Java. Also you get an error when calling "figure" from within the callback after compiling the m-file to a standalone application (very strange)

I would be grateful if you could post your code for us to learn.

Yair Altman
http://UndocumentedMatlab.com