Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6647024

AbstractLayoutCache.isExpanded(TreePath) is both implemented incorrectly




      J2SE Version (please include all output from java -version flag):
      java version "1.6.0_03"
      Java(TM) SE Runtime Environment (build 1.6.0_03-b05)
      Java HotSpot(TM) Client VM (build 1.6.0_03-b05, mixed mode, sharing)

      Does this problem occur on J2SE 5.0.x or 6.0? Yes / No (pick one)

      Operating System Configuration Information (be specific):
      Microsoft Windows XP [Version 5.1.2600]

      Bug Description:
      AbstractLayoutCache.isExpanded(TreePath) is both implemented incorrectly and called when it should not be

      The JavaDoc states that AbstractLayoutCache.isExpanded(TreePath) Returns true if the value identified by row is currently expanded.
      There is another method AbstractLayoutCache.getExpandedState(TreePath) which Returns true if the path is expanded, and visible.

      1) Both Implementations (FixedHeightLayoutCache and VariableHeightLayoutCache) incorrectly implement
         AbstractLayoutCache.isExpanded(TreePath) to do the same as AbstractLayoutCache.getExpandedState(TreePath).
         The problem appears to be that they are calling getNodeForPath(path, true, false) instead of
         getNodeForPath(path, false, false), and so are ending up returning false even if the value identified
         by row is currently expanded.

      2) BasicTreeUI.Handler.treeNodesChanged(TreeModelEvent) is calling treeState.isExpanded(parentPath) instead of
         treeState.getExpandedState(parentPath). It then incorrectly assumes that 'Changed nodes are visible'
         (copied from the developers comments).

      As a result of these everything calling these is also getting incorrect results and there can also be NullPointerExceptions:

      Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
              at javax.swing.plaf.basic.BasicTreeUI$Handler.treeNodesChanged(BasicTreeUI.java:3771)
              at javax.swing.tree.DefaultTreeModel.fireTreeNodesChanged(DefaultTreeModel.java:468)
              at javax.swing.tree.DefaultTreeModel.nodesChanged(DefaultTreeModel.java:330)
              at javax.swing.tree.DefaultTreeModel.nodeChanged(DefaultTreeModel.java:261)
              at Test$1.run(Test.java:32)
              at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
              at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
              at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:273)
              at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:183)
              at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:173)
              at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:168)
              at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:160)
              at java.awt.EventDispatchThread.run(EventDispatchThread.java:121)

      Here is some sample code where I have made VariableHeightLayoutCache isExpanded(TreePath) use
      getNodeForPath(path, false, false) instead of getNodeForPath(path, true, false). Now
      VariableHeightLayoutCache.isExpanded(TreePath) will correctly return true when
      the TreePath is expanded and BasicTreeUI.Handler.treeNodesChanged(TreeModelEvent) will
      throw the NullPointerException as shown above.

      import static javax.swing.JFrame.*;
      import java.awt.*;
      import java.util.*;
      import javax.swing.*;
      import javax.swing.plaf.metal.*;
      import javax.swing.event.*;
      import javax.swing.tree.*;

      public class Test {
        public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
            public void run() {
              JFrame frame = new JFrame();
              JTree tree = new JTree() {
                public void updateUI() {
                  setUI(new MetalTreeUI() {
                    protected AbstractLayoutCache createLayoutCache() {
                      return new AdaptedVariableHeightLayoutCache();
              frame.add(new JScrollPane(tree));
              frame.setSize(500, 500);
              TreePath path0 = tree.getPathForRow(0);
              TreePath path1 = tree.getPathForRow(1);
              TreePath path2 = tree.getPathForRow(2);




            Unassigned Unassigned
            tyao Ting-Yun Ingrid Yao (Inactive)
            0 Vote for this issue
            1 Start watching this issue