JDK-6448332 : Swing DnD: Allow custom components to support drop location exchange
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 6
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2006-07-13
  • Updated: 2017-05-23
Related Reports
Duplicate :  
Relates :  
Description
A DESCRIPTION OF THE FIX :
The new Swing Drag'n'Drop API enhancements in Mustang are usefull but I find them to limiting when trying to use them with custom components. Here I propose a minimum addition to make them even more usefull.

Swing's TransferManager has 2 new methods that are called from SwingDropTarget instead of the old ones:

    public boolean canImport(TransferHandler.TransferSupport support);

    public boolean importData(TransferHandler.TransferSupport support);

By default they delegate to the old methods so that old programs still work. These methods and mechanisms underneath are very handy and useful for various d'n'd scenarios. I very much would like to use these mechanisms for implementing d'n'd in my custom components too.

There's also a new class called TransferHandler.DropLocation that has some specific subclasses for particular Swing components. The mechanism for creating a custom DropLocation and setting the "dropLocation" property on a Swing component is not exposed to custom subclasses of Swing components. If one wants to create a custom Swing component and use new TransferHandler's capabilities of managing the drop location, it is a no go. The particular methods in JComponent and some subclasses are package protected. There are even some reflection tricks to access the JTextComponent's package protected methods from other package.

I can understand that making these methods public and overridable could hurt compatibility since the names of the methods could already be used in subclasses arround the world. The tricks to use package private methods for standard Swing components is understandable. But why not allowing custom components to support drop location exchange?

I propose the following:

Add an interface to the javax.swing package (or as an inner interface of javax.swing.TransferHandler) that standard swing components would not implement but would be available as an optional interface for custom swing components:

public interface DropLocationSupport
{
   TransferHandler.DropLocation dropLocationForPoint(Point p);
   
   Object setDropLocation(TransferHandler.DropLocation location, Object state, boolean forDrop);
 
   void dndDone();
}


Then add to the TransferHandler.DropHandler some code to call these methods whenever a custom component implements this interface. For example in TransferHandler.DropHandler.setComponentDropLocation():

           if (component instanceof DropLocationSupport) {
                state = ((DropLocationSupport)component).setDropLocation(dropLocation, state, forDrop);
           }
           else if (component instanceof JTextComponent) {
                try {
                    AccessibleMethod method =
                        new AccessibleMethod(JTextComponent.class,
                                             "setDropLocation",
                                             DropLocation.class,
                                             Object.class,
                                             Boolean.TYPE);

                    state =
                        method.invokeNoChecked(component, dropLocation,
                                               state, forDrop);
                } catch (NoSuchMethodException e) {
                    throw new AssertionError(
                        "Couldn't locate method JTextComponet.setDropLocation");
                }
            } else if (component instanceof JComponent) {
                state = ((JComponent)component).setDropLocation(dropLocation, state, forDrop);
            }


That's one way of doing it. And the most straightforward I think. The other possibility would be to delegate drop location interchange to an intermediary that would be associated with:

possibility 1: a TransferHandler
possiblility 2: a Component


possibility 1: add an interface and a constructor to TransferHandler that would take an instance implementing this interface:

public interface DropLocationDelegate
{
   TransferHandler.DropLocation dropLocationForPoint(Component c, Point p);
   
   Object setDropLocation(Component c, TransferHandler.DropLocation location, Object state, boolean forDrop);
 
   void dndDone(Component c);
}


possibility 2: add a single public overridable method to JComponent:

   public DropLocationSupport getDropLocationSupport();

this method would return an instance implementing DropLocationSupport interface described above.


I think that possibility 2 is more suitable since it allows for overriding/delegating on the JComponent level.


Is any of these acceptable?

Regards, Peter


JUnit TESTCASE :
No code to demonstrate.

Comments
EVALUATION I made it most of the way towards a solution (as far as code review) and then got interrupted. It's now almost two years later and I've not come back to it. So I'm going to attach a webrev of what I did (which includes copies of the new files). Also, I'll place in the comments section of this report the review comments that came up during code review. All of this can also be found at http://sa.sfbay.sun.com/mail-archive/6448332/
16-10-2008

EVALUATION Also find attached, two manual tests that can exercise some of the behavior.
16-10-2008

EVALUATION Note: Moving the dropLocationForPoint implementation into the UI is covered under 6500024.
02-12-2006

EVALUATION Fixing this together with 6436908. My current proposal is to add the following to JComponent: protected void dndEnter() protected void dndExit(boolean forDrop) protected TransferHandler.DropLocation dropLocationForPoint(Point p) protected void setDropLocation(TransferHandler.DropLocation location) public TransferHandler.DropLocation getDropLocation() This allows two things: 1) Custom drop location exchange 2) Developers of ALL components to take advantage of getDropLocation for rendering.
02-12-2006

EVALUATION Yes! This is definitely on the agenda for consideration in Dolphin. The current thought is to make dropLocationForPoint protected and move the default implementation into the UI classes. This will allow developers and subclassers to implement this for custom components.
13-07-2006