JDK-6907705 : fixing - #6852592: "invalidate() must be smarter" revealed problem with JTree
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 7
  • Priority: P2
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2009-12-05
  • Updated: 2012-03-22
  • Resolved: 2011-05-04
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.
JDK 7
7Resolved
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
Please see evaluation for minimized testcase.

----------------------------------------------------------
Testcase api/javax_swing/JTree/index.html#misc[JTree0009]
Platform: ALL
FAILS: JDK7b77
PASSES: JDK7b76

Message is the following:
JTree0009: Failed. Expected value: 423 Returned value: 403

Comments
EVALUATION The hierarchy of components in that test is as follows: javax.swing.JFrame javax.swing.JRootPane javax.swing.JPanel javax.swing.JLayeredPane javax.swing.JPanel (content pane) javax.swing.JScrollPane javax.swing.JViewport javax.swing.JTree javax.swing.CellRendererPane javax.swing.JScrollPane$ScrollBar javax.swing.plaf.metal.MetalScrollButton javax.swing.plaf.metal.MetalScrollButton javax.swing.JScrollPane$ScrollBar javax.swing.plaf.metal.MetalScrollButton javax.swing.plaf.metal.MetalScrollButton Note that the JScrollPane is a validate root. When the test code changes a property of the JTree (e.g. jTree[0].setVisibleRowCount(1);), the invalidation goes through the hierarchy up to the JScrollPane. The content pane is left valid. A subsequent call to jTree[0].revalidate(); validates the invalidated components as expected. Note that the test expects that changing the visible row count of the tree must not only change the JTree's size, but also the JScrollPane's size as well. But since the JScrollPane declares itself as a validate root, the content pane in which it resides doesn't know that the scroll pane must be re-layouted. Therfore we observe the effect. If I replace the call of revalidate() on the tree with the following line: ((JComponent)jFrame[0].getContentPane()).revalidate(); everythings starts working correctly. Indeed, in this case we explicitly tell the content pane that its internal layout must be updated (which indeed must be done). I'm not an expert in Swing, however, off the top of my head a solution for this problem could be for the JTree to automatically call the revalidate() method interanlly. And do it in a special way: if the tree resides in a viewport of a jscrollpane, then it's the parent of the JScrollPane that actually must be revalidated. On the other hand, if Swing specification doesn't imply that the scrollpane's size must update automatically upon changes to the layout properties of the JTree in this test case, then this may be an issue in the test itself. In that case, the test code should override the JScrollPane.isValidateRoot() method and return 'false'. This should also fix the problem.
11-04-2011

EVALUATION Fix suggested by ###@###.### doesn't work: replace frame.validate(); with tree.revalidate(); The problem might be in Swing
05-04-2011

EVALUATION Though fixing #6852592 might only expose existing problems in Swing this issue formally is a regression.
05-04-2011

SUGGESTED FIX -
04-04-2011

EVALUATION The essence of the test is: - setting jtree.setVisibleRowCount() - doing jtree.revalidate() (before JDK7b77 it has to be jframe.validate() ) - comparing height of the scrollPane containing jtree with the height calculated manually Testcase could be minimized to the following. Please use JDK7 b77+ import javax.swing.*; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeModel; import java.awt.*; import java.lang.reflect.InvocationTargetException; /** * */ public class JTree0009 { public static void main(String[] args) throws InvocationTargetException, InterruptedException { final JFrame[] jFrame = new JFrame[1]; final JTree[] jTree = new JTree[1]; final JScrollPane[] scrollPane = new JScrollPane[1]; SwingUtilities.invokeAndWait(new Runnable() { public void run() { jFrame[0] = new JFrame("public void setVisibleRowCount(int rowCount)"); jTree[0] = createTree(); jTree[0].setRowHeight(20); scrollPane[0] = new JScrollPane(jTree[0]); scrollPane[0].setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); jFrame[0].getContentPane().setLayout(new FlowLayout()); jFrame[0].getContentPane().add(scrollPane[0]); jFrame[0].setSize(300, 300); jFrame[0].setVisible(true); } }); Thread.sleep(2000); SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { jTree[0].expandRow(0); jTree[0].setVisibleRowCount(1); // the following doesn't work jTree[0].revalidate(); } }); final int initialSize = scrollPane[0].getSize().height; for (int i = 2; i < 10; i++) { final int finalI = i; SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { jTree[0].setVisibleRowCount(finalI); // the following doesn't work jTree[0].revalidate(); } }); Thread.sleep(1000); SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { int scrollPaneHeight = scrollPane[0].getSize().height; int calculatedTreeHeight = initialSize + jTree[0].getRowHeight() * (finalI - 1); boolean b = scrollPaneHeight == calculatedTreeHeight; if (!b) { System.out.println( "Expected value: " + calculatedTreeHeight + ", " + "Returned value: " + scrollPaneHeight); } else { System.out.println("OK"); } } }); } Thread.sleep(2000); SwingUtilities.invokeAndWait(new Runnable() { public void run() { jFrame[0].dispose(); } }); } public static JTree createTree() { DefaultMutableTreeNode root = new DefaultMutableTreeNode("000000000", true); TreeModel treeModel = new DefaultTreeModel(root); JTree tree = new JTree(treeModel); tree.setRowHeight(20); for (int i = 1; i < 10; i++) { root.add(new DefaultMutableTreeNode(new Integer(i))); } return tree; } }
02-04-2011