JDK-4760426 : JTree DnD conflicts with JTree.setUI(..)
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0,1.4.2
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_nt,windows_2000
  • CPU: x86
  • Submitted: 2002-10-09
  • Updated: 2005-05-20
  • Resolved: 2005-05-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6
5.0u3Resolved 6Resolved
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
Name: sv35042			Date: 10/09/2002


FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-
b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version
5.00.2195]

ADDITIONAL OPERATING SYSTEMS :
Also on Linux

A DESCRIPTION OF THE PROBLEM :
JTrees with enabled drop support produce NullPointerExceptions when
setUI() was called on them.
It doesn't matter which TreeUI is used
(Windows, Metal, Basic, as soon as the TreeUI is changed the failure
appears.
This bug appears on Windows and Linux.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1.Compile and execute the program
2.Select with a click a component of
the left JTree
3.Drag this component to the textarea
4.Do steps 2+3
with the right JTree
5.You will see a NullPointerException on the
console

EXPECTED VERSUS ACTUAL BEHAVIOR :
The left JTree is working properly, whereas the right JTree produces
NullPointerExceptions when drags are moved out of the JTree.
Code is
working so far but there are NullPointerExceptions.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.NullPointerException
        at
javax.swing.plaf.basic.BasicTreeUI$TreeDropTargetListener.restoreComponentState(BasicTreeUI.java:3680)
 
       at
javax.swing.plaf.basic.BasicDropTargetListener.dragExit(BasicDropTargetListener.java:249)
 
       at javax.swing.TransferHandler$SwingDropTarget.dragExit(TransferHandler.java:579)
        
at
sun.awt.dnd.SunDropTargetContextPeer.processExitMessage(SunDropTargetContextPeer.java:396)
 
       at
sun.awt.dnd.SunDropTargetContextPeer.access$700(SunDropTargetContextPeer.java:52)
 
       at
sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher.dispatchExitEvent(SunDropTargetContextPeer.java:793)
 
       at
sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher.dispatchEvent(SunDropTargetContextPeer.java:741)
 
       at sun.awt.dnd.SunDropTargetEvent.dispatch(SunDropTargetEvent.java:29)
        at
java.awt.Component.dispatchEventImpl(Component.java:3384)
        at
java.awt.Container.dispatchEventImpl(Container.java:1437)
        at
java.awt.Component.dispatchEvent(Component.java:3367)
        at
java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3214)
        at
java.awt.LightweightDispatcher.trackMouseEnterExit(Container.java:3046)
        at
java.awt.LightweightDispatcher.processDropTargetEvent(Container.java:2992)
        at
java.awt.LightweightDispatcher.dispatchEvent(Container.java:2854)
        at
java.awt.Container.dispatchEventImpl(Container.java:1423)
        at
java.awt.Window.dispatchEventImpl(Window.java:1566)
        at
java.awt.Component.dispatchEvent(Component.java:3367)
        at
java.awt.EventQueue.dispatchEvent(EventQueue.java:445)
        at
java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:190)
 
       at
java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:144)
 
       at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
        at
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:130)
        at
java.awt.EventDispatchThread.run(EventDispatchThread.java:98)

This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import java.awt.dnd.*;
import java.awt.datatransfer.*;
import
java.awt.event.*;

import javax.swing.*;
import javax.swing.event.*;
import
javax.swing.tree.*;
import javax.swing.plaf.metal.MetalTreeUI;


public class
PanTree extends JFrame  {
  private JTree jtree;
  private JTree ofjtree;
  private
JScrollPane jscp;
  private JScrollPane ofjscp;
public static void main(String args[]){
  
PanTree pt = new PanTree();
}
public PanTree(){
  super();
  try{
    
UIManager.setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel());
  }catch
(Exception e){
    System.err.println(e);
  }
  getContentPane().setLayout(new
FlowLayout());
  setSize(800,500);
  jtree = new JTree();
  
jtree.setDragEnabled(true);
  jtree.setTransferHandler(new TreeTransferHandler());
  
jtree.setScrollsOnExpand(true);
  
jtree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
 
 jscp =  new JScrollPane(jtree);
  
  
  ofjtree = new JTree();
  
ofjtree.setDragEnabled(true);
  ofjtree.setTransferHandler(new
TreeTransferHandler());
  ofjtree.setScrollsOnExpand(true);
  
ofjtree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
 
 ofjtree.setUI(new MetalTreeUI()); // this causes NullPointerExceptions
  ofjscp =  new
JScrollPane(ofjtree);
  JTextArea textarea = new JTextArea(30,30);
  
textarea.setDragEnabled(true);

  getContentPane().add(jscp);
  
getContentPane().add(textarea);
  getContentPane().add(ofjscp);
  
addWindowListener(new WindowAdapter() {
    public void windowClosing(WindowEvent e) {
      
System.out.println("trying to exit");
      System.exit(0);
    }
  });
  pack();
  
setVisible(true);
}

  class TreeTransferHandler extends TransferHandler{
    private
DataFlavor[] plainFlavors = null;
    
    TreeTransferHandler(){
      super();
      try {
        
plainFlavors = new DataFlavor[1];
        plainFlavors[0] = new
DataFlavor("text/plain;class=java.lang.String");
      }catch (ClassNotFoundException
cle){
        System.err.println("error initializing TreeTransferable");
      }
    }
    protected
Transferable createTransferable(JComponent c) {
      if (c instanceof JTree) {
        JTree tree =
(JTree) c;
        TreePath path = tree.getSelectionPath();
        return new TreeTransferable(tree,
path);
      }
      return null;
    }

    public int getSourceActions(JComponent c) {
      return
COPY;
    }
    
    public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
      
return true;
    }
 
    class TreeTransferable implements Transferable{
      private TreePath
path;
      private JTree tree;

      TreeTransferable(JTree tree, TreePath path) {
        this.path =
path;
        this.tree = tree;
      }

      public DataFlavor[] getTransferDataFlavors() {
        return
plainFlavors;
      }

      public boolean isDataFlavorSupported(DataFlavor flavor) {
        for (int
i = 0; i < plainFlavors.length; i++) {
          if (plainFlavors[i].equals(flavor)) {
            return
true;
          }
        }
        return false;
      }

      public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException{
        String data = getPlainData();
        data = (data == null) ?
"" : data;
        if (String.class.equals(flavor.getRepresentationClass())) {
          return data;
        
}
        throw new UnsupportedFlavorException(flavor);
      }

      protected String getPlainData()
{
        TreeModel model = tree.getModel();
        Object node = path.getLastPathComponent();
        
return path.toString()+"\n";
      }
    }
  }
}
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
Do not call setUI() on JTrees when using dop!

Release Regression From : 1.4
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

(Review ID: 144125) 
======================================================================

Comments
EVALUATION Since this bug isn't fixed until Mustang, I've added a work-around for earlier releases in the work around section.
23-08-2005

WORK AROUND While it's ideal to pull this work-around once you target Mustang, this work-around isn't expected to cause any problems if you don't. The nature of this bug is that every time the UI is switched on your JTree, a drop listener is left behind by the old UI, causing conflicts with the new listener. The proper fix is for Swing to keep track of this and remove it. The work-around is simply a couple of lines that forces this to occur. Note that this is a potential problem for any JTree, JTable, JList, or JTextComponent with a TransferHandler. As such, you may want to apply the change to all such components. Here's one way to do it, by subclassing and overridding the setUI methods of all affected components: tree = new JTree() { public void setUI(TreeUI newUI) { super.setUI(newUI); TransferHandler handler = getTransferHandler(); setTransferHandler(null); setTransferHandler(handler); } }; Alternatively, you can simply call the following on any affected component after a UI switch: TransferHandler handler = component.getTransferHandler(); component.setTransferHandler(null); component.setTransferHandler(handler);
23-08-2005

EVALUATION I can reproduce this. Not a regression though, part of new DnD behavior. ###@###.### 2002-10-18 Note that I have closed 4846941 as a duplicate of this bug. That bug simply states that the problem affects multiple components. All affected components will be fixed when this bug is addressed. The problem is that in our UI classes, we fail to remove our DropTargetListeners when the UI is uninstalled. We therefore can end up with multiple DropTargetListeners. These multiple listeners conflict with each other. ###@###.### 2003-04-11 The fixes for 4468566 and 4942851 will re-architect Swing's drop support to make it much more usable by the developer. In particular, they will provide location sensitive dropping, and much better indication of the drop location. As a result of this re-architecture, the UI classes will no longer install DropTargetListeners, as all the details of indicating drop locations will be handled within TransferHandler. This eliminates the source of these exceptions. Closing as a duplicate. ###@###.### 2005-05-20 15:27:24 GMT
20-05-2005

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: dragon mustang
25-09-2004