1 /* 2 * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.swing.plaf.synth; 27 28 import sun.swing.StringUIClientPropertyKey; 29 import sun.swing.MenuItemLayoutHelper; 30 31 import javax.swing.*; 32 import javax.swing.text.View; 33 import java.awt.*; 34 35 /** 36 * Calculates preferred size and layouts synth menu items. 37 * 38 * All JMenuItems (and JMenus) include enough space for the insets 39 * plus one or more elements. When we say "label" below, we mean 40 * "icon and/or text." 41 * 42 * Cases to consider for SynthMenuItemUI (visualized here in a 43 * LTR orientation; the RTL case would be reversed): 44 * label 45 * check icon + label 46 * check icon + label + accelerator 47 * label + accelerator 48 * 49 * Cases to consider for SynthMenuUI (again visualized here in a 50 * LTR orientation): 51 * label + arrow 52 * 53 * Note that in the above scenarios, accelerator and arrow icon are 54 * mutually exclusive. This means that if a popup menu contains a mix 55 * of JMenus and JMenuItems, we only need to allow enough space for 56 * max(maxAccelerator, maxArrow), and both accelerators and arrow icons 57 * can occupy the same "column" of space in the menu. 58 */ 59 class SynthMenuItemLayoutHelper extends MenuItemLayoutHelper { 60 61 public static final StringUIClientPropertyKey MAX_ACC_OR_ARROW_WIDTH = 62 new StringUIClientPropertyKey("maxAccOrArrowWidth"); 63 64 public static final ColumnAlignment LTR_ALIGNMENT_1 = 65 new ColumnAlignment( 66 SwingConstants.LEFT, 67 SwingConstants.LEFT, 68 SwingConstants.LEFT, 69 SwingConstants.RIGHT, 70 SwingConstants.RIGHT 71 ); 72 public static final ColumnAlignment LTR_ALIGNMENT_2 = 73 new ColumnAlignment( 74 SwingConstants.LEFT, 75 SwingConstants.LEFT, 76 SwingConstants.LEFT, 77 SwingConstants.LEFT, 78 SwingConstants.RIGHT 79 ); 80 public static final ColumnAlignment RTL_ALIGNMENT_1 = 81 new ColumnAlignment( 82 SwingConstants.RIGHT, 83 SwingConstants.RIGHT, 84 SwingConstants.RIGHT, 85 SwingConstants.LEFT, 86 SwingConstants.LEFT 87 ); 88 public static final ColumnAlignment RTL_ALIGNMENT_2 = 89 new ColumnAlignment( 90 SwingConstants.RIGHT, 91 SwingConstants.RIGHT, 92 SwingConstants.RIGHT, 93 SwingConstants.RIGHT, 94 SwingConstants.LEFT 95 ); 96 97 private SynthContext context; 98 private SynthContext accContext; 99 private SynthStyle style; 100 private SynthStyle accStyle; 101 private SynthGraphicsUtils gu; 102 private SynthGraphicsUtils accGu; 103 private boolean alignAcceleratorText; 104 private int maxAccOrArrowWidth; 105 SynthMenuItemLayoutHelper(SynthContext context, SynthContext accContext, JMenuItem mi, Icon checkIcon, Icon arrowIcon, Rectangle viewRect, int gap, String accDelimiter, boolean isLeftToRight, boolean useCheckAndArrow, String propertyPrefix)106 public SynthMenuItemLayoutHelper(SynthContext context, SynthContext accContext, 107 JMenuItem mi, Icon checkIcon, Icon arrowIcon, 108 Rectangle viewRect, int gap, String accDelimiter, 109 boolean isLeftToRight, boolean useCheckAndArrow, 110 String propertyPrefix) { 111 this.context = context; 112 this.accContext = accContext; 113 this.style = context.getStyle(); 114 this.accStyle = accContext.getStyle(); 115 this.gu = style.getGraphicsUtils(context); 116 this.accGu = accStyle.getGraphicsUtils(accContext); 117 this.alignAcceleratorText = getAlignAcceleratorText(propertyPrefix); 118 reset(mi, checkIcon, arrowIcon, viewRect, gap, accDelimiter, 119 isLeftToRight, style.getFont(context), accStyle.getFont(accContext), 120 useCheckAndArrow, propertyPrefix); 121 setLeadingGap(0); 122 } 123 getAlignAcceleratorText(String propertyPrefix)124 private boolean getAlignAcceleratorText(String propertyPrefix) { 125 return style.getBoolean(context, 126 propertyPrefix + ".alignAcceleratorText", true); 127 } 128 calcWidthsAndHeights()129 protected void calcWidthsAndHeights() { 130 // iconRect 131 if (getIcon() != null) { 132 getIconSize().setWidth(SynthGraphicsUtils.getIconWidth(getIcon(), context)); 133 getIconSize().setHeight(SynthGraphicsUtils.getIconHeight(getIcon(), context)); 134 } 135 136 // accRect 137 if (!getAccText().equals("")) { 138 getAccSize().setWidth(accGu.computeStringWidth(getAccContext(), 139 getAccFontMetrics().getFont(), getAccFontMetrics(), 140 getAccText())); 141 getAccSize().setHeight(getAccFontMetrics().getHeight()); 142 } 143 144 // textRect 145 if (getText() == null) { 146 setText(""); 147 } else if (!getText().equals("")) { 148 if (getHtmlView() != null) { 149 // Text is HTML 150 getTextSize().setWidth( 151 (int) getHtmlView().getPreferredSpan(View.X_AXIS)); 152 getTextSize().setHeight( 153 (int) getHtmlView().getPreferredSpan(View.Y_AXIS)); 154 } else { 155 // Text isn't HTML 156 getTextSize().setWidth(gu.computeStringWidth(context, 157 getFontMetrics().getFont(), getFontMetrics(), 158 getText())); 159 getTextSize().setHeight(getFontMetrics().getHeight()); 160 } 161 } 162 163 if (useCheckAndArrow()) { 164 // checkIcon 165 if (getCheckIcon() != null) { 166 getCheckSize().setWidth( 167 SynthGraphicsUtils.getIconWidth(getCheckIcon(), context)); 168 getCheckSize().setHeight( 169 SynthGraphicsUtils.getIconHeight(getCheckIcon(), context)); 170 } 171 // arrowRect 172 if (getArrowIcon() != null) { 173 getArrowSize().setWidth( 174 SynthGraphicsUtils.getIconWidth(getArrowIcon(), context)); 175 getArrowSize().setHeight( 176 SynthGraphicsUtils.getIconHeight(getArrowIcon(), context)); 177 } 178 } 179 180 // labelRect 181 if (isColumnLayout()) { 182 getLabelSize().setWidth(getIconSize().getWidth() 183 + getTextSize().getWidth() + getGap()); 184 getLabelSize().setHeight(MenuItemLayoutHelper.max( 185 getCheckSize().getHeight(), 186 getIconSize().getHeight(), 187 getTextSize().getHeight(), 188 getAccSize().getHeight(), 189 getArrowSize().getHeight())); 190 } else { 191 Rectangle textRect = new Rectangle(); 192 Rectangle iconRect = new Rectangle(); 193 gu.layoutText(context, getFontMetrics(), getText(), getIcon(), 194 getHorizontalAlignment(), getVerticalAlignment(), 195 getHorizontalTextPosition(), getVerticalTextPosition(), 196 getViewRect(), iconRect, textRect, getGap()); 197 textRect.width += getLeftTextExtraWidth(); 198 Rectangle labelRect = iconRect.union(textRect); 199 getLabelSize().setHeight(labelRect.height); 200 getLabelSize().setWidth(labelRect.width); 201 } 202 } 203 calcMaxWidths()204 protected void calcMaxWidths() { 205 calcMaxWidth(getCheckSize(), MAX_CHECK_WIDTH); 206 maxAccOrArrowWidth = 207 calcMaxValue(MAX_ACC_OR_ARROW_WIDTH, getArrowSize().getWidth()); 208 maxAccOrArrowWidth = 209 calcMaxValue(MAX_ACC_OR_ARROW_WIDTH, getAccSize().getWidth()); 210 211 if (isColumnLayout()) { 212 calcMaxWidth(getIconSize(), MAX_ICON_WIDTH); 213 calcMaxWidth(getTextSize(), MAX_TEXT_WIDTH); 214 int curGap = getGap(); 215 if ((getIconSize().getMaxWidth() == 0) 216 || (getTextSize().getMaxWidth() == 0)) { 217 curGap = 0; 218 } 219 getLabelSize().setMaxWidth( 220 calcMaxValue(MAX_LABEL_WIDTH, getIconSize().getMaxWidth() 221 + getTextSize().getMaxWidth() + curGap)); 222 } else { 223 // We shouldn't use current icon and text widths 224 // in maximal widths calculation for complex layout. 225 getIconSize().setMaxWidth(getParentIntProperty( 226 MAX_ICON_WIDTH)); 227 calcMaxWidth(getLabelSize(), MAX_LABEL_WIDTH); 228 // If maxLabelWidth is wider 229 // than the widest icon + the widest text + gap, 230 // we should update the maximal text witdh 231 int candidateTextWidth = getLabelSize().getMaxWidth() - 232 getIconSize().getMaxWidth(); 233 if (getIconSize().getMaxWidth() > 0) { 234 candidateTextWidth -= getGap(); 235 } 236 getTextSize().setMaxWidth(calcMaxValue( 237 MAX_TEXT_WIDTH, candidateTextWidth)); 238 } 239 } 240 getContext()241 public SynthContext getContext() { 242 return context; 243 } 244 getAccContext()245 public SynthContext getAccContext() { 246 return accContext; 247 } 248 getStyle()249 public SynthStyle getStyle() { 250 return style; 251 } 252 getAccStyle()253 public SynthStyle getAccStyle() { 254 return accStyle; 255 } 256 getGraphicsUtils()257 public SynthGraphicsUtils getGraphicsUtils() { 258 return gu; 259 } 260 getAccGraphicsUtils()261 public SynthGraphicsUtils getAccGraphicsUtils() { 262 return accGu; 263 } 264 alignAcceleratorText()265 public boolean alignAcceleratorText() { 266 return alignAcceleratorText; 267 } 268 getMaxAccOrArrowWidth()269 public int getMaxAccOrArrowWidth() { 270 return maxAccOrArrowWidth; 271 } 272 prepareForLayout(LayoutResult lr)273 protected void prepareForLayout(LayoutResult lr) { 274 lr.getCheckRect().width = getCheckSize().getMaxWidth(); 275 // An item can have an arrow or a check icon at once 276 if (useCheckAndArrow() && (!"".equals(getAccText()))) { 277 lr.getAccRect().width = maxAccOrArrowWidth; 278 } else { 279 lr.getArrowRect().width = maxAccOrArrowWidth; 280 } 281 } 282 getLTRColumnAlignment()283 public ColumnAlignment getLTRColumnAlignment() { 284 if (alignAcceleratorText()) { 285 return LTR_ALIGNMENT_2; 286 } else { 287 return LTR_ALIGNMENT_1; 288 } 289 } 290 getRTLColumnAlignment()291 public ColumnAlignment getRTLColumnAlignment() { 292 if (alignAcceleratorText()) { 293 return RTL_ALIGNMENT_2; 294 } else { 295 return RTL_ALIGNMENT_1; 296 } 297 } 298 layoutIconAndTextInLabelRect(LayoutResult lr)299 protected void layoutIconAndTextInLabelRect(LayoutResult lr) { 300 lr.setTextRect(new Rectangle()); 301 lr.setIconRect(new Rectangle()); 302 gu.layoutText(context, getFontMetrics(), getText(), getIcon(), 303 getHorizontalAlignment(), getVerticalAlignment(), 304 getHorizontalTextPosition(), getVerticalTextPosition(), 305 lr.getLabelRect(), lr.getIconRect(), lr.getTextRect(), getGap()); 306 } 307 } 308