# HG changeset patch # User aniyogi # Date 1453107039 -19800 # Node ID 8ac51e1179dab4795ff7a920df4c484c6ff47def # Parent 61884618e67df8d20945141df21e5249b2d8fb2b 8041894: [macosx] Test javax/swing/JSpinner/8008657/bug8008657.java failed on Mac Reviewed-by: serb, alexsch diff -r 61884618e67d -r 8ac51e1179da jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaSpinnerUI.java --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaSpinnerUI.java Thu Jan 14 18:59:11 2016 -0600 +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaSpinnerUI.java Mon Jan 18 14:20:39 2016 +0530 @@ -22,7 +22,6 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package com.apple.laf; import java.awt.*; @@ -45,33 +44,37 @@ import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor; /** - * This is originally derived from BasicSpinnerUI, but they made everything private - * so we can't subclass! + * This is originally derived from BasicSpinnerUI, but they made everything + * private so we can't subclass! */ public class AquaSpinnerUI extends SpinnerUI { + private static final RecyclableSingleton propertyChangeListener = new RecyclableSingletonFromDefaultConstructor<>(PropertyChangeHandler.class); + static PropertyChangeListener getPropertyChangeListener() { return propertyChangeListener.get(); } private static final RecyclableSingleton nextButtonHandler = new RecyclableSingleton() { - @Override - protected ArrowButtonHandler getInstance() { - return new ArrowButtonHandler("increment", true); - } - }; + @Override + protected ArrowButtonHandler getInstance() { + return new ArrowButtonHandler("increment", true); + } + }; + static ArrowButtonHandler getNextButtonHandler() { return nextButtonHandler.get(); } private static final RecyclableSingleton previousButtonHandler = new RecyclableSingleton() { - @Override - protected ArrowButtonHandler getInstance() { - return new ArrowButtonHandler("decrement", false); - } - }; + @Override + protected ArrowButtonHandler getInstance() { + return new ArrowButtonHandler("decrement", false); + } + }; + static ArrowButtonHandler getPreviousButtonHandler() { return previousButtonHandler.get(); } @@ -92,9 +95,10 @@ } boolean wasOpaque; + @Override public void installUI(final JComponent c) { - this.spinner = (JSpinner)c; + this.spinner = (JSpinner) c; installDefaults(); installListeners(); next = createNextButton(); @@ -110,8 +114,7 @@ installKeyboardActions(); // this doesn't work because JSpinner calls setOpaque(true) directly in it's constructor - // LookAndFeel.installProperty(spinner, "opaque", Boolean.FALSE); - + // LookAndFeel.installProperty(spinner, "opaque", Boolean.FALSE); // ...so we have to handle the is/was opaque ourselves wasOpaque = spinner.isOpaque(); spinner.setOpaque(false); @@ -208,6 +211,7 @@ @SuppressWarnings("serial") // Superclass is not serializable across versions class TransparentButton extends JButton implements SwingConstants { + boolean interceptRepaints = false; public TransparentButton() { @@ -219,14 +223,17 @@ } @Override - public void paint(final Graphics g) {} + public void paint(final Graphics g) { + } @Override public void repaint() { // only intercept repaints if we are after this has been initialized // otherwise we can't talk to our containing class if (interceptRepaints) { - if (spinPainter == null) return; + if (spinPainter == null) { + return; + } spinPainter.repaint(); } super.repaint(); @@ -246,7 +253,9 @@ } protected void fixupEditor(final JComponent editor) { - if (!(editor instanceof DefaultEditor)) return; + if (!(editor instanceof DefaultEditor)) { + return; + } editor.setOpaque(false); editor.setInheritsPopupMenu(true); @@ -255,7 +264,7 @@ editor.setFont(new FontUIResource(spinner.getFont())); } - final JFormattedTextField editorTextField = ((DefaultEditor)editor).getTextField(); + final JFormattedTextField editorTextField = ((DefaultEditor) editor).getTextField(); if (editorTextField.getFont() instanceof UIResource) { editorTextField.setFont(new FontUIResource(spinner.getFont())); } @@ -277,7 +286,7 @@ child.setEnabled(enabled); if (child instanceof Container) { - updateEnabledState((Container)child, enabled); + updateEnabledState((Container) child, enabled); } } } @@ -290,13 +299,13 @@ private InputMap getInputMap(final int condition) { if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) { - return (InputMap)UIManager.get("Spinner.ancestorInputMap"); + return (InputMap) UIManager.get("Spinner.ancestorInputMap"); } return null; } private ActionMap getActionMap() { - ActionMap map = (ActionMap)UIManager.get("Spinner.actionMap"); + ActionMap map = (ActionMap) UIManager.get("Spinner.actionMap"); if (map == null) { map = createActionMap(); @@ -316,6 +325,7 @@ @SuppressWarnings("serial") // Superclass is not serializable across versions private static class ArrowButtonHandler extends AbstractAction implements MouseListener { + final javax.swing.Timer autoRepeatTimer; final boolean isNext; JSpinner spinner = null; @@ -330,9 +340,9 @@ private JSpinner eventToSpinner(final AWTEvent e) { Object src = e.getSource(); while ((src instanceof Component) && !(src instanceof JSpinner)) { - src = ((Component)src).getParent(); + src = ((Component) src).getParent(); } - return (src instanceof JSpinner) ? (JSpinner)src : null; + return (src instanceof JSpinner) ? (JSpinner) src : null; } @Override @@ -342,13 +352,15 @@ spinner = eventToSpinner(e); } - if (spinner == null) return; + if (spinner == null) { + return; + } try { final int calendarField = getCalendarField(spinner); spinner.commitEdit(); if (calendarField != -1) { - ((SpinnerDateModel)spinner.getModel()).setCalendarField(calendarField); + ((SpinnerDateModel) spinner.getModel()).setCalendarField(calendarField); } final Object value = (isNext) ? spinner.getNextValue() : spinner.getPreviousValue(); if (value != null) { @@ -368,37 +380,46 @@ */ private void select(final JSpinner spinnerComponent) { final JComponent editor = spinnerComponent.getEditor(); - if (!(editor instanceof JSpinner.DateEditor)) return; + if (!(editor instanceof JSpinner.DateEditor)) { + return; + } - final JSpinner.DateEditor dateEditor = (JSpinner.DateEditor)editor; + final JSpinner.DateEditor dateEditor = (JSpinner.DateEditor) editor; final JFormattedTextField ftf = dateEditor.getTextField(); final Format format = dateEditor.getFormat(); Object value; - if (format == null || (value = spinnerComponent.getValue()) == null) return; + if (format == null || (value = spinnerComponent.getValue()) == null) { + return; + } final SpinnerDateModel model = dateEditor.getModel(); final DateFormat.Field field = DateFormat.Field.ofCalendarField(model.getCalendarField()); - if (field == null) return; + if (field == null) { + return; + } try { final AttributedCharacterIterator iterator = format.formatToCharacterIterator(value); if (!select(ftf, iterator, field) && field == DateFormat.Field.HOUR0) { select(ftf, iterator, DateFormat.Field.HOUR1); } - } catch (final IllegalArgumentException iae) {} + } catch (final IllegalArgumentException iae) { + } } /** - * Selects the passed in field, returning true if it is found, - * false otherwise. + * Selects the passed in field, returning true if it is found, false + * otherwise. */ private boolean select(final JFormattedTextField ftf, final AttributedCharacterIterator iterator, final DateFormat.Field field) { final int max = ftf.getDocument().getLength(); iterator.first(); do { - final Map attrs = iterator.getAttributes(); - if (attrs == null || !attrs.containsKey(field)) continue; + final Map attrs = iterator.getAttributes(); + if (attrs == null || !attrs.containsKey(field)) { + continue; + } final int start = iterator.getRunStart(field); final int end = iterator.getRunLimit(field); @@ -412,29 +433,35 @@ } /** - * Returns the calendarField under the start of the selection, or - * -1 if there is no valid calendar field under the selection (or - * the spinner isn't editing dates. + * Returns the calendarField under the start of the selection, or -1 if + * there is no valid calendar field under the selection (or the spinner + * isn't editing dates. */ private int getCalendarField(final JSpinner spinnerComponent) { final JComponent editor = spinnerComponent.getEditor(); - if (!(editor instanceof JSpinner.DateEditor)) return -1; + if (!(editor instanceof JSpinner.DateEditor)) { + return -1; + } - final JSpinner.DateEditor dateEditor = (JSpinner.DateEditor)editor; + final JSpinner.DateEditor dateEditor = (JSpinner.DateEditor) editor; final JFormattedTextField ftf = dateEditor.getTextField(); final int start = ftf.getSelectionStart(); final JFormattedTextField.AbstractFormatter formatter = ftf.getFormatter(); - if (!(formatter instanceof InternationalFormatter)) return -1; + if (!(formatter instanceof InternationalFormatter)) { + return -1; + } - final Format.Field[] fields = ((InternationalFormatter)formatter).getFields(start); + final Format.Field[] fields = ((InternationalFormatter) formatter).getFields(start); for (final Field element : fields) { - if (!(element instanceof DateFormat.Field)) continue; + if (!(element instanceof DateFormat.Field)) { + continue; + } int calendarField; if (element == DateFormat.Field.HOUR1) { calendarField = Calendar.HOUR; } else { - calendarField = ((DateFormat.Field)element).getCalendarField(); + calendarField = ((DateFormat.Field) element).getCalendarField(); } if (calendarField != -1) { @@ -446,7 +473,9 @@ @Override public void mousePressed(final MouseEvent e) { - if (!SwingUtilities.isLeftMouseButton(e) || !e.getComponent().isEnabled()) return; + if (!SwingUtilities.isLeftMouseButton(e) || !e.getComponent().isEnabled()) { + return; + } spinner = eventToSpinner(e); autoRepeatTimer.start(); @@ -460,26 +489,35 @@ } @Override - public void mouseClicked(final MouseEvent e) {} + public void mouseClicked(final MouseEvent e) { + } + @Override - public void mouseEntered(final MouseEvent e) {} + public void mouseEntered(final MouseEvent e) { + } + @Override - public void mouseExited(final MouseEvent e) {} + public void mouseExited(final MouseEvent e) { + } /** - * Requests focus on a child of the spinner if the spinner doesn't - * have focus. + * Requests focus on a child of the spinner if the spinner doesn't have + * focus. */ private void focusSpinnerIfNecessary() { final Component fo = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); - if (!spinner.isRequestFocusEnabled() || (fo != null && (SwingUtilities.isDescendingFrom(fo, spinner)))) return; + if (!spinner.isRequestFocusEnabled() || (fo != null && (SwingUtilities.isDescendingFrom(fo, spinner)))) { + return; + } Container root = spinner; if (!root.isFocusCycleRoot()) { root = root.getFocusCycleRootAncestor(); } - if (root == null) return; + if (root == null) { + return; + } final FocusTraversalPolicy ftp = root.getFocusTraversalPolicy(); final Component child = ftp.getComponentAfter(root, spinner); @@ -491,6 +529,7 @@ @SuppressWarnings("serial") // Superclass is not serializable across versions class SpinPainter extends JComponent { + final AquaPainter painter = AquaPainter.create(JRSUIStateFactory.getSpinnerArrows()); ButtonModel fTopModel; @@ -551,11 +590,12 @@ } /** - * A simple layout manager for the editor and the next/previous buttons. - * See the AquaSpinnerUI javadoc for more information about exactly - * how the components are arranged. + * A simple layout manager for the editor and the next/previous buttons. See + * the AquaSpinnerUI javadoc for more information about exactly how the + * components are arranged. */ static class SpinnerLayout implements LayoutManager { + private Component nextButton = null; private Component previousButton = null; private Component editor = null; @@ -656,26 +696,38 @@ } /** - * Detect JSpinner property changes we're interested in and delegate. Subclasses - * shouldn't need to replace the default propertyChangeListener (although they - * can by overriding createPropertyChangeListener) since all of the interesting - * property changes are delegated to protected methods. + * Detect JSpinner property changes we're interested in and delegate. + * Subclasses shouldn't need to replace the default propertyChangeListener + * (although they can by overriding createPropertyChangeListener) since all + * of the interesting property changes are delegated to protected methods. */ static class PropertyChangeHandler implements PropertyChangeListener { + @Override public void propertyChange(final PropertyChangeEvent e) { final String propertyName = e.getPropertyName(); - final JSpinner spinner = (JSpinner)(e.getSource()); + final JSpinner spinner = (JSpinner) (e.getSource()); final SpinnerUI spinnerUI = spinner.getUI(); if (spinnerUI instanceof AquaSpinnerUI) { - final AquaSpinnerUI ui = (AquaSpinnerUI)spinnerUI; + final AquaSpinnerUI ui = (AquaSpinnerUI) spinnerUI; if ("editor".equals(propertyName)) { - final JComponent oldEditor = (JComponent)e.getOldValue(); - final JComponent newEditor = (JComponent)e.getNewValue(); + final JComponent oldEditor = (JComponent) e.getOldValue(); + final JComponent newEditor = (JComponent) e.getNewValue(); ui.replaceEditor(oldEditor, newEditor); ui.updateEnabledState(); + } else if ("componentOrientation".equals(propertyName)) { + ComponentOrientation o + = (ComponentOrientation) e.getNewValue(); + if (o != e.getOldValue()) { + JComponent editor = spinner.getEditor(); + if (editor != null) { + editor.applyComponentOrientation(o); + } + spinner.revalidate(); + spinner.repaint(); + } } else if ("enabled".equals(propertyName)) { ui.updateEnabledState(); } else if (JComponent.TOOL_TIP_TEXT_KEY.equals(propertyName)) { @@ -683,8 +735,8 @@ } else if ("font".equals(propertyName)) { JComponent editor = spinner.getEditor(); if (editor instanceof JSpinner.DefaultEditor) { - JTextField tf = - ((JSpinner.DefaultEditor) editor).getTextField(); + JTextField tf + = ((JSpinner.DefaultEditor) editor).getTextField(); if (tf != null) { if (tf.getFont() instanceof UIResource) { tf.setFont(new FontUIResource(spinner.getFont())); @@ -703,12 +755,12 @@ final Component[] children = spinnerComponent.getComponents(); for (final Component element : children) { if (element instanceof JSpinner.DefaultEditor) { - final JTextField tf = ((JSpinner.DefaultEditor)element).getTextField(); + final JTextField tf = ((JSpinner.DefaultEditor) element).getTextField(); if (tf != null) { tf.setToolTipText(toolTipText); } } else if (element instanceof JComponent) { - ((JComponent)element).setToolTipText(toolTipText); + ((JComponent) element).setToolTipText(toolTipText); } } } diff -r 61884618e67d -r 8ac51e1179da jdk/test/javax/swing/JSpinner/8008657/bug8008657.java --- a/jdk/test/javax/swing/JSpinner/8008657/bug8008657.java Thu Jan 14 18:59:11 2016 -0600 +++ b/jdk/test/javax/swing/JSpinner/8008657/bug8008657.java Mon Jan 18 14:20:39 2016 +0530 @@ -32,6 +32,8 @@ import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; /** * @test @@ -44,18 +46,28 @@ private static Robot robot; private static JSpinner spinner; + private static JFrame frame; public static void main(String[] args) throws Exception { robot = new Robot(); + UIManager.LookAndFeelInfo[] lookAndFeelArray + = UIManager.getInstalledLookAndFeels(); + for (UIManager.LookAndFeelInfo lookAndFeelItem : lookAndFeelArray) { + executeCase(lookAndFeelItem.getClassName()); + } - SwingUtilities.invokeAndWait(() -> { + } + static void executeCase(String lookAndFeelString) throws Exception { + if (tryLookAndFeel(lookAndFeelString)) { + SwingUtilities.invokeAndWait(() -> { createDateSpinner(); createAndShowUI(); }); robot.waitForIdle(); testSpinner(false); + cleanUp(); SwingUtilities.invokeAndWait(() -> { createNumberSpinner(); @@ -64,14 +76,16 @@ robot.waitForIdle(); testSpinner(true); + cleanUp(); + } } - static void testSpinner(boolean checkHorizontalAligment) throws Exception { SwingUtilities.invokeAndWait(() -> { spinner.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); - }); + + }); robot.waitForIdle(); SwingUtilities.invokeAndWait(() -> { @@ -145,10 +159,34 @@ } static void createAndShowUI() { - JFrame frame = new JFrame("Test"); + frame = new JFrame("Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300, 100); frame.getContentPane().add(spinner); frame.setVisible(true); } + + private static void cleanUp() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame.dispose(); + } + }); + } + + private static boolean tryLookAndFeel(String lookAndFeelString) + throws Exception { + try { + UIManager.setLookAndFeel( + lookAndFeelString); + + } catch (UnsupportedLookAndFeelException + | ClassNotFoundException + | InstantiationException + | IllegalAccessException e) { + return false; + } + return true; + } }