1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.awt.Component; 25 import java.awt.Dimension; 26 import java.awt.EventQueue; 27 import java.awt.FlowLayout; 28 import java.awt.Font; 29 import java.util.Objects; 30 import java.util.concurrent.Callable; 31 32 import javax.swing.JButton; 33 import javax.swing.JCheckBox; 34 import javax.swing.JComboBox; 35 import javax.swing.JEditorPane; 36 import javax.swing.JFormattedTextField; 37 import javax.swing.JFrame; 38 import javax.swing.JLabel; 39 import javax.swing.JList; 40 import javax.swing.JMenu; 41 import javax.swing.JMenuItem; 42 import javax.swing.JRadioButton; 43 import javax.swing.JScrollPane; 44 import javax.swing.JTable; 45 import javax.swing.JTextArea; 46 import javax.swing.JTextField; 47 import javax.swing.JToolTip; 48 import javax.swing.JTree; 49 import javax.swing.SwingUtilities; 50 import javax.swing.UIManager; 51 import javax.swing.UnsupportedLookAndFeelException; 52 import javax.swing.tree.DefaultMutableTreeNode; 53 54 import static javax.swing.UIManager.getInstalledLookAndFeels; 55 56 /** 57 * @test 58 * @key headful 59 * @bug 8201552 60 * @summary Initial layout of the component should use correct graphics config. 61 * It is checked by SwingUtilities.updateComponentTreeUI(), if layout 62 * was correct the call to updateComponentTreeUI() will be no-op. 63 * @compile -encoding utf-8 StalePreferredSize.java 64 * @run main StalePreferredSize 65 * @run main/othervm -Dsun.java2d.uiScale=2.25 StalePreferredSize 66 */ 67 public final class StalePreferredSize { 68 69 static final String HTML = 70 "<html><span>A few words to get started before the " 71 + "bug</span><span>overlapping text</span></html>"; 72 73 // Some text to be tested 74 static String TEXT1 = "A quick brown fox jumps over the lazy dog"; 75 static String TEXT2 = "El veloz murciélago hindú comía feliz cardillo y " 76 + "kiwi. La cigüeña tocaba el saxofón detrás del palenque de paja"; 77 static String TEXT3 = "Voix ambiguë d’un cœur qui au zéphyr préfère les " 78 + "jattes de kiwis"; 79 static String TEXT4 = "다람쥐 헌 쳇바퀴에 타고파"; 80 static String TEXT5 = "Съешь ещё этих мягких французских булок да выпей же чаю"; 81 82 83 static JFrame frame; 84 static Component component; 85 static int typeFont = 0; // 0 - default, 1 - bold, 2 - italic 86 87 public static void main(final String[] args) throws Exception { 88 for (final UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) { 89 EventQueue.invokeAndWait(() -> setLookAndFeel(laf)); 90 for (; typeFont < 3; typeFont++) { 91 System.err.println("typeFont = " + typeFont); 92 test(HTML); 93 test(TEXT1); 94 test(TEXT2); 95 test(TEXT3); 96 test(TEXT4); 97 test(TEXT5); 98 } 99 } 100 } 101 102 private static void test(String text) throws Exception { 103 System.err.println("text = " + text); 104 // Each Callable create a component to be tested 105 Callable[] comps = { 106 () -> new JLabel(text), 107 () -> new JButton(text), 108 () -> new JMenuItem(text), 109 () -> new JMenu(text), 110 () -> new JList<>(new String[]{text}), 111 () -> new JComboBox<>(new String[]{text}), 112 () -> new JTextField(text), 113 () -> new JTextArea(text), 114 () -> new JCheckBox(text), 115 () -> new JFormattedTextField(text), 116 () -> new JRadioButton(text), 117 () -> new JTree(new DefaultMutableTreeNode(text)), 118 //TODO () -> new JSpinner(new SpinnerListModel(new String[]{HTML})), 119 () -> { 120 JToolTip tip = new JToolTip(); 121 tip.setTipText(text); 122 return tip; 123 }, 124 () -> { 125 JEditorPane pane = new JEditorPane(); 126 pane.setText(text); 127 return pane; 128 }, 129 130 () -> { 131 JTable table = new JTable(1, 1); 132 table.getModel().setValueAt(text, 0, 0); 133 return table; 134 } 135 }; 136 137 for (Callable<Component> creator : comps) { 138 checkComponent(creator); 139 } 140 } 141 142 static void checkComponent(Callable<Component> creator) throws Exception { 143 EventQueue.invokeAndWait(() -> { 144 145 try { 146 component = creator.call(); 147 } catch (Exception e) { 148 throw new RuntimeException(e); 149 } 150 151 if (typeFont == 1) { 152 component.setFont(component.getFont().deriveFont(Font.BOLD)); 153 } 154 if (typeFont == 2) { 155 component.setFont(component.getFont().deriveFont(Font.ITALIC)); 156 } 157 158 frame = new JFrame(); 159 frame.setLayout(new FlowLayout()); 160 frame.add(new JScrollPane(component)); 161 frame.setSize(300, 100); 162 frame.setLocationRelativeTo(null); 163 frame.setVisible(true); 164 }); 165 166 EventQueue.invokeAndWait(() -> { 167 168 // After the frame was shown we change nothing, so current layout 169 // should be optimal and updateComponentTreeUI() should be no-op 170 Dimension before = component.getPreferredSize(); 171 SwingUtilities.updateComponentTreeUI(frame); 172 Dimension after = component.getPreferredSize(); 173 174 frame.dispose(); 175 176 if (!Objects.equals(before, after)) { 177 System.err.println("Component: " + component); 178 System.err.println("Before: " + before); 179 System.err.println("After: " + after); 180 throw new RuntimeException("Wrong PreferredSize"); 181 } 182 }); 183 } 184 185 private static void setLookAndFeel(final UIManager.LookAndFeelInfo laf) { 186 try { 187 UIManager.setLookAndFeel(laf.getClassName()); 188 System.err.println("LookAndFeel: " + laf.getClassName()); 189 } catch (final UnsupportedLookAndFeelException ignored) { 190 System.err.println( 191 "Unsupported LookAndFeel: " + laf.getClassName()); 192 } catch (ClassNotFoundException | InstantiationException | 193 IllegalAccessException e) { 194 throw new RuntimeException(e); 195 } 196 } 197 }