| /* | |
| * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package com.apple.laf; | |
| import java.awt.BasicStroke; | |
| import java.awt.Color; | |
| import java.awt.Component; | |
| import java.awt.Dimension; | |
| import java.awt.Font; | |
| import java.awt.FontMetrics; | |
| import java.awt.Graphics; | |
| import java.awt.Graphics2D; | |
| import java.awt.Insets; | |
| import java.awt.Rectangle; | |
| import java.awt.RenderingHints; | |
| import java.awt.Stroke; | |
| import java.awt.event.FocusEvent; | |
| import java.awt.event.HierarchyEvent; | |
| import java.awt.event.HierarchyListener; | |
| import java.awt.event.MouseMotionListener; | |
| import java.beans.PropertyChangeEvent; | |
| import javax.swing.AbstractButton; | |
| import javax.swing.ButtonModel; | |
| import javax.swing.Icon; | |
| import javax.swing.ImageIcon; | |
| import javax.swing.JButton; | |
| import javax.swing.JCheckBox; | |
| import javax.swing.JComponent; | |
| import javax.swing.JRadioButton; | |
| import javax.swing.JRootPane; | |
| import javax.swing.JToggleButton; | |
| import javax.swing.JToolBar; | |
| import javax.swing.LookAndFeel; | |
| import javax.swing.SwingUtilities; | |
| import javax.swing.UIManager; | |
| import javax.swing.border.Border; | |
| import javax.swing.plaf.ButtonUI; | |
| import javax.swing.plaf.ComponentUI; | |
| import javax.swing.plaf.RootPaneUI; | |
| import javax.swing.plaf.UIResource; | |
| import javax.swing.plaf.basic.BasicButtonListener; | |
| import javax.swing.plaf.basic.BasicButtonUI; | |
| import javax.swing.plaf.basic.BasicGraphicsUtils; | |
| import javax.swing.plaf.basic.BasicHTML; | |
| import javax.swing.text.View; | |
| import apple.laf.JRSUIConstants.Size; | |
| import com.apple.laf.AquaButtonExtendedTypes.TypeSpecifier; | |
| import com.apple.laf.AquaUtilControlSize.Sizeable; | |
| import com.apple.laf.AquaUtils.RecyclableSingleton; | |
| import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor; | |
| import sun.swing.MnemonicHandler; | |
| import sun.swing.SwingUtilities2; | |
| public class AquaButtonUI extends BasicButtonUI implements Sizeable { | |
| private static final String BUTTON_TYPE = "JButton.buttonType"; | |
| private static final String SEGMENTED_BUTTON_POSITION = "JButton.segmentPosition"; | |
| private static final RecyclableSingleton<AquaButtonUI> buttonUI = new RecyclableSingletonFromDefaultConstructor<AquaButtonUI>(AquaButtonUI.class); | |
| public static ComponentUI createUI(final JComponent c) { | |
| return buttonUI.get(); | |
| } | |
| // Has the shared instance defaults been initialized? | |
| private boolean defaults_initialized = false; | |
| private Color defaultDisabledTextColor = null; | |
| protected void installDefaults(final AbstractButton b) { | |
| // load shared instance defaults | |
| final String pp = getPropertyPrefix(); | |
| if (!defaults_initialized) { | |
| defaultDisabledTextColor = UIManager.getColor(pp + "disabledText"); | |
| defaults_initialized = true; | |
| } | |
| setButtonMarginIfNeeded(b, UIManager.getInsets(pp + "margin")); | |
| LookAndFeel.installColorsAndFont(b, pp + "background", pp + "foreground", pp + "font"); | |
| LookAndFeel.installProperty(b, "opaque", UIManager.getBoolean(pp + "opaque")); | |
| final Object borderProp = b.getClientProperty(BUTTON_TYPE); | |
| boolean hasBorder = false; | |
| if (borderProp != null) { | |
| hasBorder = setButtonType(b, borderProp); | |
| } | |
| if (!hasBorder) setThemeBorder(b); | |
| final Object segmentProp = b.getClientProperty(SEGMENTED_BUTTON_POSITION); | |
| if (segmentProp != null) { | |
| final Border border = b.getBorder(); | |
| if (!(border instanceof AquaBorder)) return; | |
| b.setBorder(AquaButtonExtendedTypes.getBorderForPosition(b, b.getClientProperty(BUTTON_TYPE), segmentProp)); | |
| } | |
| } | |
| public void applySizeFor(final JComponent c, final Size size) { | |
| // this space intentionally left blank | |
| // (subclasses need to do work here) | |
| } | |
| protected void setThemeBorder(final AbstractButton b) { | |
| // Set the correct border | |
| final ButtonUI genericUI = b.getUI(); | |
| if (!(genericUI instanceof AquaButtonUI)) return; | |
| final AquaButtonUI ui = (AquaButtonUI)genericUI; | |
| Border border = b.getBorder(); | |
| if (!ui.isBorderFromProperty(b) && (border == null || border instanceof UIResource || border instanceof AquaButtonBorder)) { | |
| // See BasicGraphicsUtils.getPreferredButtonSize - it returns null for preferred size, | |
| // causing it to use the subcomponent's size, which doesn't allow space for Aqua pushbuttons | |
| boolean iconFont = true; | |
| if (isOnToolbar(b)) { | |
| if (b instanceof JToggleButton) { | |
| border = AquaButtonBorder.getToolBarButtonBorder(); | |
| } else { | |
| border = AquaButtonBorder.getBevelButtonBorder(); | |
| } | |
| } else if (b.getIcon() != null || b.getComponentCount() > 0) { | |
| // radar 3308129 && (b.getText() == null || b.getText().equals(""))) | |
| // we used to only do this for buttons that had images and no text | |
| // now we do it for all buttons that have any images - they cannot | |
| // be a default button. | |
| border = AquaButtonBorder.getToggleButtonBorder(); | |
| } else { | |
| border = UIManager.getBorder(getPropertyPrefix() + "border"); | |
| iconFont = false; | |
| } | |
| b.setBorder(border); | |
| final Font currentFont = b.getFont(); | |
| if (iconFont && (currentFont == null || currentFont instanceof UIResource)) { | |
| b.setFont(UIManager.getFont("IconButton.font")); | |
| } | |
| } | |
| } | |
| protected static boolean isOnToolbar(final AbstractButton b) { | |
| Component parent = b.getParent(); | |
| while (parent != null) { | |
| if (parent instanceof JToolBar) return true; | |
| parent = parent.getParent(); | |
| } | |
| return false; | |
| } | |
| // A state that affects border has changed. Make sure we have the right one | |
| protected static void updateBorder(final AbstractButton b) { | |
| // See if the button has overridden the automatic button type | |
| final Object prop = b.getClientProperty(BUTTON_TYPE); | |
| if (prop != null) return; | |
| final ButtonUI ui = b.getUI(); | |
| if (!(ui instanceof AquaButtonUI)) return; | |
| if (b.getBorder() != null) ((AquaButtonUI)ui).setThemeBorder(b); | |
| } | |
| protected void setButtonMarginIfNeeded(final AbstractButton b, final Insets insets) { | |
| final Insets margin = b.getMargin(); | |
| if (margin == null || (margin instanceof UIResource)) { | |
| b.setMargin(insets); | |
| } | |
| } | |
| public boolean isBorderFromProperty(final AbstractButton button) { | |
| return button.getClientProperty(BUTTON_TYPE) != null; | |
| } | |
| protected boolean setButtonType(final AbstractButton b, final Object prop) { | |
| if (!(prop instanceof String)) { | |
| b.putClientProperty(BUTTON_TYPE, null); // so we know to use the automatic button type | |
| return false; | |
| } | |
| final String buttonType = (String)prop; | |
| boolean iconFont = true; | |
| final TypeSpecifier specifier = AquaButtonExtendedTypes.getSpecifierByName(buttonType); | |
| if (specifier != null) { | |
| b.setBorder(specifier.getBorder()); | |
| iconFont = specifier.setIconFont; | |
| } | |
| final Font currentFont = b.getFont(); | |
| if (currentFont == null || currentFont instanceof UIResource) { | |
| b.setFont(UIManager.getFont(iconFont ? "IconButton.font" : "Button.font")); | |
| } | |
| return true; | |
| } | |
| protected void installListeners(final AbstractButton b) { | |
| super.installListeners(b); | |
| AquaButtonListener listener = getAquaButtonListener(b); | |
| if (listener != null) { | |
| // put the listener in the button's client properties so that | |
| // we can get at it later | |
| b.putClientProperty(this, listener); | |
| } | |
| installHierListener(b); | |
| AquaUtilControlSize.addSizePropertyListener(b); | |
| } | |
| protected void installKeyboardActions(final AbstractButton b) { | |
| final BasicButtonListener listener = (BasicButtonListener)b.getClientProperty(this); | |
| if (listener != null) listener.installKeyboardActions(b); | |
| } | |
| // Uninstall PLAF | |
| public void uninstallUI(final JComponent c) { | |
| uninstallKeyboardActions((AbstractButton)c); | |
| uninstallListeners((AbstractButton)c); | |
| uninstallDefaults((AbstractButton)c); | |
| //BasicHTML.updateRenderer(c, ""); | |
| } | |
| protected void uninstallKeyboardActions(final AbstractButton b) { | |
| final BasicButtonListener listener = (BasicButtonListener)b.getClientProperty(this); | |
| if (listener != null) listener.uninstallKeyboardActions(b); | |
| } | |
| protected void uninstallListeners(final AbstractButton b) { | |
| super.uninstallListeners(b); | |
| b.putClientProperty(this, null); | |
| uninstallHierListener(b); | |
| AquaUtilControlSize.removeSizePropertyListener(b); | |
| } | |
| protected void uninstallDefaults(final AbstractButton b) { | |
| LookAndFeel.uninstallBorder(b); | |
| defaults_initialized = false; | |
| } | |
| // Create Listeners | |
| protected AquaButtonListener createButtonListener(final AbstractButton b) { | |
| return new AquaButtonListener(b); | |
| } | |
| /** | |
| * Returns the AquaButtonListener for the passed in Button, or null if one | |
| * could not be found. | |
| */ | |
| private AquaButtonListener getAquaButtonListener(AbstractButton b) { | |
| MouseMotionListener[] listeners = b.getMouseMotionListeners(); | |
| if (listeners != null) { | |
| for (MouseMotionListener listener : listeners) { | |
| if (listener instanceof AquaButtonListener) { | |
| return (AquaButtonListener) listener; | |
| } | |
| } | |
| } | |
| return null; | |
| } | |
| // Paint Methods | |
| public void paint(final Graphics g, final JComponent c) { | |
| final AbstractButton b = (AbstractButton)c; | |
| final ButtonModel model = b.getModel(); | |
| final Insets i = c.getInsets(); | |
| Rectangle viewRect = new Rectangle(b.getWidth(), b.getHeight()); | |
| Rectangle iconRect = new Rectangle(); | |
| Rectangle textRect = new Rectangle(); | |
| // we are overdrawing here with translucent colors so we get | |
| // a darkening effect. How can we avoid it. Try clear rect? | |
| if (b.isOpaque()) { | |
| g.setColor(c.getBackground()); | |
| g.fillRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height); | |
| } | |
| AquaButtonBorder aquaBorder = null; | |
| if (((AbstractButton)c).isBorderPainted()) { | |
| final Border border = c.getBorder(); | |
| if (border instanceof AquaButtonBorder) { | |
| // only do this if borders are on! | |
| // this also takes care of focus painting. | |
| aquaBorder = (AquaButtonBorder)border; | |
| aquaBorder.paintButton(c, g, viewRect.x, viewRect.y, viewRect.width, viewRect.height); | |
| } | |
| } else { | |
| if (b.isOpaque()) { | |
| viewRect.x = i.left - 2; | |
| viewRect.y = i.top - 2; | |
| viewRect.width = b.getWidth() - (i.right + viewRect.x) + 4; | |
| viewRect.height = b.getHeight() - (i.bottom + viewRect.y) + 4; | |
| if (b.isContentAreaFilled() || model.isSelected()) { | |
| if (model.isSelected()) // Toggle buttons | |
| g.setColor(c.getBackground().darker()); | |
| else g.setColor(c.getBackground()); | |
| g.fillRect(viewRect.x, viewRect.y, viewRect.width, viewRect.height); | |
| } | |
| } | |
| // needs focus to be painted | |
| // for now we don't know exactly what to do...we'll see! | |
| if (b.isFocusPainted() && b.hasFocus()) { | |
| // paint UI specific focus | |
| paintFocus(g, b, viewRect, textRect, iconRect); | |
| } | |
| } | |
| // performs icon and text rect calculations | |
| final String text = layoutAndGetText(g, b, aquaBorder, i, viewRect, iconRect, textRect); | |
| // Paint the Icon | |
| if (b.getIcon() != null) { | |
| paintIcon(g, b, iconRect); | |
| } | |
| if (textRect.width == 0) { | |
| textRect.width = 50; | |
| } | |
| if (text != null && !text.isEmpty()) { | |
| final View v = (View)c.getClientProperty(BasicHTML.propertyKey); | |
| if (v != null) { | |
| v.paint(g, textRect); | |
| } else { | |
| paintText(g, b, textRect, text); | |
| } | |
| } | |
| } | |
| protected void paintFocus(Graphics g, AbstractButton b, | |
| Rectangle viewRect, Rectangle textRect, Rectangle iconRect) { | |
| Graphics2D g2d = null; | |
| Stroke oldStroke = null; | |
| Object oldAntialiasingHint = null; | |
| Color oldColor = g.getColor(); | |
| if (g instanceof Graphics2D) { | |
| g2d = (Graphics2D)g; | |
| oldStroke = g2d.getStroke(); | |
| oldAntialiasingHint = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING); | |
| g2d.setStroke(new BasicStroke(3)); | |
| g2d.setRenderingHint( | |
| RenderingHints.KEY_ANTIALIASING, | |
| RenderingHints.VALUE_ANTIALIAS_ON); | |
| } | |
| Color ringColor = UIManager.getColor("Focus.color"); | |
| g.setColor(ringColor); | |
| g.drawRoundRect(5, 3, b.getWidth() - 10, b.getHeight() - 7, 15, 15); | |
| if (g2d != null) { | |
| // Restore old state of Java2D renderer | |
| g2d.setStroke(oldStroke); | |
| g2d.setRenderingHint( | |
| RenderingHints.KEY_ANTIALIASING, | |
| oldAntialiasingHint); | |
| } | |
| g.setColor(oldColor); | |
| } | |
| protected String layoutAndGetText(final Graphics g, final AbstractButton b, final AquaButtonBorder aquaBorder, final Insets i, Rectangle viewRect, Rectangle iconRect, Rectangle textRect) { | |
| // re-initialize the view rect to the selected insets | |
| viewRect.x = i.left; | |
| viewRect.y = i.top; | |
| viewRect.width = b.getWidth() - (i.right + viewRect.x); | |
| viewRect.height = b.getHeight() - (i.bottom + viewRect.y); | |
| // reset the text and icon rects | |
| textRect.x = textRect.y = textRect.width = textRect.height = 0; | |
| iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0; | |
| // setup the font | |
| g.setFont(b.getFont()); | |
| final FontMetrics fm = g.getFontMetrics(); | |
| // layout the text and icon | |
| final String originalText = b.getText(); | |
| final String text = SwingUtilities.layoutCompoundLabel(b, fm, originalText, b.getIcon(), b.getVerticalAlignment(), b.getHorizontalAlignment(), b.getVerticalTextPosition(), b.getHorizontalTextPosition(), viewRect, iconRect, textRect, originalText == null ? 0 : b.getIconTextGap()); | |
| if (text == originalText || aquaBorder == null) return text; // everything fits | |
| // if the text didn't fit - check if the aqua border has alternate Insets that are more adhering | |
| final Insets alternateContentInsets = aquaBorder.getContentInsets(b, b.getWidth(), b.getHeight()); | |
| if (alternateContentInsets != null) { | |
| // recursively call and don't pass AquaBorder | |
| return layoutAndGetText(g, b, null, alternateContentInsets, viewRect, iconRect, textRect); | |
| } | |
| // there is no Aqua border, go with what we've got | |
| return text; | |
| } | |
| protected void paintIcon(final Graphics g, final AbstractButton b, final Rectangle localIconRect) { | |
| final ButtonModel model = b.getModel(); | |
| Icon icon = b.getIcon(); | |
| Icon tmpIcon = null; | |
| if (icon == null) return; | |
| Icon selectedIcon = null; | |
| // the fallback icon should be based on the selected state | |
| if (model.isSelected()) { | |
| selectedIcon = b.getSelectedIcon(); | |
| if (selectedIcon != null) { | |
| icon = selectedIcon; | |
| } | |
| } | |
| if (!model.isEnabled()) { | |
| if (model.isSelected()) { | |
| tmpIcon = b.getDisabledSelectedIcon(); | |
| if (tmpIcon == null) { | |
| tmpIcon = selectedIcon; | |
| } | |
| } | |
| if (tmpIcon == null) { | |
| tmpIcon = b.getDisabledIcon(); | |
| } | |
| } else if (model.isPressed() && model.isArmed()) { | |
| tmpIcon = b.getPressedIcon(); | |
| if (tmpIcon == null) { | |
| if (icon instanceof ImageIcon) { | |
| tmpIcon = new ImageIcon(AquaUtils.generateSelectedDarkImage(((ImageIcon)icon).getImage())); | |
| } | |
| } | |
| } else if (b.isRolloverEnabled() && model.isRollover()) { | |
| if (model.isSelected()) { | |
| tmpIcon = b.getRolloverSelectedIcon(); | |
| if (tmpIcon == null) { | |
| tmpIcon = selectedIcon; | |
| } | |
| } | |
| if (tmpIcon == null) { | |
| tmpIcon = b.getRolloverIcon(); | |
| } | |
| } else if (model.isSelected()) { | |
| tmpIcon = b.getSelectedIcon(); | |
| } | |
| if (model.isEnabled() && b.isFocusOwner() && b.getBorder() instanceof AquaButtonBorder.Toolbar) { | |
| if (tmpIcon == null) tmpIcon = icon; | |
| if (tmpIcon instanceof ImageIcon) { | |
| tmpIcon = AquaFocus.createFocusedIcon(tmpIcon, b, 3); | |
| tmpIcon.paintIcon(b, g, localIconRect.x - 3, localIconRect.y - 3); | |
| return; | |
| } | |
| } | |
| if (tmpIcon != null) { | |
| icon = tmpIcon; | |
| } | |
| icon.paintIcon(b, g, localIconRect.x, localIconRect.y); | |
| } | |
| /** | |
| * As of Java 2 platform v 1.4 this method should not be used or overridden. | |
| * Use the paintText method which takes the AbstractButton argument. | |
| */ | |
| protected void paintText(final Graphics g, final JComponent c, final Rectangle localTextRect, final String text) { | |
| final AbstractButton b = (AbstractButton)c; | |
| final ButtonModel model = b.getModel(); | |
| final FontMetrics fm = g.getFontMetrics(); | |
| final int mnemonicIndex = MnemonicHandler.isMnemonicHidden() ? -1 : b.getDisplayedMnemonicIndex(); | |
| /* Draw the Text */ | |
| if (model.isEnabled()) { | |
| /*** paint the text normally */ | |
| g.setColor(b.getForeground()); | |
| } else { | |
| /*** paint the text disabled ***/ | |
| g.setColor(defaultDisabledTextColor); | |
| } | |
| SwingUtilities2.drawStringUnderlineCharAt(c, g, text, mnemonicIndex, localTextRect.x, localTextRect.y + fm.getAscent()); | |
| } | |
| protected void paintText(final Graphics g, final AbstractButton b, final Rectangle localTextRect, final String text) { | |
| paintText(g, (JComponent)b, localTextRect, text); | |
| } | |
| protected void paintButtonPressed(final Graphics g, final AbstractButton b) { | |
| paint(g, b); | |
| } | |
| // Layout Methods | |
| public Dimension getMinimumSize(final JComponent c) { | |
| final Dimension d = getPreferredSize(c); | |
| final View v = (View)c.getClientProperty(BasicHTML.propertyKey); | |
| if (v != null) { | |
| d.width -= v.getPreferredSpan(View.X_AXIS) - v.getMinimumSpan(View.X_AXIS); | |
| } | |
| return d; | |
| } | |
| public Dimension getPreferredSize(final JComponent c) { | |
| final AbstractButton b = (AbstractButton)c; | |
| // fix for Radar #3134273 | |
| final Dimension d = BasicGraphicsUtils.getPreferredButtonSize(b, b.getIconTextGap()); | |
| if (d == null) return null; | |
| final Border border = b.getBorder(); | |
| if (border instanceof AquaButtonBorder) { | |
| ((AquaButtonBorder)border).alterPreferredSize(d); | |
| } | |
| return d; | |
| } | |
| public Dimension getMaximumSize(final JComponent c) { | |
| final Dimension d = getPreferredSize(c); | |
| final View v = (View)c.getClientProperty(BasicHTML.propertyKey); | |
| if (v != null) { | |
| d.width += v.getMaximumSpan(View.X_AXIS) - v.getPreferredSpan(View.X_AXIS); | |
| } | |
| return d; | |
| } | |
| private static final RecyclableSingleton<AquaHierarchyButtonListener> fHierListener = new RecyclableSingletonFromDefaultConstructor<AquaHierarchyButtonListener>(AquaHierarchyButtonListener.class); | |
| static AquaHierarchyButtonListener getAquaHierarchyButtonListener() { | |
| return fHierListener.get(); | |
| } | |
| // We need to know when ordinary JButtons are put on JToolbars, but not JComboBoxButtons | |
| // JToggleButtons always have the same border | |
| private boolean shouldInstallHierListener(final AbstractButton b) { | |
| return (b instanceof JButton || b instanceof JToggleButton && !(b instanceof AquaComboBoxButton) && !(b instanceof JCheckBox) && !(b instanceof JRadioButton)); | |
| } | |
| protected void installHierListener(final AbstractButton b) { | |
| if (shouldInstallHierListener(b)) { | |
| // super put the listener in the button's client properties | |
| b.addHierarchyListener(getAquaHierarchyButtonListener()); | |
| } | |
| } | |
| protected void uninstallHierListener(final AbstractButton b) { | |
| if (shouldInstallHierListener(b)) { | |
| b.removeHierarchyListener(getAquaHierarchyButtonListener()); | |
| } | |
| } | |
| static class AquaHierarchyButtonListener implements HierarchyListener { | |
| // Every time a hierarchy is changed we need to check if the button is moved on or from | |
| // the toolbar. If that is the case, we need to re-set the border of the button. | |
| public void hierarchyChanged(final HierarchyEvent e) { | |
| if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) == 0) return; | |
| final Object o = e.getSource(); | |
| if (!(o instanceof AbstractButton)) return; | |
| final AbstractButton b = (AbstractButton)o; | |
| final ButtonUI ui = b.getUI(); | |
| if (!(ui instanceof AquaButtonUI)) return; | |
| if (!(b.getBorder() instanceof UIResource)) return; // if the border is not one of ours, or null | |
| ((AquaButtonUI)ui).setThemeBorder(b); | |
| } | |
| } | |
| class AquaButtonListener extends BasicButtonListener { | |
| protected final AbstractButton b; | |
| public AquaButtonListener(final AbstractButton b) { | |
| super(b); | |
| this.b = b; | |
| } | |
| public void focusGained(final FocusEvent e) { | |
| ((Component)e.getSource()).repaint(); | |
| } | |
| public void focusLost(final FocusEvent e) { | |
| // 10-06-03 VL: [Radar 3187049] | |
| // If focusLost arrives while the button has been left-clicked this would disarm the button, | |
| // causing actionPerformed not to fire on mouse release! | |
| //b.getModel().setArmed(false); | |
| b.getModel().setPressed(false); | |
| ((Component)e.getSource()).repaint(); | |
| } | |
| public void propertyChange(final PropertyChangeEvent e) { | |
| super.propertyChange(e); | |
| final String propertyName = e.getPropertyName(); | |
| // Repaint the button, since its border needs to handle the new state. | |
| if (AquaFocusHandler.FRAME_ACTIVE_PROPERTY.equals(propertyName)) { | |
| b.repaint(); | |
| return; | |
| } | |
| if ("icon".equals(propertyName) || "text".equals(propertyName)) { | |
| setThemeBorder(b); | |
| return; | |
| } | |
| if (BUTTON_TYPE.equals(propertyName)) { | |
| // Forced border types | |
| final String value = (String)e.getNewValue(); | |
| final Border border = AquaButtonExtendedTypes.getBorderForPosition(b, value, b.getClientProperty(SEGMENTED_BUTTON_POSITION)); | |
| if (border != null) { | |
| b.setBorder(border); | |
| } | |
| return; | |
| } | |
| if (SEGMENTED_BUTTON_POSITION.equals(propertyName)) { | |
| final Border border = b.getBorder(); | |
| if (!(border instanceof AquaBorder)) return; | |
| b.setBorder(AquaButtonExtendedTypes.getBorderForPosition(b, b.getClientProperty(BUTTON_TYPE), e.getNewValue())); | |
| } | |
| if ("componentOrientation".equals(propertyName)) { | |
| final Border border = b.getBorder(); | |
| if (!(border instanceof AquaBorder)) return; | |
| Object buttonType = b.getClientProperty(BUTTON_TYPE); | |
| Object buttonPosition = b.getClientProperty(SEGMENTED_BUTTON_POSITION); | |
| if (buttonType != null && buttonPosition != null) { | |
| b.setBorder(AquaButtonExtendedTypes.getBorderForPosition(b, buttonType, buttonPosition)); | |
| } | |
| } | |
| } | |
| } | |
| } |