/* * @(#)VsnetMenuUI.java * * Copyright 2002 JIDE Software Inc. All rights reserved. */ package com.jidesoft.plaf.basic; import com.jidesoft.icons.IconsFactory; import com.jidesoft.plaf.UIDefaultsLookup; import com.jidesoft.plaf.vsnet.VsnetMenuUI; import com.jidesoft.swing.*; import com.jidesoft.utils.SecurityUtils; import com.sun.java.swing.plaf.windows.WindowsLookAndFeel; import javax.swing.*; import javax.swing.event.MouseInputListener; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicHTML; import javax.swing.text.View; import java.awt.*; import java.awt.event.*; import java.awt.geom.Rectangle2D; import java.util.ArrayList; /** * SplitButtonUI implementation */ public class BasicJideSplitButtonUI extends VsnetMenuUI { protected ThemePainter _painter; protected Color _shadowColor; protected Color _darkShadowColor; protected Color _highlight; protected Color _lightHighlightColor; protected int _splitButtonMargin = 12; protected int _splitButtonMarginOnMenu = 20; protected boolean _isFloatingIcon = false; private FocusListener _focusListener; private static final String propertyPrefix = "JideSplitButton"; @SuppressWarnings({"UnusedDeclaration"}) public static ComponentUI createUI(JComponent x) { return new BasicJideSplitButtonUI(); } @Override protected String getPropertyPrefix() { return propertyPrefix; } @Override protected void installDefaults() { _painter = (ThemePainter) UIDefaultsLookup.get("Theme.painter"); _isFloatingIcon = UIDefaultsLookup.getBoolean("Icon.floating"); _shadowColor = UIDefaultsLookup.getColor("JideButton.shadow"); _darkShadowColor = UIDefaultsLookup.getColor("JideButton.darkShadow"); _highlight = UIDefaultsLookup.getColor("JideButton.highlight"); _lightHighlightColor = UIDefaultsLookup.getColor("JideButton.light"); menuItem.setRolloverEnabled(true); super.installDefaults(); } @Override protected void uninstallDefaults() { _painter = null; _shadowColor = null; _highlight = null; _lightHighlightColor = null; _darkShadowColor = null; super.uninstallDefaults(); } @Override protected void installListeners() { super.installListeners(); if (_focusListener == null) { _focusListener = new FocusListener() { public void focusGained(FocusEvent e) { menuItem.repaint(); } public void focusLost(FocusEvent e) { menuItem.repaint(); } }; } menuItem.addFocusListener(_focusListener); } @Override protected void uninstallListeners() { super.uninstallListeners(); if (_focusListener != null) { menuItem.removeFocusListener(_focusListener); } } /** * Returns the ui that is of type <code>clazz</code>, or null if one can not be found. * * @param ui the ui * @param clazz the class * @return the actual ui for the class. */ static Object getUIOfType(ComponentUI ui, Class clazz) { if (clazz.isInstance(ui)) { return ui; } return null; } /** * Returns the InputMap for condition <code>condition</code>. Called as part of * <code>installKeyboardActions</code>. * * @param condition the condition * @param c the component * @return the input map. */ public InputMap getInputMap(int condition, JComponent c) { if (condition == JComponent.WHEN_FOCUSED) { BasicJideSplitButtonUI ui = (BasicJideSplitButtonUI) getUIOfType( ((JideSplitButton) c).getUI(), BasicJideSplitButtonUI.class); if (ui != null) { return (InputMap) UIDefaultsLookup.get(ui.getPropertyPrefix() + ".focusInputMap"); } } return null; } @Override protected void installKeyboardActions() { super.installKeyboardActions(); AbstractButton b = menuItem; LazyActionMap.installLazyActionMap(b, BasicJideSplitButtonUI.class, "JideSplitButton.actionMap"); InputMap km = getInputMap(JComponent.WHEN_FOCUSED, b); SwingUtilities.replaceUIInputMap(b, JComponent.WHEN_FOCUSED, km); } @Override protected void uninstallKeyboardActions() { AbstractButton b = menuItem; SwingUtilities.replaceUIInputMap(b, JComponent. WHEN_IN_FOCUSED_WINDOW, null); SwingUtilities.replaceUIInputMap(b, JComponent.WHEN_FOCUSED, null); SwingUtilities.replaceUIActionMap(b, null); super.uninstallKeyboardActions(); } @Override protected MouseInputListener createMouseInputListener(JComponent c) { return new MouseInputHandler(); } @Override protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) { ButtonModel model = menuItem.getModel(); int menuWidth; int menuHeight; int orientation = JideSwingUtilities.getOrientationOf(menuItem); if (orientation == SwingConstants.HORIZONTAL) { menuWidth = menuItem.getWidth(); menuHeight = menuItem.getHeight(); } else { menuWidth = menuItem.getHeight(); menuHeight = menuItem.getWidth(); } // have to change to HORIZONTAL because we rotate the Graphics already orientation = SwingConstants.HORIZONTAL; boolean paintBackground; Object o = menuItem.getClientProperty("JideSplitButton.alwaysPaintBackground"); if (o instanceof Boolean) { paintBackground = (Boolean) o; } else { paintBackground = menuItem.isOpaque(); } if (!((JMenu) menuItem).isTopLevelMenu()) { super.paintBackground(g, menuItem, bgColor); if (menuItem.isEnabled()) { if (model.isArmed() || model.isPressed() || isMouseOver()) { g.setColor(selectionForeground); g.drawLine(menuWidth - _splitButtonMarginOnMenu, 0, menuWidth - _splitButtonMarginOnMenu, menuHeight - 2); JideSwingUtilities.paintArrow(g, selectionForeground, menuWidth - _splitButtonMarginOnMenu / 2 - 2, menuHeight / 2 - 3, 7, SwingConstants.VERTICAL); } else { g.setColor(getForegroundOfState(menuItem)); g.drawLine(menuWidth - _splitButtonMarginOnMenu, 0, menuWidth - _splitButtonMarginOnMenu, menuHeight - 2); JideSwingUtilities.paintArrow(g, getForegroundOfState(menuItem), menuWidth - _splitButtonMarginOnMenu / 2 - 2, menuHeight / 2 - 3, 7, SwingConstants.VERTICAL); } } else { g.setColor(UIDefaultsLookup.getColor("controlDkShadow")); g.drawLine(menuWidth - _splitButtonMarginOnMenu, 0, menuWidth - _splitButtonMarginOnMenu, menuHeight - 2); JideSwingUtilities.paintArrow(g, UIDefaultsLookup.getColor("controlDkShadow"), menuWidth - _splitButtonMarginOnMenu / 2 - 2, menuHeight / 2 - 3, 7, SwingConstants.VERTICAL); } return; } if (paintBackground) { if (menuItem.getParent() != null) { g.setColor(menuItem.getParent().getBackground()); } else { g.setColor(menuItem.getBackground()); } g.fillRect(0, 0, menuWidth, menuHeight); } JideSplitButton b = (JideSplitButton) menuItem; if (b.getButtonStyle() == ButtonStyle.TOOLBAR_STYLE) { if ((model.isSelected())) { if (isAlwaysDropdown(b)) { Rectangle rect = new Rectangle(0, 0, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_SELECTED); } else if (b.getClientProperty(JideButton.CLIENT_PROPERTY_SEGMENT_POSITION) != null) { Rectangle rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_ROLLOVER); } else if (paintBackground) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_DISABLE_ROLLOVER); } rect = getDropDownRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_PRESSED); } else { Rectangle rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_SELECTED); } else if (paintBackground) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_DISABLE_SELECTED); } rect = getDropDownRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_SELECTED); getPainter().paintSelectedMenu(b, g, new Rectangle(0, 0, menuWidth, menuHeight), orientation, ThemePainter.STATE_SELECTED); } } else if (model.isArmed() || model.isPressed()) { Rectangle rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_PRESSED); } else if (paintBackground) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_DISABLE); } rect = getDropDownRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_ROLLOVER); } else if (model instanceof SplitButtonModel && ((DefaultSplitButtonModel) model).isButtonSelected()) { if ((isMouseOver() || b.hasFocus()) && model.isEnabled()) { Rectangle rect = getDropDownRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_ROLLOVER); rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_PRESSED); } else if (paintBackground) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_DISABLE); } } else { Rectangle rect = getDropDownRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_DEFAULT); rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_SELECTED); } else if (paintBackground) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_DISABLE_SELECTED); } } } else if (((b.isRolloverEnabled() && isMouseOver()) || b.hasFocus()) && model.isEnabled()) { if (isAlwaysDropdown(b)) { Rectangle rect = new Rectangle(0, 0, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_ROLLOVER); } else { // Draw a line border with background Rectangle rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_ROLLOVER); } else if (paintBackground) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_DISABLE_ROLLOVER); } rect = getDropDownRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_ROLLOVER); } } else { if (paintBackground) { Rectangle rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isEnabled() && b.isButtonEnabled()) { getPainter().paintButtonBackground(b, g, rect, 0, ThemePainter.STATE_DEFAULT); } else { getPainter().paintButtonBackground(b, g, rect, 0, ThemePainter.STATE_DISABLE); } if ("true".equals(SecurityUtils.getProperty("shadingtheme", "false"))) { JideSwingUtilities.fillGradient(g, rect, SwingConstants.HORIZONTAL); } rect = getDropDownRect(b, orientation, menuWidth, menuHeight); if (b.isEnabled()) { getPainter().paintButtonBackground(b, g, rect, 0, ThemePainter.STATE_DEFAULT); } else { getPainter().paintButtonBackground(b, g, rect, 0, ThemePainter.STATE_DISABLE); } if ("true".equals(SecurityUtils.getProperty("shadingtheme", "false"))) { JideSwingUtilities.fillGradient(g, rect, SwingConstants.HORIZONTAL); } } } } else if (b.getButtonStyle() == ButtonStyle.FLAT_STYLE) { if ((model.isSelected())) { // Draw a dark shadow border without bottom getPainter().paintSelectedMenu(b, g, new Rectangle(0, 0, menuWidth, menuHeight), orientation, ThemePainter.STATE_SELECTED); } else if (model.isArmed() || model.isPressed()) { Rectangle rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { JideSwingUtilities.paintBackground(g, rect, _highlight, _highlight); } rect = getDropDownRect(b, orientation, menuWidth, menuHeight); JideSwingUtilities.paintBackground(g, rect, _highlight, _highlight); if (!b.isOpaque()) { rect = getButtonRect(b, orientation, menuWidth, menuHeight); paintSunkenBorder(g, rect); rect = getDropDownRect(b, orientation, menuWidth, menuHeight); paintRaisedBorder(g, rect); } } else if (model instanceof SplitButtonModel && ((DefaultSplitButtonModel) model).isButtonSelected()) { if ((isMouseOver() || b.hasFocus()) && model.isEnabled()) { Rectangle rect = getDropDownRect(b, orientation, menuWidth, menuHeight); JideSwingUtilities.paintBackground(g, rect, _highlight, _highlight); rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { JideSwingUtilities.paintBackground(g, rect, _highlight, _highlight); } if (!b.isOpaque()) { rect = getButtonRect(b, orientation, menuWidth, menuHeight); paintSunkenBorder(g, rect); rect = getDropDownRect(b, orientation, menuWidth, menuHeight); paintRaisedBorder(g, rect); } } else { Rectangle rect; if (b.isOpaque()) { rect = getDropDownRect(b, orientation, menuWidth, menuHeight); JideSwingUtilities.paintBackground(g, rect, _highlight, _highlight); } rect = getButtonRect(b, orientation, menuWidth, menuHeight); JideSwingUtilities.paintBackground(g, rect, _highlight, _highlight); if (!b.isOpaque()) { rect = getButtonRect(b, orientation, menuWidth, menuHeight); paintSunkenBorder(g, rect); // rect = new Rectangle(menuWidth - _splitButtonMargin + getOffset(), 0, _splitButtonMargin - getOffset(), menuHeight); // paintRaisedBorder(g, rect); } } } else { if (((b.isRolloverEnabled() && isMouseOver()) || b.hasFocus()) && model.isEnabled()) { // Draw a line border with background Rectangle rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { JideSwingUtilities.paintBackground(g, rect, _highlight, _highlight); } rect = getDropDownRect(b, orientation, menuWidth, menuHeight); JideSwingUtilities.paintBackground(g, rect, _highlight, _highlight); if (isAlwaysDropdown(b)) { rect = new Rectangle(0, 0, menuWidth, menuHeight); paintRaisedBorder(g, rect); } else { rect = getButtonRect(b, orientation, menuWidth, menuHeight); paintRaisedBorder(g, rect); rect = getDropDownRect(b, orientation, menuWidth, menuHeight); paintRaisedBorder(g, rect); } } else { if (b.isOpaque()) { Rectangle rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_DEFAULT); } rect = getDropDownRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_DEFAULT); } } } } else if (b.getButtonStyle() == ButtonStyle.TOOLBOX_STYLE) { if ((model.isSelected())) { // Draw a dark shadow border without bottom getPainter().paintSelectedMenu(b, g, new Rectangle(0, 0, menuWidth, menuHeight), orientation, ThemePainter.STATE_SELECTED); } else if (model.isArmed() || model.isPressed()) { Rectangle rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_PRESSED); } rect = getDropDownRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_ROLLOVER); if (!b.isOpaque()) { rect = getButtonRect(b, orientation, menuWidth, menuHeight); paintSunken2Border(g, rect); rect = getDropDownRect(b, orientation, menuWidth, menuHeight); paintRaisedBorder(g, rect); } } else if (model instanceof SplitButtonModel && ((DefaultSplitButtonModel) model).isButtonSelected()) { if (isMouseOver() && model.isEnabled()) { Rectangle rect = getDropDownRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_ROLLOVER); rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_PRESSED); } if (!b.isOpaque()) { rect = getButtonRect(b, orientation, menuWidth, menuHeight); paintSunken2Border(g, rect); rect = getDropDownRect(b, orientation, menuWidth, menuHeight); paintRaisedBorder(g, rect); } } else { Rectangle rect; if (b.isOpaque()) { rect = getDropDownRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_DEFAULT); } rect = getButtonRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_SELECTED); if (!b.isOpaque()) { rect = getButtonRect(b, orientation, menuWidth, menuHeight); paintSunken2Border(g, rect); rect = getDropDownRect(b, orientation, menuWidth, menuHeight); paintRaisedBorder(g, rect); } } } else { if (b.isRolloverEnabled() && isMouseOver() && model.isEnabled()) { // Draw a line border with background if (isAlwaysDropdown(b)) { Rectangle rect = new Rectangle(0, 0, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_ROLLOVER); paintRaised2Border(g, rect); } else { Rectangle rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_ROLLOVER); } rect = getDropDownRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_ROLLOVER); rect = getButtonRect(b, orientation, menuWidth, menuHeight); paintRaised2Border(g, rect); rect = getDropDownRect(b, orientation, menuWidth, menuHeight); paintRaised2Border(g, rect); } } else { if (b.isOpaque()) { Rectangle rect = getButtonRect(b, orientation, menuWidth, menuHeight); if (b.isButtonEnabled()) { getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_DEFAULT); } rect = getDropDownRect(b, orientation, menuWidth, menuHeight); getPainter().paintButtonBackground(b, g, rect, orientation, ThemePainter.STATE_DEFAULT); } else { if (isAlwaysDropdown(b)) { Rectangle rect = new Rectangle(0, 0, menuWidth, menuHeight); paintRaisedBorder(g, rect); } else { Rectangle rect = getButtonRect(b, orientation, menuWidth, menuHeight); paintRaisedBorder(g, rect); rect = getDropDownRect(b, orientation, menuWidth, menuHeight); paintRaisedBorder(g, rect); } } } } } paintArrow(menuItem, g); } protected void paintArrow(JMenuItem menuItem, Graphics g) { int menuWidth; int menuHeight; int orientation = JideSwingUtilities.getOrientationOf(menuItem); if (orientation == SwingConstants.HORIZONTAL) { menuWidth = menuItem.getWidth(); menuHeight = menuItem.getHeight(); } else { menuWidth = menuItem.getHeight(); menuHeight = menuItem.getWidth(); } int startX; if (menuItem.getComponentOrientation().isLeftToRight()) { startX = menuWidth - 9; } else { startX = 4; } if (menuItem.isEnabled()) { JideSwingUtilities.paintArrow(g, getForegroundOfState(menuItem), startX, menuHeight / 2 - 1, 5, SwingConstants.HORIZONTAL); } else { JideSwingUtilities.paintArrow(g, UIDefaultsLookup.getColor("controlShadow"), startX, menuHeight / 2 - 1, 5, SwingConstants.HORIZONTAL); } } /** * Gets the bounds for the drop down part of the <code>JideSplitButton</code>. * * @param c the component. In this case, it is the <code>JideSplitButton</code>. * @param orientation the orientation. * @param width the width of the <code>JideSplitButton</code> * @param height the height of the <code>JideSplitButton</code>. * @return the bounds for the drop down part of the <code>JideSplitButton</code>. */ protected Rectangle getDropDownRect(JComponent c, int orientation, int width, int height) { Object position = c.getClientProperty(JideButton.CLIENT_PROPERTY_SEGMENT_POSITION); Rectangle rect; if (c.getComponentOrientation().isLeftToRight()) { rect = new Rectangle(width - _splitButtonMargin - 1 + getOffset(), 0, _splitButtonMargin - getOffset(), height); } else { rect = new Rectangle(0, 0, _splitButtonMargin - getOffset(), height); } if (position == null || JideButton.SEGMENT_POSITION_ONLY.equals(position)) { } else if (JideButton.SEGMENT_POSITION_FIRST.equals(position)) { if (orientation == SwingConstants.HORIZONTAL) { rect.width++; } else { rect.height++; } } else if (JideButton.SEGMENT_POSITION_MIDDLE.equals(position)) { if (orientation == SwingConstants.HORIZONTAL) { rect.width++; } else { rect.height++; } } else if (JideButton.SEGMENT_POSITION_LAST.equals(position)) { } return rect; } /** * Gets the bounds for the button part of the <code>JideSplitButton</code>. * * @param c the component. In this case, it is the <code>JideSplitButton</code>. * @param orientation the orientation. * @param width the width of the <code>JideSplitButton</code> * @param height the height of the <code>JideSplitButton</code>. * @return the bounds for the button part of the <code>JideSplitButton</code>. */ protected Rectangle getButtonRect(JComponent c, int orientation, int width, int height) { Rectangle rect; if (orientation == SwingConstants.HORIZONTAL && c.getComponentOrientation().isLeftToRight()) { rect = new Rectangle(0, 0, width - _splitButtonMargin, height); } else { rect = new Rectangle(_splitButtonMargin - 1, 0, width - _splitButtonMargin, height); } return rect; } protected void paintSunkenBorder(Graphics g, Rectangle b) { Color old = g.getColor(); g.setColor(_shadowColor); // inner 3D border g.drawLine(b.x, b.y, b.x + b.width - 1, b.y); g.drawLine(b.x, b.y, b.x, b.y + b.height - 1); g.setColor(_lightHighlightColor); // black drop shadow __| g.drawLine(b.x, b.y + b.height - 1, b.x + b.width - 1, b.y + b.height - 1); g.drawLine(b.x + b.width - 1, b.y, b.x + b.width - 1, b.y + b.height - 1); g.setColor(old); } protected void paintSunken2Border(Graphics g, Rectangle b) { Color old = g.getColor(); g.setColor(_darkShadowColor); // inner 3D border g.drawLine(b.x, b.y, b.x + b.width - 2, b.y); g.drawLine(b.x, b.y, b.x, b.y + b.height - 2); g.setColor(_shadowColor); // inner 3D border g.drawLine(b.x + 1, b.y + 1, b.x + b.width - 3, b.y + 1); g.drawLine(b.x + 1, b.y + 1, b.x + 1, b.y + b.height - 3); g.setColor(_lightHighlightColor); // black drop shadow __| g.drawLine(b.x, b.y + b.height - 1, b.x + b.width - 1, b.y + b.height - 1); g.drawLine(b.x + b.width - 1, b.x, b.x + b.width - 1, b.y + b.height - 1); g.setColor(old); } protected void paintRaised2Border(Graphics g, Rectangle b) { Color old = g.getColor(); g.setColor(_lightHighlightColor); // inner 3D border g.drawLine(b.x, b.y, b.x + b.width - 1, b.y); g.drawLine(b.x, b.y, b.x, b.y + b.height - 1); g.setColor(_shadowColor); // gray drop shadow __| g.drawLine(b.x + 1, b.y + b.height - 2, b.x + b.width - 2, b.y + b.height - 2); g.drawLine(b.x + b.width - 2, 1, b.x + b.width - 2, b.y + b.height - 2); g.setColor(_darkShadowColor); // black drop shadow __| g.drawLine(b.x, b.y + b.height - 1, b.x + b.width - 1, b.y + b.height - 1); g.drawLine(b.x + b.width - 1, b.y, b.x + b.width - 1, b.y + b.height - 1); g.setColor(old); } protected void paintRaisedBorder(Graphics g, Rectangle b) { Color old = g.getColor(); g.setColor(_lightHighlightColor); // inner 3D border g.drawLine(b.x, b.y, b.x + b.width - 1, b.y); g.drawLine(b.x, b.y, b.x, b.y + b.height - 1); g.setColor(_shadowColor); // black drop shadow __| g.drawLine(b.x, b.y + b.height - 1, b.x + b.width - 1, b.y + b.height - 1); g.drawLine(b.x + b.width - 1, b.y, b.x + b.width - 1, b.y + b.height - 1); g.setColor(old); } protected class MouseInputHandler implements MouseInputListener { public void mouseClicked(MouseEvent e) { cancelMenuIfNecessary(e); } /** * Invoked when the mouse has been clicked on the menu. This method clears or sets the selection path of the * MenuSelectionManager. * * @param e the mouse event */ public void mousePressed(MouseEvent e) { JMenu menu = (JMenu) menuItem; if (!menu.isEnabled()) return; setMouseOver(true); if (!SwingUtilities.isLeftMouseButton(e)) { return; } if (isClickOnButton(e, menu)) { if (((JideSplitButton) menuItem).isButtonEnabled()) { // click button menu.getModel().setArmed(true); menu.getModel().setPressed(true); } if (!menu.hasFocus() && menu.isRequestFocusEnabled()) { menu.requestFocus(); } } else { downButtonPressed(menu); } } private boolean isClickOnButton(MouseEvent e, JMenu menu) { if (((JideSplitButton) menu).isAlwaysDropdown()) { return false; } boolean clickOnDropDown = false; if (BasicJideButtonUI.shouldWrapText(menuItem)) { int size = 27; if (JideSwingUtilities.getOrientationOf(menuItem) == SwingConstants.HORIZONTAL) { if (e.getPoint().getY() < menu.getHeight() - size) { clickOnDropDown = true; } } else { if (e.getPoint().getY() < menu.getHeight() - size) { clickOnDropDown = true; } } } else { int size = ((JMenu) menuItem).isTopLevelMenu() ? _splitButtonMargin : _splitButtonMarginOnMenu; if (JideSwingUtilities.getOrientationOf(menuItem) == SwingConstants.HORIZONTAL) { if (menu.getComponentOrientation().isLeftToRight()) { if (e.getPoint().getX() < menu.getWidth() - size) { clickOnDropDown = true; } } else { if (e.getPoint().getX() >= size) { clickOnDropDown = true; } } } else { if (e.getPoint().getY() < menu.getHeight() - size) { clickOnDropDown = true; } } } return clickOnDropDown; } /** * Invoked when the mouse has been released on the menu. Delegates the mouse event to the MenuSelectionManager. * * @param e the mouse event */ public void mouseReleased(MouseEvent e) { JMenu menu = (JMenu) menuItem; if (!menu.isEnabled()) { return; } if (!isClickOnButton(e, menu)) { // these two lines order matters. In this order, it would not trigger actionPerformed. menuItem.getModel().setArmed(false); menuItem.getModel().setPressed(false); } cancelMenuIfNecessary(e); } private void cancelMenuIfNecessary(MouseEvent e) { JMenu menu = (JMenu) menuItem; if (!menu.isEnabled()) return; if (isClickOnButton(e, menu)) { if (((JideSplitButton) menuItem).isButtonEnabled()) { // click button // these two lines order matters. In this order, it would trigger actionPerformed. if (SwingUtilities.isLeftMouseButton(e)) { menu.getModel().setPressed(false); menu.getModel().setArmed(false); } else { menu.getModel().setArmed(false); menu.getModel().setPressed(false); } MenuSelectionManager manager = MenuSelectionManager.defaultManager(); MenuElement[] menuElements = manager.getSelectedPath(); for (int i = menuElements.length - 1; i >= 0; i--) { MenuElement menuElement = menuElements[i]; if (menuElement instanceof JPopupMenu && ((JPopupMenu) menuElement).isAncestorOf(menu)) { menu.getModel().setRollover(false); setMouseOver(false); manager.clearSelectedPath(); } } } } else { // MenuSelectionManager manager = // MenuSelectionManager.defaultManager(); // manager.processMouseEvent(e); // if (!e.isConsumed()) // manager.clearSelectedPath(); } } /** * Invoked when the cursor enters the menu. This method sets the selected path for the MenuSelectionManager and * handles the case in which a menu item is used to pop up an additional menu, as in a hierarchical menu * system. * * @param e the mouse event; not used */ public void mouseEntered(MouseEvent e) { JMenu menu = (JMenu) menuItem; if (!menu.isEnabled()) return; MenuSelectionManager manager = MenuSelectionManager.defaultManager(); MenuElement selectedPath[] = manager.getSelectedPath(); if (!menu.isTopLevelMenu()) { if (!(selectedPath.length > 0 && selectedPath[selectedPath.length - 1] == menu.getPopupMenu())) { if (menu.getDelay() == 0) { appendPath(getPath(), menu.getPopupMenu()); } else { manager.setSelectedPath(getPath()); setupPostTimer(menu); } } } else { if (selectedPath.length > 0 && selectedPath[0] == menu.getParent()) { MenuElement newPath[] = new MenuElement[3]; // A top level menu's parent is by definition // a JMenuBar newPath[0] = (MenuElement) menu.getParent(); newPath[1] = menu; newPath[2] = menu.getPopupMenu(); manager.setSelectedPath(newPath); } } if (!SwingUtilities.isLeftMouseButton(e)) { setMouseOver(true); } menuItem.repaint(); } public void mouseExited(MouseEvent e) { setMouseOver(false); menuItem.repaint(); } /** * Invoked when a mouse button is pressed on the menu and then dragged. Delegates the mouse event to the * MenuSelectionManager. * * @param e the mouse event * @see java.awt.event.MouseMotionListener#mouseDragged */ public void mouseDragged(MouseEvent e) { JMenu menu = (JMenu) menuItem; if (!menu.isEnabled()) return; MenuSelectionManager.defaultManager().processMouseEvent(e); } public void mouseMoved(MouseEvent e) { JMenu menu = (JMenu) menuItem; if (!menu.isEnabled()) return; if (menuItem instanceof JideSplitButton) { if (isClickOnButton(e, ((JMenu) menuItem))) { ((SplitButtonModel) ((JideSplitButton) menuItem).getModel()).setButtonRollover(true); } else { ((SplitButtonModel) ((JideSplitButton) menuItem).getModel()).setButtonRollover(false); } } } } @Override public Dimension getPreferredSize(JComponent c) { if (!(c instanceof JMenu) || !((JMenu) c).isTopLevelMenu()) { return super.getPreferredSize(c); } AbstractButton b = (AbstractButton) c; boolean isHorizontal = JideSwingUtilities.getOrientationOf(c) == SwingConstants.HORIZONTAL; Dimension d = JideSwingUtilities.getPreferredButtonSize(b, defaultTextIconGap, true); // TODO: we should use isHorizontal when JideSwingUtilities.getPreferredButtonSize supports it if (BasicJideButtonUI.shouldWrapText(c)) { if (c instanceof JideSplitButton) { d.width += getAdjustExtraWidth(b, b.getText(), 8); } } else { d.width += getRightMargin(); if (isDownArrowVisible(b.getParent())) { d.width += 1; } } if (isHorizontal) return d; else //noinspection SuspiciousNameCombination return new Dimension(d.height, d.width); // swap width and height } @Override public Dimension getMinimumSize(JComponent c) { if (!(c instanceof JMenu) || !((JMenu) c).isTopLevelMenu()) { return super.getMinimumSize(c); } Dimension d = getPreferredSize(c); View v = (View) c.getClientProperty(BasicHTML.propertyKey); if (v != null) { if (JideSwingUtilities.getOrientationOf(c) == SwingConstants.HORIZONTAL) d.width -= v.getPreferredSpan(View.X_AXIS) - v.getMinimumSpan(View.X_AXIS); else // TODO: not sure if this is correct d.height -= v.getPreferredSpan(View.X_AXIS) - v.getMinimumSpan(View.X_AXIS); } return d; } @Override public Dimension getMaximumSize(JComponent c) { if (!(c instanceof JMenu) || !((JMenu) c).isTopLevelMenu()) { return super.getMaximumSize(c); } Dimension d = getPreferredSize(c); View v = (View) c.getClientProperty(BasicHTML.propertyKey); if (v != null) { if (JideSwingUtilities.getOrientationOf(c) == SwingConstants.HORIZONTAL) d.width += v.getMaximumSpan(View.X_AXIS) - v.getPreferredSpan(View.X_AXIS); else // TODO: not sure if this is correct d.height += v.getMaximumSpan(View.X_AXIS) - v.getPreferredSpan(View.X_AXIS); } return d; } @Override protected void paintText(Graphics g, JMenuItem menuItem, Rectangle textRect, String text) { // Note: This method is almost identical to the same method in WindowsMenuItemUI ButtonModel model = menuItem.getModel(); FontMetrics fm = g.getFontMetrics(); if (!(menuItem instanceof JMenu) || !((JMenu) menuItem).isTopLevelMenu()) { int defaultTextIconGap = UIDefaultsLookup.getInt("MenuItem.textIconGap"); int defaultShadowWidth = UIDefaultsLookup.getInt("MenuItem.shadowWidth"); if (menuItem.getComponentOrientation().isLeftToRight()) { textRect.x = defaultShadowWidth + defaultTextIconGap; } else { // isLeftToRight is false Rectangle2D rectText = fm.getStringBounds(text, g); textRect.x = (int) (menuItem.getWidth() - defaultShadowWidth - defaultTextIconGap + rectText.getWidth() + (4 + menuItem.getHeight() / 2 - 1)); } } else if (!menuItem.getComponentOrientation().isLeftToRight()) { if (menuItem.getComponentOrientation().isHorizontal()) { Rectangle2D rectText = fm.getStringBounds(text, g); textRect.x = (int) (menuItem.getWidth() - textRect.x - rectText.getWidth() + (4 + menuItem.getHeight() / 2 - 1)); } } int mnemonicIndex = menuItem.getDisplayedMnemonicIndex(); // W2K Feature: Check to see if the Underscore should be rendered. if (WindowsLookAndFeel.isMnemonicHidden()) { mnemonicIndex = -1; } Color oldColor = g.getColor(); if (!model.isEnabled() || (menuItem instanceof JideSplitButton && !((JideSplitButton) menuItem).isButtonEnabled())) { if (menuItem.getParent() != null) { // *** paint the text disabled g.setColor(menuItem.getParent().getBackground().brighter()); // JDK PORTING HINT // JDK1.3: No drawStringUnderlineCharAt, draw the string then draw the underline drawStringUnderlineCharAt(menuItem, g, text, mnemonicIndex, textRect.x, textRect.y + fm.getAscent()); g.setColor(menuItem.getParent().getBackground().darker()); } // JDK PORTING HINT // JDK1.3: No drawStringUnderlineCharAt, draw the string then draw the underline drawStringUnderlineCharAt(menuItem, g, text, mnemonicIndex, textRect.x - 1, textRect.y + fm.getAscent() - 1); } else { // For Win95, the selected text color is the selection foreground color Color color = getForegroundOfState(menuItem); if(color == null || color instanceof UIResource) { if (model.isSelected()) { g.setColor(selectionForeground); } else { g.setColor(color); } } else { g.setColor(color); } drawStringUnderlineCharAt(menuItem, g, text, mnemonicIndex, textRect.x, textRect.y + fm.getAscent()); } g.setColor(oldColor); } private Color getForegroundOfState(JMenuItem menuItem) { int state = JideSwingUtilities.getButtonState(menuItem); Color foreground = null; if (menuItem instanceof ComponentStateSupport) { foreground = ((ComponentStateSupport) menuItem).getForegroundOfState(state); } if (foreground == null || foreground instanceof UIResource) { foreground = menuItem.getForeground(); } return foreground; } protected void drawStringUnderlineCharAt(JComponent c, Graphics g, String text, int underlinedIndex, int x, int y) { JideSwingUtilities.drawStringUnderlineCharAt(c, g, text, underlinedIndex, x, y); } @Override protected void paintIcon(JMenuItem b, Graphics g) { ButtonModel model = b.getModel(); // Paint the Icon if (b.getIcon() != null) { // if (JideSwingUtilities.getOrientationOf(b) == SwingConstants.VERTICAL) { // ((Graphics2D) g).translate(0, b.getWidth() - 1); // ((Graphics2D) g).rotate(-Math.PI / 2); // } Icon icon = getIcon(b); if (icon != null) { if (!b.getComponentOrientation().isLeftToRight()) { if (b.getComponentOrientation().isHorizontal()) { iconRect.x = b.getWidth() - iconRect.x - icon.getIconWidth() + ( 4 + b.getHeight() / 2 - 1); } } boolean enabled = model.isEnabled() && (!(model instanceof SplitButtonModel) || ((SplitButtonModel) model).isButtonEnabled()); if (isFloatingIcon() && enabled) { if (model.isRollover() && !model.isPressed() && !model.isSelected()) { if (!"true".equals(SecurityUtils.getProperty("shadingtheme", "false"))) { if (icon instanceof ImageIcon) { ImageIcon shadow = IconsFactory.createGrayImage(((ImageIcon) icon).getImage()); shadow.paintIcon(b, g, iconRect.x + 1, iconRect.y + 1); } else { ImageIcon shadow = IconsFactory.createGrayImage(b, icon); shadow.paintIcon(b, g, iconRect.x + 1, iconRect.y + 1); } icon.paintIcon(b, g, iconRect.x - 1, iconRect.y - 1); } else { icon.paintIcon(b, g, iconRect.x, iconRect.y); } } else { icon.paintIcon(b, g, iconRect.x, iconRect.y); } } else { icon.paintIcon(b, g, iconRect.x, iconRect.y); } } // if (JideSwingUtilities.getOrientationOf(b) == SwingConstants.VERTICAL) { // ((Graphics2D) g).rotate(Math.PI / 2); // ((Graphics2D) g).translate(0, -b.getHeight() + 1); // } } } @Override protected boolean isFloatingIcon() { return _isFloatingIcon; } @Override protected Icon getIcon(AbstractButton b) { ButtonModel model = b.getModel(); Icon icon = b.getIcon(); Icon tmpIcon = null; if (!model.isEnabled() || !((JideSplitButton) menuItem).isButtonEnabled()) { if (model.isSelected()) { tmpIcon = b.getDisabledSelectedIcon(); } else { tmpIcon = b.getDisabledIcon(); } // create default disabled icon if (tmpIcon == null) { if (icon instanceof ImageIcon) { icon = IconsFactory.createGrayImage(((ImageIcon) icon).getImage()); } else { icon = IconsFactory.createGrayImage(b, icon); } } } else if (model.isPressed() && model.isArmed()) { tmpIcon = b.getPressedIcon(); if (tmpIcon != null) { // revert back to 0 offset // clearTextShiftOffset(); } } else if (b.isRolloverEnabled() && model.isRollover()) { if (model.isSelected()) { tmpIcon = b.getRolloverSelectedIcon(); } else { tmpIcon = b.getRolloverIcon(); } } else if (model.isSelected()) { tmpIcon = b.getSelectedIcon(); } if (tmpIcon != null) { icon = tmpIcon; } return icon; } /** * The gap between the button part and the drop down menu part. * * @return the gap. */ protected int getOffset() { return 0; } protected boolean isAlwaysDropdown(JMenuItem menuItem) { return menuItem instanceof JideSplitButton && ((JideSplitButton) menuItem).isAlwaysDropdown(); } @Override protected int getRightMargin() { return _splitButtonMargin - 1; } /** * Actions for Buttons. Two type of action are supported: pressed: Moves the button to a pressed state released: * Disarms the button. */ private static class Actions extends UIAction { private static final String PRESS = "pressed"; private static final String RELEASE = "released"; private static final String DOWN_PRESS = "downPressed"; private static final String DOWN_RELEASE = "downReleased"; Actions(String name) { super(name); } public void actionPerformed(ActionEvent e) { AbstractButton b = (AbstractButton) e.getSource(); String key = getName(); // if isAlwaysDropDown it true, treat PRESS as DOWN_PRESS if (PRESS.equals(key) && ((JideSplitButton) b).isAlwaysDropdown()) { key = DOWN_PRESS; } if (PRESS.equals(key)) { ButtonModel model = b.getModel(); model.setArmed(true); model.setPressed(true); if (!b.hasFocus()) { b.requestFocus(); } } else if (RELEASE.equals(key)) { ButtonModel model = b.getModel(); model.setPressed(false); model.setArmed(false); } else if (DOWN_PRESS.equals(key)) { downButtonPressed((JMenu) b); } else if (DOWN_RELEASE.equals(key)) { } } @Override public boolean isEnabled(Object sender) { return !(sender != null && (sender instanceof AbstractButton) && !((AbstractButton) sender).getModel().isEnabled()); } } /** * Populates Buttons actions. * * @param map the map */ public static void loadActionMap(LazyActionMap map) { map.put(new Actions(Actions.PRESS)); map.put(new Actions(Actions.RELEASE)); map.put(new Actions(Actions.DOWN_PRESS)); map.put(new Actions(Actions.DOWN_RELEASE)); } @Override protected void updateMnemonicBinding() { super.updateMnemonicBinding(); int mnemonic = menuItem.getModel().getMnemonic(); if (mnemonic != 0 && windowInputMap != null) { int[] shortcutKeys = (int[]) UIDefaultsLookup.get("Menu.shortcutKeys"); if (shortcutKeys == null) { shortcutKeys = new int[]{KeyEvent.ALT_MASK}; } for (int shortcutKey : shortcutKeys) { windowInputMap.put(KeyStroke.getKeyStroke(mnemonic, shortcutKey, false), "pressed"); windowInputMap.put(KeyStroke.getKeyStroke(mnemonic, shortcutKey, true), "released"); } } } protected static void downButtonPressed(JMenu menu) { MenuSelectionManager manager = MenuSelectionManager.defaultManager(); if (menu.isTopLevelMenu()) { if (menu.isSelected()) { manager.clearSelectedPath(); } else { //Container cnt = menu.getParent(); Container cnt = getFirstParentMenuElement(menu); if (cnt != null && cnt instanceof MenuElement) { ArrayList<Component> parents = new ArrayList<Component>(); while (cnt instanceof MenuElement) { parents.add(0, cnt); if (cnt instanceof JPopupMenu) { cnt = (Container) ((JPopupMenu) cnt).getInvoker(); } else { //cnt = cnt.getParent(); cnt = getFirstParentMenuElement(cnt); } } MenuElement me[] = new MenuElement[parents.size() + 1]; for (int i = 0; i < parents.size(); i++) { Container container = (Container) parents.get(i); me[i] = (MenuElement) container; } me[parents.size()] = menu; manager.setSelectedPath(me); } else { MenuElement me[] = new MenuElement[1]; me[0] = menu; manager.setSelectedPath(me); } } } MenuElement selectedPath[] = manager.getSelectedPath(); if (selectedPath.length > 0 && selectedPath[selectedPath.length - 1] != menu.getPopupMenu()) { if (menu.isTopLevelMenu() || menu.getDelay() == 0) { appendPath(selectedPath, menu.getPopupMenu()); } else { setupPostTimer(menu); } } } protected static Container getFirstParentMenuElement(Component comp) { Container parent = comp.getParent(); while (parent != null) { if (parent instanceof MenuElement) return parent; parent = parent.getParent(); } return null; } /** * @param c the component * @param text the text * @param extraWidth the extra width * @return the adjusted width. */ public static int getAdjustExtraWidth(Component c, String text, int extraWidth) { String[] lines = getWrappedText(text); Font font = c.getFont(); FontMetrics fm = c.getFontMetrics(font); int line1Width = fm.stringWidth(lines[0]); int line2Width = lines.length <= 1 ? 0 : fm.stringWidth(lines[1]); int oldMaxWidth = Math.max(line1Width, line2Width); line2Width += extraWidth; int maxWidth = Math.max(line1Width, line2Width); return maxWidth - oldMaxWidth; } public static String getMaxLengthWord(String text) { if (text.indexOf(' ') == -1) { return text; } else { int minDiff = text.length(); int minPos = -1; int mid = text.length() / 2; int pos = -1; while (true) { pos = text.indexOf(' ', pos + 1); if (pos == -1) { break; } int diff = Math.abs(pos - mid); if (diff < minDiff) { minDiff = diff; minPos = pos; } } return minPos >= mid ? text.substring(0, minPos) : text.substring(minPos + 1); } } /** * Gets the text after wrapping. Please note, it will only wrap text into two lines thus it is not designed for * general usage. * * @param text the text * @return the two lines. */ public static String[] getWrappedText(String text) { String[] words = text.split(" "); if (words.length <= 2) { return words; // no line break } else if (words.length >= 3) { int minDiff = text.length(); int minPos = -1; int pos = -1; int mid = text.length() / 2; while (true) { pos = text.indexOf(' ', pos + 1); if (pos == -1) { break; } int diff = Math.abs(pos - mid); if (diff < minDiff) { minDiff = diff; minPos = pos; } } return new String[]{text.substring(0, minPos), text.substring(minPos + 1)}; } return words; } }