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 import sun.swing.plaf.synth.SynthIcon; 31 32 import javax.swing.*; 33 import javax.swing.text.View; 34 import java.awt.*; 35 36 /** 37 * Calculates preferred size and layouts synth menu items. 38 * 39 * All JMenuItems (and JMenus) include enough space for the insets 40 * plus one or more elements. When we say "label" below, we mean 41 * "icon and/or text." 42 * 43 * Cases to consider for SynthMenuItemUI (visualized here in a 44 * LTR orientation; the RTL case would be reversed): 45 * label 46 * check icon + label 47 * check icon + label + accelerator 48 * label + accelerator 49 * 50 * Cases to consider for SynthMenuUI (again visualized here in a 51 * LTR orientation): 52 * label + arrow 53 * 54 * Note that in the above scenarios, accelerator and arrow icon are 55 * mutually exclusive. This means that if a popup menu contains a mix 56 * of JMenus and JMenuItems, we only need to allow enough space for 57 * max(maxAccelerator, maxArrow), and both accelerators and arrow icons 58 * can occupy the same "column" of space in the menu. 59 */ 60 class SynthMenuItemLayoutHelper extends MenuItemLayoutHelper { 61 62 public static final StringUIClientPropertyKey MAX_ACC_OR_ARROW_WIDTH = 63 new StringUIClientPropertyKey("maxAccOrArrowWidth"); 64 65 public static final ColumnAlignment LTR_ALIGNMENT_1 = 66 new ColumnAlignment( 67 SwingConstants.LEFT, 68 SwingConstants.LEFT, 69 SwingConstants.LEFT, 70 SwingConstants.RIGHT, 71 SwingConstants.RIGHT 72 ); 73 public static final ColumnAlignment LTR_ALIGNMENT_2 = 74 new ColumnAlignment( 75 SwingConstants.LEFT, 76 SwingConstants.LEFT, 77 SwingConstants.LEFT, 78 SwingConstants.LEFT, 79 SwingConstants.RIGHT 80 ); 81 public static final ColumnAlignment RTL_ALIGNMENT_1 = 82 new ColumnAlignment( 83 SwingConstants.RIGHT, 84 SwingConstants.RIGHT, 85 SwingConstants.RIGHT, 86 SwingConstants.LEFT, 87 SwingConstants.LEFT 88 ); 89 public static final ColumnAlignment RTL_ALIGNMENT_2 = 90 new ColumnAlignment( 91 SwingConstants.RIGHT, 92 SwingConstants.RIGHT, 93 SwingConstants.RIGHT, 94 SwingConstants.RIGHT, 95 SwingConstants.LEFT 96 ); 97 98 private SynthContext context; 99 private SynthContext accContext; 100 private SynthStyle style; 101 private SynthStyle accStyle; 102 private SynthGraphicsUtils gu; 103 private SynthGraphicsUtils accGu; 104 private boolean alignAcceleratorText; 105 private int maxAccOrArrowWidth; 106 SynthMenuItemLayoutHelper(SynthContext context, SynthContext accContext, JMenuItem mi, Icon checkIcon, Icon arrowIcon, Rectangle viewRect, int gap, String accDelimiter, boolean isLeftToRight, boolean useCheckAndArrow, String propertyPrefix)107 public SynthMenuItemLayoutHelper(SynthContext context, SynthContext accContext, 108 JMenuItem mi, Icon checkIcon, Icon arrowIcon, 109 Rectangle viewRect, int gap, String accDelimiter, 110 boolean isLeftToRight, boolean useCheckAndArrow, 111 String propertyPrefix) { 112 this.context = context; 113 this.accContext = accContext; 114 this.style = context.getStyle(); 115 this.accStyle = accContext.getStyle(); 116 this.gu = style.getGraphicsUtils(context); 117 this.accGu = accStyle.getGraphicsUtils(accContext); 118 this.alignAcceleratorText = getAlignAcceleratorText(propertyPrefix); 119 reset(mi, checkIcon, arrowIcon, viewRect, gap, accDelimiter, 120 isLeftToRight, style.getFont(context), accStyle.getFont(accContext), 121 useCheckAndArrow, propertyPrefix); 122 setLeadingGap(0); 123 } 124 getAlignAcceleratorText(String propertyPrefix)125 private boolean getAlignAcceleratorText(String propertyPrefix) { 126 return style.getBoolean(context, 127 propertyPrefix + ".alignAcceleratorText", true); 128 } 129 calcWidthsAndHeights()130 protected void calcWidthsAndHeights() { 131 // iconRect 132 if (getIcon() != null) { 133 getIconSize().setWidth(SynthIcon.getIconWidth(getIcon(), context)); 134 getIconSize().setHeight(SynthIcon.getIconHeight(getIcon(), context)); 135 } 136 137 // accRect 138 if (!getAccText().equals("")) { 139 getAccSize().setWidth(accGu.computeStringWidth(getAccContext(), 140 getAccFontMetrics().getFont(), getAccFontMetrics(), 141 getAccText())); 142 getAccSize().setHeight(getAccFontMetrics().getHeight()); 143 } 144 145 // textRect 146 if (getText() == null) { 147 setText(""); 148 } else if (!getText().equals("")) { 149 if (getHtmlView() != null) { 150 // Text is HTML 151 getTextSize().setWidth( 152 (int) getHtmlView().getPreferredSpan(View.X_AXIS)); 153 getTextSize().setHeight( 154 (int) getHtmlView().getPreferredSpan(View.Y_AXIS)); 155 } else { 156 // Text isn't HTML 157 getTextSize().setWidth(gu.computeStringWidth(context, 158 getFontMetrics().getFont(), getFontMetrics(), 159 getText())); 160 getTextSize().setHeight(getFontMetrics().getHeight()); 161 } 162 } 163 164 if (useCheckAndArrow()) { 165 // checkIcon 166 if (getCheckIcon() != null) { 167 getCheckSize().setWidth( 168 SynthIcon.getIconWidth(getCheckIcon(), context)); 169 getCheckSize().setHeight( 170 SynthIcon.getIconHeight(getCheckIcon(), context)); 171 } 172 // arrowRect 173 if (getArrowIcon() != null) { 174 getArrowSize().setWidth( 175 SynthIcon.getIconWidth(getArrowIcon(), context)); 176 getArrowSize().setHeight( 177 SynthIcon.getIconHeight(getArrowIcon(), context)); 178 } 179 } 180 181 // labelRect 182 if (isColumnLayout()) { 183 getLabelSize().setWidth(getIconSize().getWidth() 184 + getTextSize().getWidth() + getGap()); 185 getLabelSize().setHeight(MenuItemLayoutHelper.max( 186 getCheckSize().getHeight(), 187 getIconSize().getHeight(), 188 getTextSize().getHeight(), 189 getAccSize().getHeight(), 190 getArrowSize().getHeight())); 191 } else { 192 Rectangle textRect = new Rectangle(); 193 Rectangle iconRect = new Rectangle(); 194 gu.layoutText(context, getFontMetrics(), getText(), getIcon(), 195 getHorizontalAlignment(), getVerticalAlignment(), 196 getHorizontalTextPosition(), getVerticalTextPosition(), 197 getViewRect(), iconRect, textRect, getGap()); 198 textRect.width += getLeftTextExtraWidth(); 199 Rectangle labelRect = iconRect.union(textRect); 200 getLabelSize().setHeight(labelRect.height); 201 getLabelSize().setWidth(labelRect.width); 202 } 203 } 204 calcMaxWidths()205 protected void calcMaxWidths() { 206 calcMaxWidth(getCheckSize(), MAX_CHECK_WIDTH); 207 maxAccOrArrowWidth = 208 calcMaxValue(MAX_ACC_OR_ARROW_WIDTH, getArrowSize().getWidth()); 209 maxAccOrArrowWidth = 210 calcMaxValue(MAX_ACC_OR_ARROW_WIDTH, getAccSize().getWidth()); 211 212 if (isColumnLayout()) { 213 calcMaxWidth(getIconSize(), MAX_ICON_WIDTH); 214 calcMaxWidth(getTextSize(), MAX_TEXT_WIDTH); 215 int curGap = getGap(); 216 if ((getIconSize().getMaxWidth() == 0) 217 || (getTextSize().getMaxWidth() == 0)) { 218 curGap = 0; 219 } 220 getLabelSize().setMaxWidth( 221 calcMaxValue(MAX_LABEL_WIDTH, getIconSize().getMaxWidth() 222 + getTextSize().getMaxWidth() + curGap)); 223 } else { 224 // We shouldn't use current icon and text widths 225 // in maximal widths calculation for complex layout. 226 getIconSize().setMaxWidth(getParentIntProperty( 227 MAX_ICON_WIDTH)); 228 calcMaxWidth(getLabelSize(), MAX_LABEL_WIDTH); 229 // If maxLabelWidth is wider 230 // than the widest icon + the widest text + gap, 231 // we should update the maximal text witdh 232 int candidateTextWidth = getLabelSize().getMaxWidth() - 233 getIconSize().getMaxWidth(); 234 if (getIconSize().getMaxWidth() > 0) { 235 candidateTextWidth -= getGap(); 236 } 237 getTextSize().setMaxWidth(calcMaxValue( 238 MAX_TEXT_WIDTH, candidateTextWidth)); 239 } 240 } 241 getContext()242 public SynthContext getContext() { 243 return context; 244 } 245 getAccContext()246 public SynthContext getAccContext() { 247 return accContext; 248 } 249 getStyle()250 public SynthStyle getStyle() { 251 return style; 252 } 253 getAccStyle()254 public SynthStyle getAccStyle() { 255 return accStyle; 256 } 257 getGraphicsUtils()258 public SynthGraphicsUtils getGraphicsUtils() { 259 return gu; 260 } 261 getAccGraphicsUtils()262 public SynthGraphicsUtils getAccGraphicsUtils() { 263 return accGu; 264 } 265 alignAcceleratorText()266 public boolean alignAcceleratorText() { 267 return alignAcceleratorText; 268 } 269 getMaxAccOrArrowWidth()270 public int getMaxAccOrArrowWidth() { 271 return maxAccOrArrowWidth; 272 } 273 prepareForLayout(LayoutResult lr)274 protected void prepareForLayout(LayoutResult lr) { 275 lr.getCheckRect().width = getCheckSize().getMaxWidth(); 276 // An item can have an arrow or a check icon at once 277 if (useCheckAndArrow() && (!"".equals(getAccText()))) { 278 lr.getAccRect().width = maxAccOrArrowWidth; 279 } else { 280 lr.getArrowRect().width = maxAccOrArrowWidth; 281 } 282 } 283 getLTRColumnAlignment()284 public ColumnAlignment getLTRColumnAlignment() { 285 if (alignAcceleratorText()) { 286 return LTR_ALIGNMENT_2; 287 } else { 288 return LTR_ALIGNMENT_1; 289 } 290 } 291 getRTLColumnAlignment()292 public ColumnAlignment getRTLColumnAlignment() { 293 if (alignAcceleratorText()) { 294 return RTL_ALIGNMENT_2; 295 } else { 296 return RTL_ALIGNMENT_1; 297 } 298 } 299 layoutIconAndTextInLabelRect(LayoutResult lr)300 protected void layoutIconAndTextInLabelRect(LayoutResult lr) { 301 lr.setTextRect(new Rectangle()); 302 lr.setIconRect(new Rectangle()); 303 gu.layoutText(context, getFontMetrics(), getText(), getIcon(), 304 getHorizontalAlignment(), getVerticalAlignment(), 305 getHorizontalTextPosition(), getVerticalTextPosition(), 306 lr.getLabelRect(), lr.getIconRect(), lr.getTextRect(), getGap()); 307 } 308 } 309