Skip to main content

Providing drag & drop feedback for custom JComponents

2 replies [Last post]
aephyr
Offline
Joined: 2009-11-20

Since the methods that follow in JComponent are package-private, it is near impossible to provide drop feedback:

<br />
DropLocation dropLocationForPoint(Point p)</p>
<p>Object setDropLocation(TransferHandler.DropLocation location, Object state, boolean forDrop)<br />

The Workaround I have now is both ugly and insufficient. To get access to the accept/reject status, Swing's DropTarget is wrapped and calls to dragEnter(DropTargetDragEvent) and dragOver(DropTargetDragEvent) wrap those event objects before dispatching to Swing's DropTarget. Works fine, but it doesn't honor the TransferHandler.TransferSupport.showDropLocation property.

<br />
class JExample extends JComponent {</p>
<p>	public void setTransferHandler(TransferHandler th) {<br />
		super.setTransferHandler(th);<br />
		if (th != null)<br />
			setDropTarget(new DT(getDropTarget()));<br />
	}</p>
<p>	private void setDropLocation(Point pt) {<br />
		DropLocation oldLocation = dropLocation;<br />
		dropLocation = pt == null ? null :<br />
			createDropLocation(pt);<br />
		if (oldLocation == null ? dropLocation != null :<br />
				!oldLocation.equals(dropLocation))<br />
			repaint(); // TODO: trim this repaint call<br />
	}</p>
<p>	private class DTDE extends DropTargetDragEvent {</p>
<p>		DTDE(DropTargetDragEvent e) {<br />
			super(e.getDropTargetContext(), e.getLocation(),<br />
					e.getDropAction(), e.getSourceActions());<br />
			dtde = e;<br />
		}</p>
<p>		private DropTargetDragEvent dtde;</p>
<p>		@Override<br />
		public void acceptDrag(int dragOperation) {<br />
			setDropLocation(dtde.getLocation());<br />
			dtde.acceptDrag(dragOperation);<br />
		}</p>
<p>		@Override<br />
		public void rejectDrag() {<br />
			setDropLocation(null);<br />
			dtde.rejectDrag();<br />
		}</p>
<p>	}</p>
<p>	private class DT extends DropTarget {</p>
<p>		DT(DropTarget dt) {<br />
			super(dt.getComponent(), dt.getDefaultActions(), null);<br />
			delegate = dt;<br />
		}</p>
<p>		private DropTarget delegate;</p>
<p>		@Override<br />
		public void dragEnter(DropTargetDragEvent dtde) {<br />
			delegate.dragEnter(new DTDE(dtde));<br />
		}</p>
<p>		@Override<br />
		public void dragExit(DropTargetEvent dte) {<br />
			delegate.dragExit(dte);<br />
			setDropLocation(null);<br />
		}</p>
<p>		@Override<br />
		public void dragOver(DropTargetDragEvent dtde) {<br />
			delegate.dragOver(new DTDE(dtde));<br />
		}</p>
<p>		@Override<br />
		public void drop(DropTargetDropEvent dtde) {<br />
			delegate.drop(dtde);<br />
			setDropLocation(null);<br />
		}</p>
<p>		@Override<br />
		public void dropActionChanged(DropTargetDragEvent dtde) {<br />
			delegate.dropActionChanged(dtde);<br />
		}</p>
<p>		@Override<br />
		public void addDropTargetListener(DropTargetListener dtl)<br />
				throws TooManyListenersException {<br />
			delegate.addDropTargetListener(dtl);<br />
		}</p>
<p>		@Override<br />
		public void removeDropTargetListener(DropTargetListener dtl) {<br />
			delegate.removeDropTargetListener(dtl);<br />
		}</p>
<p>	}<br />

I hope someone can point out a better way!

Edit: Almost forget the biggest problem... The custom DropLocation is not accessible from the TransferHandler. Only TransferHandler's default DropLocation with the drop coordinates only is returned.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
walterln
Offline
Joined: 2007-04-17

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6448332

Maybe you could try the swing-dev mailing list to see if the ready-for-code-review revision mentioned there is still available.

aephyr
Offline
Joined: 2009-11-20

Thanks for the link. So there is hope that the functionality will be available in 1.7! Now if only there was hope that 1.7 will get released.