Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/swing/MenuItemLayoutHelper.java
38829 views
/*1* Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.swing;2627import static sun.swing.SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET;2829import javax.swing.*;30import javax.swing.plaf.basic.BasicHTML;31import javax.swing.text.View;32import java.awt.*;33import java.awt.event.KeyEvent;34import java.util.Map;35import java.util.HashMap;3637/**38* Calculates preferred size and layouts menu items.39*/40public class MenuItemLayoutHelper {4142/* Client Property keys for calculation of maximal widths */43public static final StringUIClientPropertyKey MAX_ARROW_WIDTH =44new StringUIClientPropertyKey("maxArrowWidth");45public static final StringUIClientPropertyKey MAX_CHECK_WIDTH =46new StringUIClientPropertyKey("maxCheckWidth");47public static final StringUIClientPropertyKey MAX_ICON_WIDTH =48new StringUIClientPropertyKey("maxIconWidth");49public static final StringUIClientPropertyKey MAX_TEXT_WIDTH =50new StringUIClientPropertyKey("maxTextWidth");51public static final StringUIClientPropertyKey MAX_ACC_WIDTH =52new StringUIClientPropertyKey("maxAccWidth");53public static final StringUIClientPropertyKey MAX_LABEL_WIDTH =54new StringUIClientPropertyKey("maxLabelWidth");5556private JMenuItem mi;57private JComponent miParent;5859private Font font;60private Font accFont;61private FontMetrics fm;62private FontMetrics accFm;6364private Icon icon;65private Icon checkIcon;66private Icon arrowIcon;67private String text;68private String accText;6970private boolean isColumnLayout;71private boolean useCheckAndArrow;72private boolean isLeftToRight;73private boolean isTopLevelMenu;74private View htmlView;7576private int verticalAlignment;77private int horizontalAlignment;78private int verticalTextPosition;79private int horizontalTextPosition;80private int gap;81private int leadingGap;82private int afterCheckIconGap;83private int minTextOffset;8485private int leftTextExtraWidth;8687private Rectangle viewRect;8889private RectSize iconSize;90private RectSize textSize;91private RectSize accSize;92private RectSize checkSize;93private RectSize arrowSize;94private RectSize labelSize;9596/**97* The empty protected constructor is necessary for derived classes.98*/99protected MenuItemLayoutHelper() {100}101102public MenuItemLayoutHelper(JMenuItem mi, Icon checkIcon, Icon arrowIcon,103Rectangle viewRect, int gap, String accDelimiter,104boolean isLeftToRight, Font font, Font accFont,105boolean useCheckAndArrow, String propertyPrefix) {106reset(mi, checkIcon, arrowIcon, viewRect, gap, accDelimiter,107isLeftToRight, font, accFont, useCheckAndArrow, propertyPrefix);108}109110protected void reset(JMenuItem mi, Icon checkIcon, Icon arrowIcon,111Rectangle viewRect, int gap, String accDelimiter,112boolean isLeftToRight, Font font, Font accFont,113boolean useCheckAndArrow, String propertyPrefix) {114this.mi = mi;115this.miParent = getMenuItemParent(mi);116this.accText = getAccText(accDelimiter);117this.verticalAlignment = mi.getVerticalAlignment();118this.horizontalAlignment = mi.getHorizontalAlignment();119this.verticalTextPosition = mi.getVerticalTextPosition();120this.horizontalTextPosition = mi.getHorizontalTextPosition();121this.useCheckAndArrow = useCheckAndArrow;122this.font = font;123this.accFont = accFont;124this.fm = mi.getFontMetrics(font);125this.accFm = mi.getFontMetrics(accFont);126this.isLeftToRight = isLeftToRight;127this.isColumnLayout = isColumnLayout(isLeftToRight,128horizontalAlignment, horizontalTextPosition,129verticalTextPosition);130this.isTopLevelMenu = (this.miParent == null) ? true : false;131this.checkIcon = checkIcon;132this.icon = getIcon(propertyPrefix);133this.arrowIcon = arrowIcon;134this.text = mi.getText();135this.gap = gap;136this.afterCheckIconGap = getAfterCheckIconGap(propertyPrefix);137this.minTextOffset = getMinTextOffset(propertyPrefix);138this.htmlView = (View) mi.getClientProperty(BasicHTML.propertyKey);139this.viewRect = viewRect;140141this.iconSize = new RectSize();142this.textSize = new RectSize();143this.accSize = new RectSize();144this.checkSize = new RectSize();145this.arrowSize = new RectSize();146this.labelSize = new RectSize();147calcExtraWidths();148calcWidthsAndHeights();149setOriginalWidths();150calcMaxWidths();151152this.leadingGap = getLeadingGap(propertyPrefix);153calcMaxTextOffset(viewRect);154}155156private void calcExtraWidths() {157leftTextExtraWidth = getLeftExtraWidth(text);158}159160private int getLeftExtraWidth(String str) {161int lsb = SwingUtilities2.getLeftSideBearing(mi, fm, str);162if (lsb < 0) {163return -lsb;164} else {165return 0;166}167}168169private void setOriginalWidths() {170iconSize.origWidth = iconSize.width;171textSize.origWidth = textSize.width;172accSize.origWidth = accSize.width;173checkSize.origWidth = checkSize.width;174arrowSize.origWidth = arrowSize.width;175}176177private String getAccText(String acceleratorDelimiter) {178String accText = "";179KeyStroke accelerator = mi.getAccelerator();180if (accelerator != null) {181int modifiers = accelerator.getModifiers();182if (modifiers > 0) {183accText = KeyEvent.getKeyModifiersText(modifiers);184accText += acceleratorDelimiter;185}186int keyCode = accelerator.getKeyCode();187if (keyCode != 0) {188accText += KeyEvent.getKeyText(keyCode);189} else {190accText += accelerator.getKeyChar();191}192}193return accText;194}195196private Icon getIcon(String propertyPrefix) {197// In case of column layout, .checkIconFactory is defined for this UI,198// the icon is compatible with it and useCheckAndArrow() is true,199// then the icon is handled by the checkIcon.200Icon icon = null;201MenuItemCheckIconFactory iconFactory =202(MenuItemCheckIconFactory) UIManager.get(propertyPrefix203+ ".checkIconFactory");204if (!isColumnLayout || !useCheckAndArrow || iconFactory == null205|| !iconFactory.isCompatible(checkIcon, propertyPrefix)) {206icon = mi.getIcon();207}208return icon;209}210211private int getMinTextOffset(String propertyPrefix) {212int minimumTextOffset = 0;213Object minimumTextOffsetObject =214UIManager.get(propertyPrefix + ".minimumTextOffset");215if (minimumTextOffsetObject instanceof Integer) {216minimumTextOffset = (Integer) minimumTextOffsetObject;217}218return minimumTextOffset;219}220221private int getAfterCheckIconGap(String propertyPrefix) {222int afterCheckIconGap = gap;223Object afterCheckIconGapObject =224UIManager.get(propertyPrefix + ".afterCheckIconGap");225if (afterCheckIconGapObject instanceof Integer) {226afterCheckIconGap = (Integer) afterCheckIconGapObject;227}228return afterCheckIconGap;229}230231private int getLeadingGap(String propertyPrefix) {232if (checkSize.getMaxWidth() > 0) {233return getCheckOffset(propertyPrefix);234} else {235return gap; // There is no any check icon236}237}238239private int getCheckOffset(String propertyPrefix) {240int checkIconOffset = gap;241Object checkIconOffsetObject =242UIManager.get(propertyPrefix + ".checkIconOffset");243if (checkIconOffsetObject instanceof Integer) {244checkIconOffset = (Integer) checkIconOffsetObject;245}246return checkIconOffset;247}248249protected void calcWidthsAndHeights() {250// iconRect251if (icon != null) {252iconSize.width = icon.getIconWidth();253iconSize.height = icon.getIconHeight();254}255256// accRect257if (!accText.equals("")) {258accSize.width = SwingUtilities2.stringWidth(mi, accFm, accText);259accSize.height = accFm.getHeight();260}261262// textRect263if (text == null) {264text = "";265} else if (!text.equals("")) {266if (htmlView != null) {267// Text is HTML268textSize.width =269(int) htmlView.getPreferredSpan(View.X_AXIS);270textSize.height =271(int) htmlView.getPreferredSpan(View.Y_AXIS);272} else {273// Text isn't HTML274textSize.width = SwingUtilities2.stringWidth(mi, fm, text);275textSize.height = fm.getHeight();276}277}278279if (useCheckAndArrow) {280// checkIcon281if (checkIcon != null) {282checkSize.width = checkIcon.getIconWidth();283checkSize.height = checkIcon.getIconHeight();284}285// arrowRect286if (arrowIcon != null) {287arrowSize.width = arrowIcon.getIconWidth();288arrowSize.height = arrowIcon.getIconHeight();289}290}291292// labelRect293if (isColumnLayout) {294labelSize.width = iconSize.width + textSize.width + gap;295labelSize.height = max(checkSize.height, iconSize.height,296textSize.height, accSize.height, arrowSize.height);297} else {298Rectangle textRect = new Rectangle();299Rectangle iconRect = new Rectangle();300SwingUtilities.layoutCompoundLabel(mi, fm, text, icon,301verticalAlignment, horizontalAlignment,302verticalTextPosition, horizontalTextPosition,303viewRect, iconRect, textRect, gap);304textRect.width += leftTextExtraWidth;305Rectangle labelRect = iconRect.union(textRect);306labelSize.height = labelRect.height;307labelSize.width = labelRect.width;308}309}310311protected void calcMaxWidths() {312calcMaxWidth(checkSize, MAX_CHECK_WIDTH);313calcMaxWidth(arrowSize, MAX_ARROW_WIDTH);314calcMaxWidth(accSize, MAX_ACC_WIDTH);315316if (isColumnLayout) {317calcMaxWidth(iconSize, MAX_ICON_WIDTH);318calcMaxWidth(textSize, MAX_TEXT_WIDTH);319int curGap = gap;320if ((iconSize.getMaxWidth() == 0)321|| (textSize.getMaxWidth() == 0)) {322curGap = 0;323}324labelSize.maxWidth =325calcMaxValue(MAX_LABEL_WIDTH, iconSize.maxWidth326+ textSize.maxWidth + curGap);327} else {328// We shouldn't use current icon and text widths329// in maximal widths calculation for complex layout.330iconSize.maxWidth = getParentIntProperty(MAX_ICON_WIDTH);331calcMaxWidth(labelSize, MAX_LABEL_WIDTH);332// If maxLabelWidth is wider333// than the widest icon + the widest text + gap,334// we should update the maximal text witdh335int candidateTextWidth = labelSize.maxWidth - iconSize.maxWidth;336if (iconSize.maxWidth > 0) {337candidateTextWidth -= gap;338}339textSize.maxWidth = calcMaxValue(MAX_TEXT_WIDTH, candidateTextWidth);340}341}342343protected void calcMaxWidth(RectSize rs, Object key) {344rs.maxWidth = calcMaxValue(key, rs.width);345}346347/**348* Calculates and returns maximal value through specified parent component349* client property.350*351* @param propertyName name of the property, which stores the maximal value.352* @param value a value which pretends to be maximal353* @return maximal value among the parent property and the value.354*/355protected int calcMaxValue(Object propertyName, int value) {356// Get maximal value from parent client property357int maxValue = getParentIntProperty(propertyName);358// Store new maximal width in parent client property359if (value > maxValue) {360if (miParent != null) {361miParent.putClientProperty(propertyName, value);362}363return value;364} else {365return maxValue;366}367}368369/**370* Returns parent client property as int.371* @param propertyName name of the parent property.372* @return value of the property as int.373*/374protected int getParentIntProperty(Object propertyName) {375Object value = null;376if (miParent != null) {377value = miParent.getClientProperty(propertyName);378}379if ((value == null) || !(value instanceof Integer)) {380value = 0;381}382return (Integer) value;383}384385public static boolean isColumnLayout(boolean isLeftToRight,386JMenuItem mi) {387assert(mi != null);388return isColumnLayout(isLeftToRight, mi.getHorizontalAlignment(),389mi.getHorizontalTextPosition(), mi.getVerticalTextPosition());390}391392/**393* Answers should we do column layout for a menu item or not.394* We do it when a user doesn't set any alignments395* and text positions manually, except the vertical alignment.396*/397public static boolean isColumnLayout(boolean isLeftToRight,398int horizontalAlignment,399int horizontalTextPosition,400int verticalTextPosition) {401if (verticalTextPosition != SwingConstants.CENTER) {402return false;403}404if (isLeftToRight) {405if (horizontalAlignment != SwingConstants.LEADING406&& horizontalAlignment != SwingConstants.LEFT) {407return false;408}409if (horizontalTextPosition != SwingConstants.TRAILING410&& horizontalTextPosition != SwingConstants.RIGHT) {411return false;412}413} else {414if (horizontalAlignment != SwingConstants.LEADING415&& horizontalAlignment != SwingConstants.RIGHT) {416return false;417}418if (horizontalTextPosition != SwingConstants.TRAILING419&& horizontalTextPosition != SwingConstants.LEFT) {420return false;421}422}423return true;424}425426/**427* Calculates maximal text offset.428* It is required for some L&Fs (ex: Vista L&F).429* The offset is meaningful only for L2R column layout.430*431* @param viewRect the rectangle, the maximal text offset432* will be calculated for.433*/434private void calcMaxTextOffset(Rectangle viewRect) {435if (!isColumnLayout || !isLeftToRight) {436return;437}438439// Calculate the current text offset440int offset = viewRect.x + leadingGap + checkSize.maxWidth441+ afterCheckIconGap + iconSize.maxWidth + gap;442if (checkSize.maxWidth == 0) {443offset -= afterCheckIconGap;444}445if (iconSize.maxWidth == 0) {446offset -= gap;447}448449// maximal text offset shouldn't be less than minimal text offset;450if (offset < minTextOffset) {451offset = minTextOffset;452}453454// Calculate and store the maximal text offset455calcMaxValue(SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET, offset);456}457458/**459* Layout icon, text, check icon, accelerator text and arrow icon460* in the viewRect and return their positions.461*462* If horizontalAlignment, verticalTextPosition and horizontalTextPosition463* are default (user doesn't set any manually) the layouting algorithm is:464* Elements are layouted in the five columns:465* check icon + icon + text + accelerator text + arrow icon466*467* In the other case elements are layouted in the four columns:468* check icon + label + accelerator text + arrow icon469* Label is union of icon and text.470*471* The order of columns can be reversed.472* It depends on the menu item orientation.473*/474public LayoutResult layoutMenuItem() {475LayoutResult lr = createLayoutResult();476prepareForLayout(lr);477478if (isColumnLayout()) {479if (isLeftToRight()) {480doLTRColumnLayout(lr, getLTRColumnAlignment());481} else {482doRTLColumnLayout(lr, getRTLColumnAlignment());483}484} else {485if (isLeftToRight()) {486doLTRComplexLayout(lr, getLTRColumnAlignment());487} else {488doRTLComplexLayout(lr, getRTLColumnAlignment());489}490}491492alignAccCheckAndArrowVertically(lr);493return lr;494}495496private LayoutResult createLayoutResult() {497return new LayoutResult(498new Rectangle(iconSize.width, iconSize.height),499new Rectangle(textSize.width, textSize.height),500new Rectangle(accSize.width, accSize.height),501new Rectangle(checkSize.width, checkSize.height),502new Rectangle(arrowSize.width, arrowSize.height),503new Rectangle(labelSize.width, labelSize.height)504);505}506507public ColumnAlignment getLTRColumnAlignment() {508return ColumnAlignment.LEFT_ALIGNMENT;509}510511public ColumnAlignment getRTLColumnAlignment() {512return ColumnAlignment.RIGHT_ALIGNMENT;513}514515protected void prepareForLayout(LayoutResult lr) {516lr.checkRect.width = checkSize.maxWidth;517lr.accRect.width = accSize.maxWidth;518lr.arrowRect.width = arrowSize.maxWidth;519}520521/**522* Aligns the accelertor text and the check and arrow icons vertically523* with the center of the label rect.524*/525private void alignAccCheckAndArrowVertically(LayoutResult lr) {526lr.accRect.y = (int)(lr.labelRect.y527+ (float)lr.labelRect.height/2528- (float)lr.accRect.height/2);529fixVerticalAlignment(lr, lr.accRect);530if (useCheckAndArrow) {531lr.arrowRect.y = (int)(lr.labelRect.y532+ (float)lr.labelRect.height/2533- (float)lr.arrowRect.height/2);534lr.checkRect.y = (int)(lr.labelRect.y535+ (float)lr.labelRect.height/2536- (float)lr.checkRect.height/2);537fixVerticalAlignment(lr, lr.arrowRect);538fixVerticalAlignment(lr, lr.checkRect);539}540}541542/**543* Fixes vertical alignment of all menu item elements if rect.y544* or (rect.y + rect.height) is out of viewRect bounds545*/546private void fixVerticalAlignment(LayoutResult lr, Rectangle r) {547int delta = 0;548if (r.y < viewRect.y) {549delta = viewRect.y - r.y;550} else if (r.y + r.height > viewRect.y + viewRect.height) {551delta = viewRect.y + viewRect.height - r.y - r.height;552}553if (delta != 0) {554lr.checkRect.y += delta;555lr.iconRect.y += delta;556lr.textRect.y += delta;557lr.accRect.y += delta;558lr.arrowRect.y += delta;559lr.labelRect.y += delta;560}561}562563private void doLTRColumnLayout(LayoutResult lr, ColumnAlignment alignment) {564// Set maximal width for all the five basic rects565// (three other ones are already maximal)566lr.iconRect.width = iconSize.maxWidth;567lr.textRect.width = textSize.maxWidth;568569// Set X coordinates570// All rects will be aligned at the left side571calcXPositionsLTR(viewRect.x, leadingGap, gap, lr.checkRect,572lr.iconRect, lr.textRect);573574// Tune afterCheckIconGap575if (lr.checkRect.width > 0) { // there is the afterCheckIconGap576lr.iconRect.x += afterCheckIconGap - gap;577lr.textRect.x += afterCheckIconGap - gap;578}579580calcXPositionsRTL(viewRect.x + viewRect.width, leadingGap, gap,581lr.arrowRect, lr.accRect);582583// Take into account minimal text offset584int textOffset = lr.textRect.x - viewRect.x;585if (!isTopLevelMenu && (textOffset < minTextOffset)) {586lr.textRect.x += minTextOffset - textOffset;587}588589alignRects(lr, alignment);590591// Set Y coordinate for text and icon.592// Y coordinates for other rects593// will be calculated later in layoutMenuItem.594calcTextAndIconYPositions(lr);595596// Calculate valid X and Y coordinates for labelRect597lr.setLabelRect(lr.textRect.union(lr.iconRect));598}599600private void doLTRComplexLayout(LayoutResult lr, ColumnAlignment alignment) {601lr.labelRect.width = labelSize.maxWidth;602603// Set X coordinates604calcXPositionsLTR(viewRect.x, leadingGap, gap, lr.checkRect,605lr.labelRect);606607// Tune afterCheckIconGap608if (lr.checkRect.width > 0) { // there is the afterCheckIconGap609lr.labelRect.x += afterCheckIconGap - gap;610}611612calcXPositionsRTL(viewRect.x + viewRect.width,613leadingGap, gap, lr.arrowRect, lr.accRect);614615// Take into account minimal text offset616int labelOffset = lr.labelRect.x - viewRect.x;617if (!isTopLevelMenu && (labelOffset < minTextOffset)) {618lr.labelRect.x += minTextOffset - labelOffset;619}620621alignRects(lr, alignment);622623// Center labelRect vertically624calcLabelYPosition(lr);625626layoutIconAndTextInLabelRect(lr);627}628629private void doRTLColumnLayout(LayoutResult lr, ColumnAlignment alignment) {630// Set maximal width for all the five basic rects631// (three other ones are already maximal)632lr.iconRect.width = iconSize.maxWidth;633lr.textRect.width = textSize.maxWidth;634635// Set X coordinates636calcXPositionsRTL(viewRect.x + viewRect.width, leadingGap, gap,637lr.checkRect, lr.iconRect, lr.textRect);638639// Tune the gap after check icon640if (lr.checkRect.width > 0) { // there is the gap after check icon641lr.iconRect.x -= afterCheckIconGap - gap;642lr.textRect.x -= afterCheckIconGap - gap;643}644645calcXPositionsLTR(viewRect.x, leadingGap, gap, lr.arrowRect,646lr.accRect);647648// Take into account minimal text offset649int textOffset = (viewRect.x + viewRect.width)650- (lr.textRect.x + lr.textRect.width);651if (!isTopLevelMenu && (textOffset < minTextOffset)) {652lr.textRect.x -= minTextOffset - textOffset;653}654655alignRects(lr, alignment);656657// Set Y coordinates for text and icon.658// Y coordinates for other rects659// will be calculated later in layoutMenuItem.660calcTextAndIconYPositions(lr);661662// Calculate valid X and Y coordinate for labelRect663lr.setLabelRect(lr.textRect.union(lr.iconRect));664}665666private void doRTLComplexLayout(LayoutResult lr, ColumnAlignment alignment) {667lr.labelRect.width = labelSize.maxWidth;668669// Set X coordinates670calcXPositionsRTL(viewRect.x + viewRect.width, leadingGap, gap,671lr.checkRect, lr.labelRect);672673// Tune the gap after check icon674if (lr.checkRect.width > 0) { // there is the gap after check icon675lr.labelRect.x -= afterCheckIconGap - gap;676}677678calcXPositionsLTR(viewRect.x, leadingGap, gap, lr.arrowRect, lr.accRect);679680// Take into account minimal text offset681int labelOffset = (viewRect.x + viewRect.width)682- (lr.labelRect.x + lr.labelRect.width);683if (!isTopLevelMenu && (labelOffset < minTextOffset)) {684lr.labelRect.x -= minTextOffset - labelOffset;685}686687alignRects(lr, alignment);688689// Center labelRect vertically690calcLabelYPosition(lr);691692layoutIconAndTextInLabelRect(lr);693}694695private void alignRects(LayoutResult lr, ColumnAlignment alignment) {696alignRect(lr.checkRect, alignment.getCheckAlignment(),697checkSize.getOrigWidth());698alignRect(lr.iconRect, alignment.getIconAlignment(),699iconSize.getOrigWidth());700alignRect(lr.textRect, alignment.getTextAlignment(),701textSize.getOrigWidth());702alignRect(lr.accRect, alignment.getAccAlignment(),703accSize.getOrigWidth());704alignRect(lr.arrowRect, alignment.getArrowAlignment(),705arrowSize.getOrigWidth());706}707708private void alignRect(Rectangle rect, int alignment, int origWidth) {709if (alignment == SwingConstants.RIGHT) {710rect.x = rect.x + rect.width - origWidth;711}712rect.width = origWidth;713}714715protected void layoutIconAndTextInLabelRect(LayoutResult lr) {716lr.setTextRect(new Rectangle());717lr.setIconRect(new Rectangle());718SwingUtilities.layoutCompoundLabel(719mi, fm, text,icon, verticalAlignment, horizontalAlignment,720verticalTextPosition, horizontalTextPosition, lr.labelRect,721lr.iconRect, lr.textRect, gap);722}723724private void calcXPositionsLTR(int startXPos, int leadingGap,725int gap, Rectangle... rects) {726int curXPos = startXPos + leadingGap;727for (Rectangle rect : rects) {728rect.x = curXPos;729if (rect.width > 0) {730curXPos += rect.width + gap;731}732}733}734735private void calcXPositionsRTL(int startXPos, int leadingGap,736int gap, Rectangle... rects) {737int curXPos = startXPos - leadingGap;738for (Rectangle rect : rects) {739rect.x = curXPos - rect.width;740if (rect.width > 0) {741curXPos -= rect.width + gap;742}743}744}745746/**747* Sets Y coordinates of text and icon748* taking into account the vertical alignment749*/750private void calcTextAndIconYPositions(LayoutResult lr) {751if (verticalAlignment == SwingUtilities.TOP) {752lr.textRect.y = (int)(viewRect.y753+ (float)lr.labelRect.height/2754- (float)lr.textRect.height/2);755lr.iconRect.y = (int)(viewRect.y756+ (float)lr.labelRect.height/2757- (float)lr.iconRect.height/2);758} else if (verticalAlignment == SwingUtilities.CENTER) {759lr.textRect.y = (int)(viewRect.y760+ (float)viewRect.height/2761- (float)lr.textRect.height/2);762lr.iconRect.y = (int)(viewRect.y763+ (float)viewRect.height/2764- (float)lr.iconRect.height/2);765}766else if (verticalAlignment == SwingUtilities.BOTTOM) {767lr.textRect.y = (int)(viewRect.y768+ viewRect.height769- (float)lr.labelRect.height/2770- (float)lr.textRect.height/2);771lr.iconRect.y = (int)(viewRect.y772+ viewRect.height773- (float)lr.labelRect.height/2774- (float)lr.iconRect.height/2);775}776}777778/**779* Sets labelRect Y coordinate780* taking into account the vertical alignment781*/782private void calcLabelYPosition(LayoutResult lr) {783if (verticalAlignment == SwingUtilities.TOP) {784lr.labelRect.y = viewRect.y;785} else if (verticalAlignment == SwingUtilities.CENTER) {786lr.labelRect.y = (int)(viewRect.y787+ (float)viewRect.height/2788- (float)lr.labelRect.height/2);789} else if (verticalAlignment == SwingUtilities.BOTTOM) {790lr.labelRect.y = viewRect.y + viewRect.height791- lr.labelRect.height;792}793}794795/**796* Returns parent of this component if it is not a top-level menu797* Otherwise returns null.798* @param menuItem the menu item whose parent will be returned.799* @return parent of this component if it is not a top-level menu800* Otherwise returns null.801*/802public static JComponent getMenuItemParent(JMenuItem menuItem) {803Container parent = menuItem.getParent();804if ((parent instanceof JComponent) &&805(!(menuItem instanceof JMenu) ||806!((JMenu)menuItem).isTopLevelMenu())) {807return (JComponent) parent;808} else {809return null;810}811}812813public static void clearUsedParentClientProperties(JMenuItem menuItem) {814clearUsedClientProperties(getMenuItemParent(menuItem));815}816817public static void clearUsedClientProperties(JComponent c) {818if (c != null) {819c.putClientProperty(MAX_ARROW_WIDTH, null);820c.putClientProperty(MAX_CHECK_WIDTH, null);821c.putClientProperty(MAX_ACC_WIDTH, null);822c.putClientProperty(MAX_TEXT_WIDTH, null);823c.putClientProperty(MAX_ICON_WIDTH, null);824c.putClientProperty(MAX_LABEL_WIDTH, null);825c.putClientProperty(BASICMENUITEMUI_MAX_TEXT_OFFSET, null);826}827}828829/**830* Finds and returns maximal integer value in the given array.831* @param values array where the search will be performed.832* @return maximal vaule.833*/834public static int max(int... values) {835int maxValue = Integer.MIN_VALUE;836for (int i : values) {837if (i > maxValue) {838maxValue = i;839}840}841return maxValue;842}843844public static Rectangle createMaxRect() {845return new Rectangle(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);846}847848public static void addMaxWidth(RectSize size, int gap, Dimension result) {849if (size.maxWidth > 0) {850result.width += size.maxWidth + gap;851}852}853854public static void addWidth(int width, int gap, Dimension result) {855if (width > 0) {856result.width += width + gap;857}858}859860public JMenuItem getMenuItem() {861return mi;862}863864public JComponent getMenuItemParent() {865return miParent;866}867868public Font getFont() {869return font;870}871872public Font getAccFont() {873return accFont;874}875876public FontMetrics getFontMetrics() {877return fm;878}879880public FontMetrics getAccFontMetrics() {881return accFm;882}883884public Icon getIcon() {885return icon;886}887888public Icon getCheckIcon() {889return checkIcon;890}891892public Icon getArrowIcon() {893return arrowIcon;894}895896public String getText() {897return text;898}899900public String getAccText() {901return accText;902}903904public boolean isColumnLayout() {905return isColumnLayout;906}907908public boolean useCheckAndArrow() {909return useCheckAndArrow;910}911912public boolean isLeftToRight() {913return isLeftToRight;914}915916public boolean isTopLevelMenu() {917return isTopLevelMenu;918}919920public View getHtmlView() {921return htmlView;922}923924public int getVerticalAlignment() {925return verticalAlignment;926}927928public int getHorizontalAlignment() {929return horizontalAlignment;930}931932public int getVerticalTextPosition() {933return verticalTextPosition;934}935936public int getHorizontalTextPosition() {937return horizontalTextPosition;938}939940public int getGap() {941return gap;942}943944public int getLeadingGap() {945return leadingGap;946}947948public int getAfterCheckIconGap() {949return afterCheckIconGap;950}951952public int getMinTextOffset() {953return minTextOffset;954}955956public Rectangle getViewRect() {957return viewRect;958}959960public RectSize getIconSize() {961return iconSize;962}963964public RectSize getTextSize() {965return textSize;966}967968public RectSize getAccSize() {969return accSize;970}971972public RectSize getCheckSize() {973return checkSize;974}975976public RectSize getArrowSize() {977return arrowSize;978}979980public RectSize getLabelSize() {981return labelSize;982}983984protected void setMenuItem(JMenuItem mi) {985this.mi = mi;986}987988protected void setMenuItemParent(JComponent miParent) {989this.miParent = miParent;990}991992protected void setFont(Font font) {993this.font = font;994}995996protected void setAccFont(Font accFont) {997this.accFont = accFont;998}9991000protected void setFontMetrics(FontMetrics fm) {1001this.fm = fm;1002}10031004protected void setAccFontMetrics(FontMetrics accFm) {1005this.accFm = accFm;1006}10071008protected void setIcon(Icon icon) {1009this.icon = icon;1010}10111012protected void setCheckIcon(Icon checkIcon) {1013this.checkIcon = checkIcon;1014}10151016protected void setArrowIcon(Icon arrowIcon) {1017this.arrowIcon = arrowIcon;1018}10191020protected void setText(String text) {1021this.text = text;1022}10231024protected void setAccText(String accText) {1025this.accText = accText;1026}10271028protected void setColumnLayout(boolean columnLayout) {1029isColumnLayout = columnLayout;1030}10311032protected void setUseCheckAndArrow(boolean useCheckAndArrow) {1033this.useCheckAndArrow = useCheckAndArrow;1034}10351036protected void setLeftToRight(boolean leftToRight) {1037isLeftToRight = leftToRight;1038}10391040protected void setTopLevelMenu(boolean topLevelMenu) {1041isTopLevelMenu = topLevelMenu;1042}10431044protected void setHtmlView(View htmlView) {1045this.htmlView = htmlView;1046}10471048protected void setVerticalAlignment(int verticalAlignment) {1049this.verticalAlignment = verticalAlignment;1050}10511052protected void setHorizontalAlignment(int horizontalAlignment) {1053this.horizontalAlignment = horizontalAlignment;1054}10551056protected void setVerticalTextPosition(int verticalTextPosition) {1057this.verticalTextPosition = verticalTextPosition;1058}10591060protected void setHorizontalTextPosition(int horizontalTextPosition) {1061this.horizontalTextPosition = horizontalTextPosition;1062}10631064protected void setGap(int gap) {1065this.gap = gap;1066}10671068protected void setLeadingGap(int leadingGap) {1069this.leadingGap = leadingGap;1070}10711072protected void setAfterCheckIconGap(int afterCheckIconGap) {1073this.afterCheckIconGap = afterCheckIconGap;1074}10751076protected void setMinTextOffset(int minTextOffset) {1077this.minTextOffset = minTextOffset;1078}10791080protected void setViewRect(Rectangle viewRect) {1081this.viewRect = viewRect;1082}10831084protected void setIconSize(RectSize iconSize) {1085this.iconSize = iconSize;1086}10871088protected void setTextSize(RectSize textSize) {1089this.textSize = textSize;1090}10911092protected void setAccSize(RectSize accSize) {1093this.accSize = accSize;1094}10951096protected void setCheckSize(RectSize checkSize) {1097this.checkSize = checkSize;1098}10991100protected void setArrowSize(RectSize arrowSize) {1101this.arrowSize = arrowSize;1102}11031104protected void setLabelSize(RectSize labelSize) {1105this.labelSize = labelSize;1106}11071108public int getLeftTextExtraWidth() {1109return leftTextExtraWidth;1110}11111112/**1113* Returns false if the component is a JMenu and it is a top1114* level menu (on the menubar).1115*/1116public static boolean useCheckAndArrow(JMenuItem menuItem) {1117boolean b = true;1118if ((menuItem instanceof JMenu) &&1119(((JMenu) menuItem).isTopLevelMenu())) {1120b = false;1121}1122return b;1123}11241125public static class LayoutResult {1126private Rectangle iconRect;1127private Rectangle textRect;1128private Rectangle accRect;1129private Rectangle checkRect;1130private Rectangle arrowRect;1131private Rectangle labelRect;11321133public LayoutResult() {1134iconRect = new Rectangle();1135textRect = new Rectangle();1136accRect = new Rectangle();1137checkRect = new Rectangle();1138arrowRect = new Rectangle();1139labelRect = new Rectangle();1140}11411142public LayoutResult(Rectangle iconRect, Rectangle textRect,1143Rectangle accRect, Rectangle checkRect,1144Rectangle arrowRect, Rectangle labelRect) {1145this.iconRect = iconRect;1146this.textRect = textRect;1147this.accRect = accRect;1148this.checkRect = checkRect;1149this.arrowRect = arrowRect;1150this.labelRect = labelRect;1151}11521153public Rectangle getIconRect() {1154return iconRect;1155}11561157public void setIconRect(Rectangle iconRect) {1158this.iconRect = iconRect;1159}11601161public Rectangle getTextRect() {1162return textRect;1163}11641165public void setTextRect(Rectangle textRect) {1166this.textRect = textRect;1167}11681169public Rectangle getAccRect() {1170return accRect;1171}11721173public void setAccRect(Rectangle accRect) {1174this.accRect = accRect;1175}11761177public Rectangle getCheckRect() {1178return checkRect;1179}11801181public void setCheckRect(Rectangle checkRect) {1182this.checkRect = checkRect;1183}11841185public Rectangle getArrowRect() {1186return arrowRect;1187}11881189public void setArrowRect(Rectangle arrowRect) {1190this.arrowRect = arrowRect;1191}11921193public Rectangle getLabelRect() {1194return labelRect;1195}11961197public void setLabelRect(Rectangle labelRect) {1198this.labelRect = labelRect;1199}12001201public Map<String, Rectangle> getAllRects() {1202Map<String, Rectangle> result = new HashMap<String, Rectangle>();1203result.put("checkRect", checkRect);1204result.put("iconRect", iconRect);1205result.put("textRect", textRect);1206result.put("accRect", accRect);1207result.put("arrowRect", arrowRect);1208result.put("labelRect", labelRect);1209return result;1210}1211}12121213public static class ColumnAlignment {1214private int checkAlignment;1215private int iconAlignment;1216private int textAlignment;1217private int accAlignment;1218private int arrowAlignment;12191220public static final ColumnAlignment LEFT_ALIGNMENT =1221new ColumnAlignment(1222SwingConstants.LEFT,1223SwingConstants.LEFT,1224SwingConstants.LEFT,1225SwingConstants.LEFT,1226SwingConstants.LEFT1227);12281229public static final ColumnAlignment RIGHT_ALIGNMENT =1230new ColumnAlignment(1231SwingConstants.RIGHT,1232SwingConstants.RIGHT,1233SwingConstants.RIGHT,1234SwingConstants.RIGHT,1235SwingConstants.RIGHT1236);12371238public ColumnAlignment(int checkAlignment, int iconAlignment,1239int textAlignment, int accAlignment,1240int arrowAlignment) {1241this.checkAlignment = checkAlignment;1242this.iconAlignment = iconAlignment;1243this.textAlignment = textAlignment;1244this.accAlignment = accAlignment;1245this.arrowAlignment = arrowAlignment;1246}12471248public int getCheckAlignment() {1249return checkAlignment;1250}12511252public int getIconAlignment() {1253return iconAlignment;1254}12551256public int getTextAlignment() {1257return textAlignment;1258}12591260public int getAccAlignment() {1261return accAlignment;1262}12631264public int getArrowAlignment() {1265return arrowAlignment;1266}1267}12681269public static class RectSize {1270private int width;1271private int height;1272private int origWidth;1273private int maxWidth;12741275public RectSize() {1276}12771278public RectSize(int width, int height, int origWidth, int maxWidth) {1279this.width = width;1280this.height = height;1281this.origWidth = origWidth;1282this.maxWidth = maxWidth;1283}12841285public int getWidth() {1286return width;1287}12881289public int getHeight() {1290return height;1291}12921293public int getOrigWidth() {1294return origWidth;1295}12961297public int getMaxWidth() {1298return maxWidth;1299}13001301public void setWidth(int width) {1302this.width = width;1303}13041305public void setHeight(int height) {1306this.height = height;1307}13081309public void setOrigWidth(int origWidth) {1310this.origWidth = origWidth;1311}13121313public void setMaxWidth(int maxWidth) {1314this.maxWidth = maxWidth;1315}13161317public String toString() {1318return "[w=" + width + ",h=" + height + ",ow="1319+ origWidth + ",mw=" + maxWidth + "]";1320}1321}1322}132313241325