/* * Copyright (c) 2002, 2008, 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 sun.swing; import static sun.swing.SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET; import javax.swing.*;import javax.swing.plaf.basic.BasicHTML;import javax.swing.text.View;import java.awt.*;import java.awt.event.KeyEvent;import java.util.Map;import java.util.HashMap; /** * Calculates preferred size and layouts menu items. */public class MenuItemLayoutHelper { /* Client Property keys for calculation of maximal widths */ public static final StringUIClientPropertyKey MAX_ARROW_WIDTH = new StringUIClientPropertyKey("maxArrowWidth"); public static final StringUIClientPropertyKey MAX_CHECK_WIDTH = new StringUIClientPropertyKey("maxCheckWidth"); public static final StringUIClientPropertyKey MAX_ICON_WIDTH = new StringUIClientPropertyKey("maxIconWidth"); public static final StringUIClientPropertyKey MAX_TEXT_WIDTH = new StringUIClientPropertyKey("maxTextWidth"); public static final StringUIClientPropertyKey MAX_ACC_WIDTH = new StringUIClientPropertyKey("maxAccWidth"); public static final StringUIClientPropertyKey MAX_LABEL_WIDTH = new StringUIClientPropertyKey("maxLabelWidth"); private JMenuItem mi; private JComponent miParent; private Font font; private Font accFont; private FontMetrics fm; private FontMetrics accFm; private Icon icon; private Icon checkIcon; private Icon arrowIcon; private String text; private String accText; private boolean isColumnLayout; private boolean useCheckAndArrow; private boolean isLeftToRight; private boolean isTopLevelMenu; private View htmlView; private int verticalAlignment; private int horizontalAlignment; private int verticalTextPosition; private int horizontalTextPosition; private int gap; private int leadingGap; private int afterCheckIconGap; private int minTextOffset; private int leftTextExtraWidth; private Rectangle viewRect; private RectSize iconSize; private RectSize textSize; private RectSize accSize; private RectSize checkSize; private RectSize arrowSize; private RectSize labelSize; /** * The empty protected constructor is necessary for derived classes. */ protected MenuItemLayoutHelper() { } public MenuItemLayoutHelper(JMenuItem mi, Icon checkIcon, Icon arrowIcon, Rectangle viewRect, int gap, String accDelimiter, boolean isLeftToRight, Font font, Font accFont, boolean useCheckAndArrow, String propertyPrefix) { reset(mi, checkIcon, arrowIcon, viewRect, gap, accDelimiter, isLeftToRight, font, accFont, useCheckAndArrow, propertyPrefix); } protected void reset(JMenuItem mi, Icon checkIcon, Icon arrowIcon, Rectangle viewRect, int gap, String accDelimiter, boolean isLeftToRight, Font font, Font accFont, boolean useCheckAndArrow, String propertyPrefix) { this.mi = mi; this.miParent = getMenuItemParent(mi); this.accText = getAccText(accDelimiter); this.verticalAlignment = mi.getVerticalAlignment(); this.horizontalAlignment = mi.getHorizontalAlignment(); this.verticalTextPosition = mi.getVerticalTextPosition(); this.horizontalTextPosition = mi.getHorizontalTextPosition(); this.useCheckAndArrow = useCheckAndArrow; this.font = font; this.accFont = accFont; this.fm = mi.getFontMetrics(font); this.accFm = mi.getFontMetrics(accFont); this.isLeftToRight = isLeftToRight; this.isColumnLayout = isColumnLayout(isLeftToRight, horizontalAlignment, horizontalTextPosition, verticalTextPosition); this.isTopLevelMenu = (this.miParent == null) ? true : false; this.checkIcon = checkIcon; this.icon = getIcon(propertyPrefix); this.arrowIcon = arrowIcon; this.text = mi.getText(); this.gap = gap; this.afterCheckIconGap = getAfterCheckIconGap(propertyPrefix); this.minTextOffset = getMinTextOffset(propertyPrefix); this.htmlView = (View) mi.getClientProperty(BasicHTML.propertyKey); this.viewRect = viewRect; this.iconSize = new RectSize(); this.textSize = new RectSize(); this.accSize = new RectSize(); this.checkSize = new RectSize(); this.arrowSize = new RectSize(); this.labelSize = new RectSize(); calcExtraWidths(); calcWidthsAndHeights(); setOriginalWidths(); calcMaxWidths(); this.leadingGap = getLeadingGap(propertyPrefix); calcMaxTextOffset(viewRect); } private void calcExtraWidths() { leftTextExtraWidth = getLeftExtraWidth(text); } private int getLeftExtraWidth(String str) { int lsb = SwingUtilities2.getLeftSideBearing(mi, fm, str); if (lsb < 0) { return -lsb; } else { return 0; } } private void setOriginalWidths() { iconSize.origWidth = iconSize.width; textSize.origWidth = textSize.width; accSize.origWidth = accSize.width; checkSize.origWidth = checkSize.width; arrowSize.origWidth = arrowSize.width; } private String getAccText(String acceleratorDelimiter) { String accText = ""; KeyStroke accelerator = mi.getAccelerator(); if (accelerator != null) { int modifiers = accelerator.getModifiers(); if (modifiers > 0) { accText = KeyEvent.getKeyModifiersText(modifiers); accText += acceleratorDelimiter; } int keyCode = accelerator.getKeyCode(); if (keyCode != 0) { accText += KeyEvent.getKeyText(keyCode); } else { accText += accelerator.getKeyChar(); } } return accText; } private Icon getIcon(String propertyPrefix) { // In case of column layout, .checkIconFactory is defined for this UI, // the icon is compatible with it and useCheckAndArrow() is true, // then the icon is handled by the checkIcon. Icon icon = null; MenuItemCheckIconFactory iconFactory = (MenuItemCheckIconFactory) UIManager.get(propertyPrefix + ".checkIconFactory"); if (!isColumnLayout || !useCheckAndArrow || iconFactory == null || !iconFactory.isCompatible(checkIcon, propertyPrefix)) { icon = mi.getIcon(); } return icon; } private int getMinTextOffset(String propertyPrefix) { int minimumTextOffset = 0; Object minimumTextOffsetObject = UIManager.get(propertyPrefix + ".minimumTextOffset"); if (minimumTextOffsetObject instanceof Integer) { minimumTextOffset = (Integer) minimumTextOffsetObject; } return minimumTextOffset; } private int getAfterCheckIconGap(String propertyPrefix) { int afterCheckIconGap = gap; Object afterCheckIconGapObject = UIManager.get(propertyPrefix + ".afterCheckIconGap"); if (afterCheckIconGapObject instanceof Integer) { afterCheckIconGap = (Integer) afterCheckIconGapObject; } return afterCheckIconGap; } private int getLeadingGap(String propertyPrefix) { if (checkSize.getMaxWidth() > 0) { return getCheckOffset(propertyPrefix); } else { return gap; // There is no any check icon } } private int getCheckOffset(String propertyPrefix) { int checkIconOffset = gap; Object checkIconOffsetObject = UIManager.get(propertyPrefix + ".checkIconOffset"); if (checkIconOffsetObject instanceof Integer) { checkIconOffset = (Integer) checkIconOffsetObject; } return checkIconOffset; } protected void calcWidthsAndHeights() { // iconRect if (icon != null) { iconSize.width = icon.getIconWidth(); iconSize.height = icon.getIconHeight(); } // accRect if (!accText.equals("")) { accSize.width = SwingUtilities2.stringWidth(mi, accFm, accText); accSize.height = accFm.getHeight(); } // textRect if (text == null) { text = ""; } else if (!text.equals("")) { if (htmlView != null) { // Text is HTML textSize.width = (int) htmlView.getPreferredSpan(View.X_AXIS); textSize.height = (int) htmlView.getPreferredSpan(View.Y_AXIS); } else { // Text isn't HTML textSize.width = SwingUtilities2.stringWidth(mi, fm, text); textSize.height = fm.getHeight(); } } if (useCheckAndArrow) { // checkIcon if (checkIcon != null) { checkSize.width = checkIcon.getIconWidth(); checkSize.height = checkIcon.getIconHeight(); } // arrowRect if (arrowIcon != null) { arrowSize.width = arrowIcon.getIconWidth(); arrowSize.height = arrowIcon.getIconHeight(); } } // labelRect if (isColumnLayout) { labelSize.width = iconSize.width + textSize.width + gap; labelSize.height = max(checkSize.height, iconSize.height, textSize.height, accSize.height, arrowSize.height); } else { Rectangle textRect = new Rectangle(); Rectangle iconRect = new Rectangle(); SwingUtilities.layoutCompoundLabel(mi, fm, text, icon, verticalAlignment, horizontalAlignment, verticalTextPosition, horizontalTextPosition, viewRect, iconRect, textRect, gap); textRect.width += leftTextExtraWidth; Rectangle labelRect = iconRect.union(textRect); labelSize.height = labelRect.height; labelSize.width = labelRect.width; } } protected void calcMaxWidths() { calcMaxWidth(checkSize, MAX_CHECK_WIDTH); calcMaxWidth(arrowSize, MAX_ARROW_WIDTH); calcMaxWidth(accSize, MAX_ACC_WIDTH); if (isColumnLayout) { calcMaxWidth(iconSize, MAX_ICON_WIDTH); calcMaxWidth(textSize, MAX_TEXT_WIDTH); int curGap = gap; if ((iconSize.getMaxWidth() == 0) || (textSize.getMaxWidth() == 0)) { curGap = 0; } labelSize.maxWidth = calcMaxValue(MAX_LABEL_WIDTH, iconSize.maxWidth + textSize.maxWidth + curGap); } else { // We shouldn't use current icon and text widths // in maximal widths calculation for complex layout. iconSize.maxWidth = getParentIntProperty(MAX_ICON_WIDTH); calcMaxWidth(labelSize, MAX_LABEL_WIDTH); // If maxLabelWidth is wider // than the widest icon + the widest text + gap, // we should update the maximal text witdh int candidateTextWidth = labelSize.maxWidth - iconSize.maxWidth; if (iconSize.maxWidth > 0) { candidateTextWidth -= gap; } textSize.maxWidth = calcMaxValue(MAX_TEXT_WIDTH, candidateTextWidth); } } protected void calcMaxWidth(RectSize rs, Object key) { rs.maxWidth = calcMaxValue(key, rs.width); } /** * Calculates and returns maximal value through specified parent component * client property. * * @param propertyName name of the property, which stores the maximal value. * @param value a value which pretends to be maximal * @return maximal value among the parent property and the value. */ protected int calcMaxValue(Object propertyName, int value) { // Get maximal value from parent client property int maxValue = getParentIntProperty(propertyName); // Store new maximal width in parent client property if (value > maxValue) { if (miParent != null) { miParent.putClientProperty(propertyName, value); } return value; } else { return maxValue; } } /** * Returns parent client property as int. * @param propertyName name of the parent property. * @return value of the property as int. */ protected int getParentIntProperty(Object propertyName) { Object value = null; if (miParent != null) { value = miParent.getClientProperty(propertyName); } if ((value == null) || !(value instanceof Integer)) { value = 0; } return (Integer) value; } public static boolean isColumnLayout(boolean isLeftToRight, JMenuItem mi) { assert(mi != null); return isColumnLayout(isLeftToRight, mi.getHorizontalAlignment(), mi.getHorizontalTextPosition(), mi.getVerticalTextPosition()); } /** * Answers should we do column layout for a menu item or not. * We do it when a user doesn't set any alignments * and text positions manually, except the vertical alignment. */ public static boolean isColumnLayout(boolean isLeftToRight, int horizontalAlignment, int horizontalTextPosition, int verticalTextPosition) { if (verticalTextPosition != SwingConstants.CENTER) { return false; } if (isLeftToRight) { if (horizontalAlignment != SwingConstants.LEADING && horizontalAlignment != SwingConstants.LEFT) { return false; } if (horizontalTextPosition != SwingConstants.TRAILING && horizontalTextPosition != SwingConstants.RIGHT) { return false; } } else { if (horizontalAlignment != SwingConstants.LEADING && horizontalAlignment != SwingConstants.RIGHT) { return false; } if (horizontalTextPosition != SwingConstants.TRAILING && horizontalTextPosition != SwingConstants.LEFT) { return false; } } return true; } /** * Calculates maximal text offset. * It is required for some L&Fs (ex: Vista L&F). * The offset is meaningful only for L2R column layout. * * @param viewRect the rectangle, the maximal text offset * will be calculated for. */ private void calcMaxTextOffset(Rectangle viewRect) { if (!isColumnLayout || !isLeftToRight) { return; } // Calculate the current text offset int offset = viewRect.x + leadingGap + checkSize.maxWidth + afterCheckIconGap + iconSize.maxWidth + gap; if (checkSize.maxWidth == 0) { offset -= afterCheckIconGap; } if (iconSize.maxWidth == 0) { offset -= gap; } // maximal text offset shouldn't be less than minimal text offset; if (offset < minTextOffset) { offset = minTextOffset; } // Calculate and store the maximal text offset calcMaxValue(SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET, offset); } /** * Layout icon, text, check icon, accelerator text and arrow icon * in the viewRect and return their positions. * * If horizontalAlignment, verticalTextPosition and horizontalTextPosition * are default (user doesn't set any manually) the layouting algorithm is: * Elements are layouted in the five columns: * check icon + icon + text + accelerator text + arrow icon * * In the other case elements are layouted in the four columns: * check icon + label + accelerator text + arrow icon * Label is union of icon and text. * * The order of columns can be reversed. * It depends on the menu item orientation. */ public LayoutResult layoutMenuItem() { LayoutResult lr = createLayoutResult(); prepareForLayout(lr); if (isColumnLayout()) { if (isLeftToRight()) { doLTRColumnLayout(lr, getLTRColumnAlignment()); } else { doRTLColumnLayout(lr, getRTLColumnAlignment()); } } else { if (isLeftToRight()) { doLTRComplexLayout(lr, getLTRColumnAlignment()); } else { doRTLComplexLayout(lr, getRTLColumnAlignment()); } } alignAccCheckAndArrowVertically(lr); return lr; } private LayoutResult createLayoutResult() { return new LayoutResult( new Rectangle(iconSize.width, iconSize.height), new Rectangle(textSize.width, textSize.height),Lines 1–500 of 1323. Load more
/* * Copyright (c) 2002, 2008, 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 sun.swing; import static sun.swing.SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET; import javax.swing.*; import javax.swing.plaf.basic.BasicHTML; import javax.swing.text.View; import java.awt.*; import java.awt.event.KeyEvent; import java.util.Map; import java.util.HashMap; /** * Calculates preferred size and layouts menu items. */ public class MenuItemLayoutHelper { /* Client Property keys for calculation of maximal widths */ public static final StringUIClientPropertyKey MAX_ARROW_WIDTH = new StringUIClientPropertyKey("maxArrowWidth"); public static final StringUIClientPropertyKey MAX_CHECK_WIDTH = new StringUIClientPropertyKey("maxCheckWidth"); public static final StringUIClientPropertyKey MAX_ICON_WIDTH = new StringUIClientPropertyKey("maxIconWidth"); public static final StringUIClientPropertyKey MAX_TEXT_WIDTH = new StringUIClientPropertyKey("maxTextWidth"); public static final StringUIClientPropertyKey MAX_ACC_WIDTH = new StringUIClientPropertyKey("maxAccWidth"); public static final StringUIClientPropertyKey MAX_LABEL_WIDTH = new StringUIClientPropertyKey("maxLabelWidth"); private JMenuItem mi; private JComponent miParent; private Font font; private Font accFont; private FontMetrics fm; private FontMetrics accFm; private Icon icon; private Icon checkIcon; private Icon arrowIcon; private String text; private String accText; private boolean isColumnLayout; private boolean useCheckAndArrow; private boolean isLeftToRight; private boolean isTopLevelMenu; private View htmlView; private int verticalAlignment; private int horizontalAlignment; private int verticalTextPosition; private int horizontalTextPosition; private int gap; private int leadingGap; private int afterCheckIconGap; private int minTextOffset; private int leftTextExtraWidth; private Rectangle viewRect; private RectSize iconSize; private RectSize textSize; private RectSize accSize; private RectSize checkSize; private RectSize arrowSize; private RectSize labelSize; /** * The empty protected constructor is necessary for derived classes. */ protected MenuItemLayoutHelper() { } public MenuItemLayoutHelper(JMenuItem mi, Icon checkIcon, Icon arrowIcon, Rectangle viewRect, int gap, String accDelimiter, boolean isLeftToRight, Font font, Font accFont, boolean useCheckAndArrow, String propertyPrefix) { reset(mi, checkIcon, arrowIcon, viewRect, gap, accDelimiter, isLeftToRight, font, accFont, useCheckAndArrow, propertyPrefix); } protected void reset(JMenuItem mi, Icon checkIcon, Icon arrowIcon, Rectangle viewRect, int gap, String accDelimiter, boolean isLeftToRight, Font font, Font accFont, boolean useCheckAndArrow, String propertyPrefix) { this.mi = mi; this.miParent = getMenuItemParent(mi); this.accText = getAccText(accDelimiter); this.verticalAlignment = mi.getVerticalAlignment(); this.horizontalAlignment = mi.getHorizontalAlignment(); this.verticalTextPosition = mi.getVerticalTextPosition(); this.horizontalTextPosition = mi.getHorizontalTextPosition(); this.useCheckAndArrow = useCheckAndArrow; this.font = font; this.accFont = accFont; this.fm = mi.getFontMetrics(font); this.accFm = mi.getFontMetrics(accFont); this.isLeftToRight = isLeftToRight; this.isColumnLayout = isColumnLayout(isLeftToRight, horizontalAlignment, horizontalTextPosition, verticalTextPosition); this.isTopLevelMenu = (this.miParent == null) ? true : false; this.checkIcon = checkIcon; this.icon = getIcon(propertyPrefix); this.arrowIcon = arrowIcon; this.text = mi.getText(); this.gap = gap; this.afterCheckIconGap = getAfterCheckIconGap(propertyPrefix); this.minTextOffset = getMinTextOffset(propertyPrefix); this.htmlView = (View) mi.getClientProperty(BasicHTML.propertyKey); this.viewRect = viewRect; this.iconSize = new RectSize(); this.textSize = new RectSize(); this.accSize = new RectSize(); this.checkSize = new RectSize(); this.arrowSize = new RectSize(); this.labelSize = new RectSize(); calcExtraWidths(); calcWidthsAndHeights(); setOriginalWidths(); calcMaxWidths(); this.leadingGap = getLeadingGap(propertyPrefix); calcMaxTextOffset(viewRect); } private void calcExtraWidths() { leftTextExtraWidth = getLeftExtraWidth(text); } private int getLeftExtraWidth(String str) { int lsb = SwingUtilities2.getLeftSideBearing(mi, fm, str); if (lsb < 0) { return -lsb; } else { return 0; } } private void setOriginalWidths() { iconSize.origWidth = iconSize.width; textSize.origWidth = textSize.width; accSize.origWidth = accSize.width; checkSize.origWidth = checkSize.width; arrowSize.origWidth = arrowSize.width; } private String getAccText(String acceleratorDelimiter) { String accText = ""; KeyStroke accelerator = mi.getAccelerator(); if (accelerator != null) { int modifiers = accelerator.getModifiers(); if (modifiers > 0) { accText = KeyEvent.getKeyModifiersText(modifiers); accText += acceleratorDelimiter; } int keyCode = accelerator.getKeyCode(); if (keyCode != 0) { accText += KeyEvent.getKeyText(keyCode); } else { accText += accelerator.getKeyChar(); } } return accText; } private Icon getIcon(String propertyPrefix) { // In case of column layout, .checkIconFactory is defined for this UI, // the icon is compatible with it and useCheckAndArrow() is true, // then the icon is handled by the checkIcon. Icon icon = null; MenuItemCheckIconFactory iconFactory = (MenuItemCheckIconFactory) UIManager.get(propertyPrefix + ".checkIconFactory"); if (!isColumnLayout || !useCheckAndArrow || iconFactory == null || !iconFactory.isCompatible(checkIcon, propertyPrefix)) { icon = mi.getIcon(); } return icon; } private int getMinTextOffset(String propertyPrefix) { int minimumTextOffset = 0; Object minimumTextOffsetObject = UIManager.get(propertyPrefix + ".minimumTextOffset"); if (minimumTextOffsetObject instanceof Integer) { minimumTextOffset = (Integer) minimumTextOffsetObject; } return minimumTextOffset; } private int getAfterCheckIconGap(String propertyPrefix) { int afterCheckIconGap = gap; Object afterCheckIconGapObject = UIManager.get(propertyPrefix + ".afterCheckIconGap"); if (afterCheckIconGapObject instanceof Integer) { afterCheckIconGap = (Integer) afterCheckIconGapObject; } return afterCheckIconGap; } private int getLeadingGap(String propertyPrefix) { if (checkSize.getMaxWidth() > 0) { return getCheckOffset(propertyPrefix); } else { return gap; // There is no any check icon } } private int getCheckOffset(String propertyPrefix) { int checkIconOffset = gap; Object checkIconOffsetObject = UIManager.get(propertyPrefix + ".checkIconOffset"); if (checkIconOffsetObject instanceof Integer) { checkIconOffset = (Integer) checkIconOffsetObject; } return checkIconOffset; } protected void calcWidthsAndHeights() { // iconRect if (icon != null) { iconSize.width = icon.getIconWidth(); iconSize.height = icon.getIconHeight(); } // accRect if (!accText.equals("")) { accSize.width = SwingUtilities2.stringWidth(mi, accFm, accText); accSize.height = accFm.getHeight(); } // textRect if (text == null) { text = ""; } else if (!text.equals("")) { if (htmlView != null) { // Text is HTML textSize.width = (int) htmlView.getPreferredSpan(View.X_AXIS); textSize.height = (int) htmlView.getPreferredSpan(View.Y_AXIS); } else { // Text isn't HTML textSize.width = SwingUtilities2.stringWidth(mi, fm, text); textSize.height = fm.getHeight(); } } if (useCheckAndArrow) { // checkIcon if (checkIcon != null) { checkSize.width = checkIcon.getIconWidth(); checkSize.height = checkIcon.getIconHeight(); } // arrowRect if (arrowIcon != null) { arrowSize.width = arrowIcon.getIconWidth(); arrowSize.height = arrowIcon.getIconHeight(); } } // labelRect if (isColumnLayout) { labelSize.width = iconSize.width + textSize.width + gap; labelSize.height = max(checkSize.height, iconSize.height, textSize.height, accSize.height, arrowSize.height); } else { Rectangle textRect = new Rectangle(); Rectangle iconRect = new Rectangle(); SwingUtilities.layoutCompoundLabel(mi, fm, text, icon, verticalAlignment, horizontalAlignment, verticalTextPosition, horizontalTextPosition, viewRect, iconRect, textRect, gap); textRect.width += leftTextExtraWidth; Rectangle labelRect = iconRect.union(textRect); labelSize.height = labelRect.height; labelSize.width = labelRect.width; } } protected void calcMaxWidths() { calcMaxWidth(checkSize, MAX_CHECK_WIDTH); calcMaxWidth(arrowSize, MAX_ARROW_WIDTH); calcMaxWidth(accSize, MAX_ACC_WIDTH); if (isColumnLayout) { calcMaxWidth(iconSize, MAX_ICON_WIDTH); calcMaxWidth(textSize, MAX_TEXT_WIDTH); int curGap = gap; if ((iconSize.getMaxWidth() == 0) || (textSize.getMaxWidth() == 0)) { curGap = 0; } labelSize.maxWidth = calcMaxValue(MAX_LABEL_WIDTH, iconSize.maxWidth + textSize.maxWidth + curGap); } else { // We shouldn't use current icon and text widths // in maximal widths calculation for complex layout. iconSize.maxWidth = getParentIntProperty(MAX_ICON_WIDTH); calcMaxWidth(labelSize, MAX_LABEL_WIDTH); // If maxLabelWidth is wider // than the widest icon + the widest text + gap, // we should update the maximal text witdh int candidateTextWidth = labelSize.maxWidth - iconSize.maxWidth; if (iconSize.maxWidth > 0) { candidateTextWidth -= gap; } textSize.maxWidth = calcMaxValue(MAX_TEXT_WIDTH, candidateTextWidth); } } protected void calcMaxWidth(RectSize rs, Object key) { rs.maxWidth = calcMaxValue(key, rs.width); } /** * Calculates and returns maximal value through specified parent component * client property. * * @param propertyName name of the property, which stores the maximal value. * @param value a value which pretends to be maximal * @return maximal value among the parent property and the value. */ protected int calcMaxValue(Object propertyName, int value) { // Get maximal value from parent client property int maxValue = getParentIntProperty(propertyName); // Store new maximal width in parent client property if (value > maxValue) { if (miParent != null) { miParent.putClientProperty(propertyName, value); } return value; } else { return maxValue; } } /** * Returns parent client property as int. * @param propertyName name of the parent property. * @return value of the property as int. */ protected int getParentIntProperty(Object propertyName) { Object value = null; if (miParent != null) { value = miParent.getClientProperty(propertyName); } if ((value == null) || !(value instanceof Integer)) { value = 0; } return (Integer) value; } public static boolean isColumnLayout(boolean isLeftToRight, JMenuItem mi) { assert(mi != null); return isColumnLayout(isLeftToRight, mi.getHorizontalAlignment(), mi.getHorizontalTextPosition(), mi.getVerticalTextPosition()); } /** * Answers should we do column layout for a menu item or not. * We do it when a user doesn't set any alignments * and text positions manually, except the vertical alignment. */ public static boolean isColumnLayout(boolean isLeftToRight, int horizontalAlignment, int horizontalTextPosition, int verticalTextPosition) { if (verticalTextPosition != SwingConstants.CENTER) { return false; } if (isLeftToRight) { if (horizontalAlignment != SwingConstants.LEADING && horizontalAlignment != SwingConstants.LEFT) { return false; } if (horizontalTextPosition != SwingConstants.TRAILING && horizontalTextPosition != SwingConstants.RIGHT) { return false; } } else { if (horizontalAlignment != SwingConstants.LEADING && horizontalAlignment != SwingConstants.RIGHT) { return false; } if (horizontalTextPosition != SwingConstants.TRAILING && horizontalTextPosition != SwingConstants.LEFT) { return false; } } return true; } /** * Calculates maximal text offset. * It is required for some L&Fs (ex: Vista L&F). * The offset is meaningful only for L2R column layout. * * @param viewRect the rectangle, the maximal text offset * will be calculated for. */ private void calcMaxTextOffset(Rectangle viewRect) { if (!isColumnLayout || !isLeftToRight) { return; } // Calculate the current text offset int offset = viewRect.x + leadingGap + checkSize.maxWidth + afterCheckIconGap + iconSize.maxWidth + gap; if (checkSize.maxWidth == 0) { offset -= afterCheckIconGap; } if (iconSize.maxWidth == 0) { offset -= gap; } // maximal text offset shouldn't be less than minimal text offset; if (offset < minTextOffset) { offset = minTextOffset; } // Calculate and store the maximal text offset calcMaxValue(SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET, offset); } /** * Layout icon, text, check icon, accelerator text and arrow icon * in the viewRect and return their positions. * * If horizontalAlignment, verticalTextPosition and horizontalTextPosition * are default (user doesn't set any manually) the layouting algorithm is: * Elements are layouted in the five columns: * check icon + icon + text + accelerator text + arrow icon * * In the other case elements are layouted in the four columns: * check icon + label + accelerator text + arrow icon * Label is union of icon and text. * * The order of columns can be reversed. * It depends on the menu item orientation. */ public LayoutResult layoutMenuItem() { LayoutResult lr = createLayoutResult(); prepareForLayout(lr); if (isColumnLayout()) { if (isLeftToRight()) { doLTRColumnLayout(lr, getLTRColumnAlignment()); } else { doRTLColumnLayout(lr, getRTLColumnAlignment()); } } else { if (isLeftToRight()) { doLTRComplexLayout(lr, getLTRColumnAlignment()); } else { doRTLComplexLayout(lr, getRTLColumnAlignment()); } } alignAccCheckAndArrowVertically(lr); return lr; } private LayoutResult createLayoutResult() { return new LayoutResult( new Rectangle(iconSize.width, iconSize.height), new Rectangle(textSize.width, textSize.height),