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 sun.swing; 27 28 import static sun.swing.SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET; 29 30 import javax.swing.*; 31 import javax.swing.plaf.basic.BasicHTML; 32 import javax.swing.text.View; 33 import java.awt.*; 34 import java.awt.event.KeyEvent; 35 import java.util.Map; 36 import java.util.HashMap; 37 38 /** 39 * Calculates preferred size and layouts menu items. 40 */ 41 public class MenuItemLayoutHelper { 42 43 /* Client Property keys for calculation of maximal widths */ 44 public static final StringUIClientPropertyKey MAX_ARROW_WIDTH = 45 new StringUIClientPropertyKey("maxArrowWidth"); 46 public static final StringUIClientPropertyKey MAX_CHECK_WIDTH = 47 new StringUIClientPropertyKey("maxCheckWidth"); 48 public static final StringUIClientPropertyKey MAX_ICON_WIDTH = 49 new StringUIClientPropertyKey("maxIconWidth"); 50 public static final StringUIClientPropertyKey MAX_TEXT_WIDTH = 51 new StringUIClientPropertyKey("maxTextWidth"); 52 public static final StringUIClientPropertyKey MAX_ACC_WIDTH = 53 new StringUIClientPropertyKey("maxAccWidth"); 54 public static final StringUIClientPropertyKey MAX_LABEL_WIDTH = 55 new StringUIClientPropertyKey("maxLabelWidth"); 56 57 private JMenuItem mi; 58 private JComponent miParent; 59 60 private Font font; 61 private Font accFont; 62 private FontMetrics fm; 63 private FontMetrics accFm; 64 65 private Icon icon; 66 private Icon checkIcon; 67 private Icon arrowIcon; 68 private String text; 69 private String accText; 70 71 private boolean isColumnLayout; 72 private boolean useCheckAndArrow; 73 private boolean isLeftToRight; 74 private boolean isTopLevelMenu; 75 private View htmlView; 76 77 private int verticalAlignment; 78 private int horizontalAlignment; 79 private int verticalTextPosition; 80 private int horizontalTextPosition; 81 private int gap; 82 private int leadingGap; 83 private int afterCheckIconGap; 84 private int minTextOffset; 85 86 private int leftTextExtraWidth; 87 88 private Rectangle viewRect; 89 90 private RectSize iconSize; 91 private RectSize textSize; 92 private RectSize accSize; 93 private RectSize checkSize; 94 private RectSize arrowSize; 95 private RectSize labelSize; 96 97 /** 98 * The empty protected constructor is necessary for derived classes. 99 */ MenuItemLayoutHelper()100 protected MenuItemLayoutHelper() { 101 } 102 MenuItemLayoutHelper(JMenuItem mi, Icon checkIcon, Icon arrowIcon, Rectangle viewRect, int gap, String accDelimiter, boolean isLeftToRight, Font font, Font accFont, boolean useCheckAndArrow, String propertyPrefix)103 public MenuItemLayoutHelper(JMenuItem mi, Icon checkIcon, Icon arrowIcon, 104 Rectangle viewRect, int gap, String accDelimiter, 105 boolean isLeftToRight, Font font, Font accFont, 106 boolean useCheckAndArrow, String propertyPrefix) { 107 reset(mi, checkIcon, arrowIcon, viewRect, gap, accDelimiter, 108 isLeftToRight, font, accFont, useCheckAndArrow, propertyPrefix); 109 } 110 reset(JMenuItem mi, Icon checkIcon, Icon arrowIcon, Rectangle viewRect, int gap, String accDelimiter, boolean isLeftToRight, Font font, Font accFont, boolean useCheckAndArrow, String propertyPrefix)111 protected void reset(JMenuItem mi, Icon checkIcon, Icon arrowIcon, 112 Rectangle viewRect, int gap, String accDelimiter, 113 boolean isLeftToRight, Font font, Font accFont, 114 boolean useCheckAndArrow, String propertyPrefix) { 115 this.mi = mi; 116 this.miParent = getMenuItemParent(mi); 117 this.accText = getAccText(accDelimiter); 118 this.verticalAlignment = mi.getVerticalAlignment(); 119 this.horizontalAlignment = mi.getHorizontalAlignment(); 120 this.verticalTextPosition = mi.getVerticalTextPosition(); 121 this.horizontalTextPosition = mi.getHorizontalTextPosition(); 122 this.useCheckAndArrow = useCheckAndArrow; 123 this.font = font; 124 this.accFont = accFont; 125 this.fm = mi.getFontMetrics(font); 126 this.accFm = mi.getFontMetrics(accFont); 127 this.isLeftToRight = isLeftToRight; 128 this.isColumnLayout = isColumnLayout(isLeftToRight, 129 horizontalAlignment, horizontalTextPosition, 130 verticalTextPosition); 131 this.isTopLevelMenu = (this.miParent == null) ? true : false; 132 this.checkIcon = checkIcon; 133 this.icon = getIcon(propertyPrefix); 134 this.arrowIcon = arrowIcon; 135 this.text = mi.getText(); 136 this.gap = gap; 137 this.afterCheckIconGap = getAfterCheckIconGap(propertyPrefix); 138 this.minTextOffset = getMinTextOffset(propertyPrefix); 139 this.htmlView = (View) mi.getClientProperty(BasicHTML.propertyKey); 140 this.viewRect = viewRect; 141 142 this.iconSize = new RectSize(); 143 this.textSize = new RectSize(); 144 this.accSize = new RectSize(); 145 this.checkSize = new RectSize(); 146 this.arrowSize = new RectSize(); 147 this.labelSize = new RectSize(); 148 calcExtraWidths(); 149 calcWidthsAndHeights(); 150 setOriginalWidths(); 151 calcMaxWidths(); 152 153 this.leadingGap = getLeadingGap(propertyPrefix); 154 calcMaxTextOffset(viewRect); 155 } 156 calcExtraWidths()157 private void calcExtraWidths() { 158 leftTextExtraWidth = getLeftExtraWidth(text); 159 } 160 getLeftExtraWidth(String str)161 private int getLeftExtraWidth(String str) { 162 int lsb = SwingUtilities2.getLeftSideBearing(mi, fm, str); 163 if (lsb < 0) { 164 return -lsb; 165 } else { 166 return 0; 167 } 168 } 169 setOriginalWidths()170 private void setOriginalWidths() { 171 iconSize.origWidth = iconSize.width; 172 textSize.origWidth = textSize.width; 173 accSize.origWidth = accSize.width; 174 checkSize.origWidth = checkSize.width; 175 arrowSize.origWidth = arrowSize.width; 176 } 177 getAccText(String acceleratorDelimiter)178 private String getAccText(String acceleratorDelimiter) { 179 String accText = ""; 180 KeyStroke accelerator = mi.getAccelerator(); 181 if (accelerator != null) { 182 int modifiers = accelerator.getModifiers(); 183 if (modifiers > 0) { 184 accText = KeyEvent.getKeyModifiersText(modifiers); 185 accText += acceleratorDelimiter; 186 } 187 int keyCode = accelerator.getKeyCode(); 188 if (keyCode != 0) { 189 accText += KeyEvent.getKeyText(keyCode); 190 } else { 191 accText += accelerator.getKeyChar(); 192 } 193 } 194 return accText; 195 } 196 getIcon(String propertyPrefix)197 private Icon getIcon(String propertyPrefix) { 198 // In case of column layout, .checkIconFactory is defined for this UI, 199 // the icon is compatible with it and useCheckAndArrow() is true, 200 // then the icon is handled by the checkIcon. 201 Icon icon = null; 202 MenuItemCheckIconFactory iconFactory = 203 (MenuItemCheckIconFactory) UIManager.get(propertyPrefix 204 + ".checkIconFactory"); 205 if (!isColumnLayout || !useCheckAndArrow || iconFactory == null 206 || !iconFactory.isCompatible(checkIcon, propertyPrefix)) { 207 icon = mi.getIcon(); 208 } 209 return icon; 210 } 211 getMinTextOffset(String propertyPrefix)212 private int getMinTextOffset(String propertyPrefix) { 213 int minimumTextOffset = 0; 214 Object minimumTextOffsetObject = 215 UIManager.get(propertyPrefix + ".minimumTextOffset"); 216 if (minimumTextOffsetObject instanceof Integer) { 217 minimumTextOffset = (Integer) minimumTextOffsetObject; 218 } 219 return minimumTextOffset; 220 } 221 getAfterCheckIconGap(String propertyPrefix)222 private int getAfterCheckIconGap(String propertyPrefix) { 223 int afterCheckIconGap = gap; 224 Object afterCheckIconGapObject = 225 UIManager.get(propertyPrefix + ".afterCheckIconGap"); 226 if (afterCheckIconGapObject instanceof Integer) { 227 afterCheckIconGap = (Integer) afterCheckIconGapObject; 228 } 229 return afterCheckIconGap; 230 } 231 getLeadingGap(String propertyPrefix)232 private int getLeadingGap(String propertyPrefix) { 233 if (checkSize.getMaxWidth() > 0) { 234 return getCheckOffset(propertyPrefix); 235 } else { 236 return gap; // There is no any check icon 237 } 238 } 239 getCheckOffset(String propertyPrefix)240 private int getCheckOffset(String propertyPrefix) { 241 int checkIconOffset = gap; 242 Object checkIconOffsetObject = 243 UIManager.get(propertyPrefix + ".checkIconOffset"); 244 if (checkIconOffsetObject instanceof Integer) { 245 checkIconOffset = (Integer) checkIconOffsetObject; 246 } 247 return checkIconOffset; 248 } 249 calcWidthsAndHeights()250 protected void calcWidthsAndHeights() { 251 // iconRect 252 if (icon != null) { 253 iconSize.width = icon.getIconWidth(); 254 iconSize.height = icon.getIconHeight(); 255 } 256 257 // accRect 258 if (!accText.equals("")) { 259 accSize.width = SwingUtilities2.stringWidth(mi, accFm, accText); 260 accSize.height = accFm.getHeight(); 261 } 262 263 // textRect 264 if (text == null) { 265 text = ""; 266 } else if (!text.equals("")) { 267 if (htmlView != null) { 268 // Text is HTML 269 textSize.width = 270 (int) htmlView.getPreferredSpan(View.X_AXIS); 271 textSize.height = 272 (int) htmlView.getPreferredSpan(View.Y_AXIS); 273 } else { 274 // Text isn't HTML 275 textSize.width = SwingUtilities2.stringWidth(mi, fm, text); 276 textSize.height = fm.getHeight(); 277 } 278 } 279 280 if (useCheckAndArrow) { 281 // checkIcon 282 if (checkIcon != null) { 283 checkSize.width = checkIcon.getIconWidth(); 284 checkSize.height = checkIcon.getIconHeight(); 285 } 286 // arrowRect 287 if (arrowIcon != null) { 288 arrowSize.width = arrowIcon.getIconWidth(); 289 arrowSize.height = arrowIcon.getIconHeight(); 290 } 291 } 292 293 // labelRect 294 if (isColumnLayout) { 295 labelSize.width = iconSize.width + textSize.width + gap; 296 labelSize.height = max(checkSize.height, iconSize.height, 297 textSize.height, accSize.height, arrowSize.height); 298 } else { 299 Rectangle textRect = new Rectangle(); 300 Rectangle iconRect = new Rectangle(); 301 SwingUtilities.layoutCompoundLabel(mi, fm, text, icon, 302 verticalAlignment, horizontalAlignment, 303 verticalTextPosition, horizontalTextPosition, 304 viewRect, iconRect, textRect, gap); 305 textRect.width += leftTextExtraWidth; 306 Rectangle labelRect = iconRect.union(textRect); 307 labelSize.height = labelRect.height; 308 labelSize.width = labelRect.width; 309 } 310 } 311 calcMaxWidths()312 protected void calcMaxWidths() { 313 calcMaxWidth(checkSize, MAX_CHECK_WIDTH); 314 calcMaxWidth(arrowSize, MAX_ARROW_WIDTH); 315 calcMaxWidth(accSize, MAX_ACC_WIDTH); 316 317 if (isColumnLayout) { 318 calcMaxWidth(iconSize, MAX_ICON_WIDTH); 319 calcMaxWidth(textSize, MAX_TEXT_WIDTH); 320 int curGap = gap; 321 if ((iconSize.getMaxWidth() == 0) 322 || (textSize.getMaxWidth() == 0)) { 323 curGap = 0; 324 } 325 labelSize.maxWidth = 326 calcMaxValue(MAX_LABEL_WIDTH, iconSize.maxWidth 327 + textSize.maxWidth + curGap); 328 } else { 329 // We shouldn't use current icon and text widths 330 // in maximal widths calculation for complex layout. 331 iconSize.maxWidth = getParentIntProperty(MAX_ICON_WIDTH); 332 calcMaxWidth(labelSize, MAX_LABEL_WIDTH); 333 // If maxLabelWidth is wider 334 // than the widest icon + the widest text + gap, 335 // we should update the maximal text witdh 336 int candidateTextWidth = labelSize.maxWidth - iconSize.maxWidth; 337 if (iconSize.maxWidth > 0) { 338 candidateTextWidth -= gap; 339 } 340 textSize.maxWidth = calcMaxValue(MAX_TEXT_WIDTH, candidateTextWidth); 341 } 342 } 343 calcMaxWidth(RectSize rs, Object key)344 protected void calcMaxWidth(RectSize rs, Object key) { 345 rs.maxWidth = calcMaxValue(key, rs.width); 346 } 347 348 /** 349 * Calculates and returns maximal value through specified parent component 350 * client property. 351 * 352 * @param propertyName name of the property, which stores the maximal value. 353 * @param value a value which pretends to be maximal 354 * @return maximal value among the parent property and the value. 355 */ calcMaxValue(Object propertyName, int value)356 protected int calcMaxValue(Object propertyName, int value) { 357 // Get maximal value from parent client property 358 int maxValue = getParentIntProperty(propertyName); 359 // Store new maximal width in parent client property 360 if (value > maxValue) { 361 if (miParent != null) { 362 miParent.putClientProperty(propertyName, value); 363 } 364 return value; 365 } else { 366 return maxValue; 367 } 368 } 369 370 /** 371 * Returns parent client property as int. 372 * @param propertyName name of the parent property. 373 * @return value of the property as int. 374 */ getParentIntProperty(Object propertyName)375 protected int getParentIntProperty(Object propertyName) { 376 Object value = null; 377 if (miParent != null) { 378 value = miParent.getClientProperty(propertyName); 379 } 380 if ((value == null) || !(value instanceof Integer)) { 381 value = 0; 382 } 383 return (Integer) value; 384 } 385 isColumnLayout(boolean isLeftToRight, JMenuItem mi)386 public static boolean isColumnLayout(boolean isLeftToRight, 387 JMenuItem mi) { 388 assert(mi != null); 389 return isColumnLayout(isLeftToRight, mi.getHorizontalAlignment(), 390 mi.getHorizontalTextPosition(), mi.getVerticalTextPosition()); 391 } 392 393 /** 394 * Answers should we do column layout for a menu item or not. 395 * We do it when a user doesn't set any alignments 396 * and text positions manually, except the vertical alignment. 397 */ isColumnLayout(boolean isLeftToRight, int horizontalAlignment, int horizontalTextPosition, int verticalTextPosition)398 public static boolean isColumnLayout(boolean isLeftToRight, 399 int horizontalAlignment, 400 int horizontalTextPosition, 401 int verticalTextPosition) { 402 if (verticalTextPosition != SwingConstants.CENTER) { 403 return false; 404 } 405 if (isLeftToRight) { 406 if (horizontalAlignment != SwingConstants.LEADING 407 && horizontalAlignment != SwingConstants.LEFT) { 408 return false; 409 } 410 if (horizontalTextPosition != SwingConstants.TRAILING 411 && horizontalTextPosition != SwingConstants.RIGHT) { 412 return false; 413 } 414 } else { 415 if (horizontalAlignment != SwingConstants.LEADING 416 && horizontalAlignment != SwingConstants.RIGHT) { 417 return false; 418 } 419 if (horizontalTextPosition != SwingConstants.TRAILING 420 && horizontalTextPosition != SwingConstants.LEFT) { 421 return false; 422 } 423 } 424 return true; 425 } 426 427 /** 428 * Calculates maximal text offset. 429 * It is required for some L&Fs (ex: Vista L&F). 430 * The offset is meaningful only for L2R column layout. 431 * 432 * @param viewRect the rectangle, the maximal text offset 433 * will be calculated for. 434 */ calcMaxTextOffset(Rectangle viewRect)435 private void calcMaxTextOffset(Rectangle viewRect) { 436 if (!isColumnLayout || !isLeftToRight) { 437 return; 438 } 439 440 // Calculate the current text offset 441 int offset = viewRect.x + leadingGap + checkSize.maxWidth 442 + afterCheckIconGap + iconSize.maxWidth + gap; 443 if (checkSize.maxWidth == 0) { 444 offset -= afterCheckIconGap; 445 } 446 if (iconSize.maxWidth == 0) { 447 offset -= gap; 448 } 449 450 // maximal text offset shouldn't be less than minimal text offset; 451 if (offset < minTextOffset) { 452 offset = minTextOffset; 453 } 454 455 // Calculate and store the maximal text offset 456 calcMaxValue(SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET, offset); 457 } 458 459 /** 460 * Layout icon, text, check icon, accelerator text and arrow icon 461 * in the viewRect and return their positions. 462 * 463 * If horizontalAlignment, verticalTextPosition and horizontalTextPosition 464 * are default (user doesn't set any manually) the layouting algorithm is: 465 * Elements are layouted in the five columns: 466 * check icon + icon + text + accelerator text + arrow icon 467 * 468 * In the other case elements are layouted in the four columns: 469 * check icon + label + accelerator text + arrow icon 470 * Label is union of icon and text. 471 * 472 * The order of columns can be reversed. 473 * It depends on the menu item orientation. 474 */ layoutMenuItem()475 public LayoutResult layoutMenuItem() { 476 LayoutResult lr = createLayoutResult(); 477 prepareForLayout(lr); 478 479 if (isColumnLayout()) { 480 if (isLeftToRight()) { 481 doLTRColumnLayout(lr, getLTRColumnAlignment()); 482 } else { 483 doRTLColumnLayout(lr, getRTLColumnAlignment()); 484 } 485 } else { 486 if (isLeftToRight()) { 487 doLTRComplexLayout(lr, getLTRColumnAlignment()); 488 } else { 489 doRTLComplexLayout(lr, getRTLColumnAlignment()); 490 } 491 } 492 493 alignAccCheckAndArrowVertically(lr); 494 return lr; 495 } 496 createLayoutResult()497 private LayoutResult createLayoutResult() { 498 return new LayoutResult( 499 new Rectangle(iconSize.width, iconSize.height), 500 new Rectangle(textSize.width, textSize.height), 501 new Rectangle(accSize.width, accSize.height), 502 new Rectangle(checkSize.width, checkSize.height), 503 new Rectangle(arrowSize.width, arrowSize.height), 504 new Rectangle(labelSize.width, labelSize.height) 505 ); 506 } 507 getLTRColumnAlignment()508 public ColumnAlignment getLTRColumnAlignment() { 509 return ColumnAlignment.LEFT_ALIGNMENT; 510 } 511 getRTLColumnAlignment()512 public ColumnAlignment getRTLColumnAlignment() { 513 return ColumnAlignment.RIGHT_ALIGNMENT; 514 } 515 prepareForLayout(LayoutResult lr)516 protected void prepareForLayout(LayoutResult lr) { 517 lr.checkRect.width = checkSize.maxWidth; 518 lr.accRect.width = accSize.maxWidth; 519 lr.arrowRect.width = arrowSize.maxWidth; 520 } 521 522 /** 523 * Aligns the accelertor text and the check and arrow icons vertically 524 * with the center of the label rect. 525 */ alignAccCheckAndArrowVertically(LayoutResult lr)526 private void alignAccCheckAndArrowVertically(LayoutResult lr) { 527 lr.accRect.y = (int)(lr.labelRect.y 528 + (float)lr.labelRect.height/2 529 - (float)lr.accRect.height/2); 530 fixVerticalAlignment(lr, lr.accRect); 531 if (useCheckAndArrow) { 532 lr.arrowRect.y = (int)(lr.labelRect.y 533 + (float)lr.labelRect.height/2 534 - (float)lr.arrowRect.height/2); 535 lr.checkRect.y = (int)(lr.labelRect.y 536 + (float)lr.labelRect.height/2 537 - (float)lr.checkRect.height/2); 538 fixVerticalAlignment(lr, lr.arrowRect); 539 fixVerticalAlignment(lr, lr.checkRect); 540 } 541 } 542 543 /** 544 * Fixes vertical alignment of all menu item elements if rect.y 545 * or (rect.y + rect.height) is out of viewRect bounds 546 */ fixVerticalAlignment(LayoutResult lr, Rectangle r)547 private void fixVerticalAlignment(LayoutResult lr, Rectangle r) { 548 int delta = 0; 549 if (r.y < viewRect.y) { 550 delta = viewRect.y - r.y; 551 } else if (r.y + r.height > viewRect.y + viewRect.height) { 552 delta = viewRect.y + viewRect.height - r.y - r.height; 553 } 554 if (delta != 0) { 555 lr.checkRect.y += delta; 556 lr.iconRect.y += delta; 557 lr.textRect.y += delta; 558 lr.accRect.y += delta; 559 lr.arrowRect.y += delta; 560 lr.labelRect.y += delta; 561 } 562 } 563 doLTRColumnLayout(LayoutResult lr, ColumnAlignment alignment)564 private void doLTRColumnLayout(LayoutResult lr, ColumnAlignment alignment) { 565 // Set maximal width for all the five basic rects 566 // (three other ones are already maximal) 567 lr.iconRect.width = iconSize.maxWidth; 568 lr.textRect.width = textSize.maxWidth; 569 570 // Set X coordinates 571 // All rects will be aligned at the left side 572 calcXPositionsLTR(viewRect.x, leadingGap, gap, lr.checkRect, 573 lr.iconRect, lr.textRect); 574 575 // Tune afterCheckIconGap 576 if (lr.checkRect.width > 0) { // there is the afterCheckIconGap 577 lr.iconRect.x += afterCheckIconGap - gap; 578 lr.textRect.x += afterCheckIconGap - gap; 579 } 580 581 calcXPositionsRTL(viewRect.x + viewRect.width, leadingGap, gap, 582 lr.arrowRect, lr.accRect); 583 584 // Take into account minimal text offset 585 int textOffset = lr.textRect.x - viewRect.x; 586 if (!isTopLevelMenu && (textOffset < minTextOffset)) { 587 lr.textRect.x += minTextOffset - textOffset; 588 } 589 590 alignRects(lr, alignment); 591 592 // Set Y coordinate for text and icon. 593 // Y coordinates for other rects 594 // will be calculated later in layoutMenuItem. 595 calcTextAndIconYPositions(lr); 596 597 // Calculate valid X and Y coordinates for labelRect 598 lr.setLabelRect(lr.textRect.union(lr.iconRect)); 599 } 600 doLTRComplexLayout(LayoutResult lr, ColumnAlignment alignment)601 private void doLTRComplexLayout(LayoutResult lr, ColumnAlignment alignment) { 602 lr.labelRect.width = labelSize.maxWidth; 603 604 // Set X coordinates 605 calcXPositionsLTR(viewRect.x, leadingGap, gap, lr.checkRect, 606 lr.labelRect); 607 608 // Tune afterCheckIconGap 609 if (lr.checkRect.width > 0) { // there is the afterCheckIconGap 610 lr.labelRect.x += afterCheckIconGap - gap; 611 } 612 613 calcXPositionsRTL(viewRect.x + viewRect.width, 614 leadingGap, gap, lr.arrowRect, lr.accRect); 615 616 // Take into account minimal text offset 617 int labelOffset = lr.labelRect.x - viewRect.x; 618 if (!isTopLevelMenu && (labelOffset < minTextOffset)) { 619 lr.labelRect.x += minTextOffset - labelOffset; 620 } 621 622 alignRects(lr, alignment); 623 624 // Center labelRect vertically 625 calcLabelYPosition(lr); 626 627 layoutIconAndTextInLabelRect(lr); 628 } 629 doRTLColumnLayout(LayoutResult lr, ColumnAlignment alignment)630 private void doRTLColumnLayout(LayoutResult lr, ColumnAlignment alignment) { 631 // Set maximal width for all the five basic rects 632 // (three other ones are already maximal) 633 lr.iconRect.width = iconSize.maxWidth; 634 lr.textRect.width = textSize.maxWidth; 635 636 // Set X coordinates 637 calcXPositionsRTL(viewRect.x + viewRect.width, leadingGap, gap, 638 lr.checkRect, lr.iconRect, lr.textRect); 639 640 // Tune the gap after check icon 641 if (lr.checkRect.width > 0) { // there is the gap after check icon 642 lr.iconRect.x -= afterCheckIconGap - gap; 643 lr.textRect.x -= afterCheckIconGap - gap; 644 } 645 646 calcXPositionsLTR(viewRect.x, leadingGap, gap, lr.arrowRect, 647 lr.accRect); 648 649 // Take into account minimal text offset 650 int textOffset = (viewRect.x + viewRect.width) 651 - (lr.textRect.x + lr.textRect.width); 652 if (!isTopLevelMenu && (textOffset < minTextOffset)) { 653 lr.textRect.x -= minTextOffset - textOffset; 654 } 655 656 alignRects(lr, alignment); 657 658 // Set Y coordinates for text and icon. 659 // Y coordinates for other rects 660 // will be calculated later in layoutMenuItem. 661 calcTextAndIconYPositions(lr); 662 663 // Calculate valid X and Y coordinate for labelRect 664 lr.setLabelRect(lr.textRect.union(lr.iconRect)); 665 } 666 doRTLComplexLayout(LayoutResult lr, ColumnAlignment alignment)667 private void doRTLComplexLayout(LayoutResult lr, ColumnAlignment alignment) { 668 lr.labelRect.width = labelSize.maxWidth; 669 670 // Set X coordinates 671 calcXPositionsRTL(viewRect.x + viewRect.width, leadingGap, gap, 672 lr.checkRect, lr.labelRect); 673 674 // Tune the gap after check icon 675 if (lr.checkRect.width > 0) { // there is the gap after check icon 676 lr.labelRect.x -= afterCheckIconGap - gap; 677 } 678 679 calcXPositionsLTR(viewRect.x, leadingGap, gap, lr.arrowRect, lr.accRect); 680 681 // Take into account minimal text offset 682 int labelOffset = (viewRect.x + viewRect.width) 683 - (lr.labelRect.x + lr.labelRect.width); 684 if (!isTopLevelMenu && (labelOffset < minTextOffset)) { 685 lr.labelRect.x -= minTextOffset - labelOffset; 686 } 687 688 alignRects(lr, alignment); 689 690 // Center labelRect vertically 691 calcLabelYPosition(lr); 692 693 layoutIconAndTextInLabelRect(lr); 694 } 695 alignRects(LayoutResult lr, ColumnAlignment alignment)696 private void alignRects(LayoutResult lr, ColumnAlignment alignment) { 697 alignRect(lr.checkRect, alignment.getCheckAlignment(), 698 checkSize.getOrigWidth()); 699 alignRect(lr.iconRect, alignment.getIconAlignment(), 700 iconSize.getOrigWidth()); 701 alignRect(lr.textRect, alignment.getTextAlignment(), 702 textSize.getOrigWidth()); 703 alignRect(lr.accRect, alignment.getAccAlignment(), 704 accSize.getOrigWidth()); 705 alignRect(lr.arrowRect, alignment.getArrowAlignment(), 706 arrowSize.getOrigWidth()); 707 } 708 alignRect(Rectangle rect, int alignment, int origWidth)709 private void alignRect(Rectangle rect, int alignment, int origWidth) { 710 if (alignment == SwingConstants.RIGHT) { 711 rect.x = rect.x + rect.width - origWidth; 712 } 713 rect.width = origWidth; 714 } 715 layoutIconAndTextInLabelRect(LayoutResult lr)716 protected void layoutIconAndTextInLabelRect(LayoutResult lr) { 717 lr.setTextRect(new Rectangle()); 718 lr.setIconRect(new Rectangle()); 719 SwingUtilities.layoutCompoundLabel( 720 mi, fm, text,icon, verticalAlignment, horizontalAlignment, 721 verticalTextPosition, horizontalTextPosition, lr.labelRect, 722 lr.iconRect, lr.textRect, gap); 723 } 724 calcXPositionsLTR(int startXPos, int leadingGap, int gap, Rectangle... rects)725 private void calcXPositionsLTR(int startXPos, int leadingGap, 726 int gap, Rectangle... rects) { 727 int curXPos = startXPos + leadingGap; 728 for (Rectangle rect : rects) { 729 rect.x = curXPos; 730 if (rect.width > 0) { 731 curXPos += rect.width + gap; 732 } 733 } 734 } 735 calcXPositionsRTL(int startXPos, int leadingGap, int gap, Rectangle... rects)736 private void calcXPositionsRTL(int startXPos, int leadingGap, 737 int gap, Rectangle... rects) { 738 int curXPos = startXPos - leadingGap; 739 for (Rectangle rect : rects) { 740 rect.x = curXPos - rect.width; 741 if (rect.width > 0) { 742 curXPos -= rect.width + gap; 743 } 744 } 745 } 746 747 /** 748 * Sets Y coordinates of text and icon 749 * taking into account the vertical alignment 750 */ calcTextAndIconYPositions(LayoutResult lr)751 private void calcTextAndIconYPositions(LayoutResult lr) { 752 if (verticalAlignment == SwingUtilities.TOP) { 753 lr.textRect.y = (int)(viewRect.y 754 + (float)lr.labelRect.height/2 755 - (float)lr.textRect.height/2); 756 lr.iconRect.y = (int)(viewRect.y 757 + (float)lr.labelRect.height/2 758 - (float)lr.iconRect.height/2); 759 } else if (verticalAlignment == SwingUtilities.CENTER) { 760 lr.textRect.y = (int)(viewRect.y 761 + (float)viewRect.height/2 762 - (float)lr.textRect.height/2); 763 lr.iconRect.y = (int)(viewRect.y 764 + (float)viewRect.height/2 765 - (float)lr.iconRect.height/2); 766 } 767 else if (verticalAlignment == SwingUtilities.BOTTOM) { 768 lr.textRect.y = (int)(viewRect.y 769 + viewRect.height 770 - (float)lr.labelRect.height/2 771 - (float)lr.textRect.height/2); 772 lr.iconRect.y = (int)(viewRect.y 773 + viewRect.height 774 - (float)lr.labelRect.height/2 775 - (float)lr.iconRect.height/2); 776 } 777 } 778 779 /** 780 * Sets labelRect Y coordinate 781 * taking into account the vertical alignment 782 */ calcLabelYPosition(LayoutResult lr)783 private void calcLabelYPosition(LayoutResult lr) { 784 if (verticalAlignment == SwingUtilities.TOP) { 785 lr.labelRect.y = viewRect.y; 786 } else if (verticalAlignment == SwingUtilities.CENTER) { 787 lr.labelRect.y = (int)(viewRect.y 788 + (float)viewRect.height/2 789 - (float)lr.labelRect.height/2); 790 } else if (verticalAlignment == SwingUtilities.BOTTOM) { 791 lr.labelRect.y = viewRect.y + viewRect.height 792 - lr.labelRect.height; 793 } 794 } 795 796 /** 797 * Returns parent of this component if it is not a top-level menu 798 * Otherwise returns null. 799 * @param menuItem the menu item whose parent will be returned. 800 * @return parent of this component if it is not a top-level menu 801 * Otherwise returns null. 802 */ getMenuItemParent(JMenuItem menuItem)803 public static JComponent getMenuItemParent(JMenuItem menuItem) { 804 Container parent = menuItem.getParent(); 805 if ((parent instanceof JComponent) && 806 (!(menuItem instanceof JMenu) || 807 !((JMenu)menuItem).isTopLevelMenu())) { 808 return (JComponent) parent; 809 } else { 810 return null; 811 } 812 } 813 clearUsedParentClientProperties(JMenuItem menuItem)814 public static void clearUsedParentClientProperties(JMenuItem menuItem) { 815 clearUsedClientProperties(getMenuItemParent(menuItem)); 816 } 817 clearUsedClientProperties(JComponent c)818 public static void clearUsedClientProperties(JComponent c) { 819 if (c != null) { 820 c.putClientProperty(MAX_ARROW_WIDTH, null); 821 c.putClientProperty(MAX_CHECK_WIDTH, null); 822 c.putClientProperty(MAX_ACC_WIDTH, null); 823 c.putClientProperty(MAX_TEXT_WIDTH, null); 824 c.putClientProperty(MAX_ICON_WIDTH, null); 825 c.putClientProperty(MAX_LABEL_WIDTH, null); 826 c.putClientProperty(BASICMENUITEMUI_MAX_TEXT_OFFSET, null); 827 } 828 } 829 830 /** 831 * Finds and returns maximal integer value in the given array. 832 * @param values array where the search will be performed. 833 * @return maximal vaule. 834 */ max(int... values)835 public static int max(int... values) { 836 int maxValue = Integer.MIN_VALUE; 837 for (int i : values) { 838 if (i > maxValue) { 839 maxValue = i; 840 } 841 } 842 return maxValue; 843 } 844 createMaxRect()845 public static Rectangle createMaxRect() { 846 return new Rectangle(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE); 847 } 848 addMaxWidth(RectSize size, int gap, Dimension result)849 public static void addMaxWidth(RectSize size, int gap, Dimension result) { 850 if (size.maxWidth > 0) { 851 result.width += size.maxWidth + gap; 852 } 853 } 854 addWidth(int width, int gap, Dimension result)855 public static void addWidth(int width, int gap, Dimension result) { 856 if (width > 0) { 857 result.width += width + gap; 858 } 859 } 860 getMenuItem()861 public JMenuItem getMenuItem() { 862 return mi; 863 } 864 getMenuItemParent()865 public JComponent getMenuItemParent() { 866 return miParent; 867 } 868 getFont()869 public Font getFont() { 870 return font; 871 } 872 getAccFont()873 public Font getAccFont() { 874 return accFont; 875 } 876 getFontMetrics()877 public FontMetrics getFontMetrics() { 878 return fm; 879 } 880 getAccFontMetrics()881 public FontMetrics getAccFontMetrics() { 882 return accFm; 883 } 884 getIcon()885 public Icon getIcon() { 886 return icon; 887 } 888 getCheckIcon()889 public Icon getCheckIcon() { 890 return checkIcon; 891 } 892 getArrowIcon()893 public Icon getArrowIcon() { 894 return arrowIcon; 895 } 896 getText()897 public String getText() { 898 return text; 899 } 900 getAccText()901 public String getAccText() { 902 return accText; 903 } 904 isColumnLayout()905 public boolean isColumnLayout() { 906 return isColumnLayout; 907 } 908 useCheckAndArrow()909 public boolean useCheckAndArrow() { 910 return useCheckAndArrow; 911 } 912 isLeftToRight()913 public boolean isLeftToRight() { 914 return isLeftToRight; 915 } 916 isTopLevelMenu()917 public boolean isTopLevelMenu() { 918 return isTopLevelMenu; 919 } 920 getHtmlView()921 public View getHtmlView() { 922 return htmlView; 923 } 924 getVerticalAlignment()925 public int getVerticalAlignment() { 926 return verticalAlignment; 927 } 928 getHorizontalAlignment()929 public int getHorizontalAlignment() { 930 return horizontalAlignment; 931 } 932 getVerticalTextPosition()933 public int getVerticalTextPosition() { 934 return verticalTextPosition; 935 } 936 getHorizontalTextPosition()937 public int getHorizontalTextPosition() { 938 return horizontalTextPosition; 939 } 940 getGap()941 public int getGap() { 942 return gap; 943 } 944 getLeadingGap()945 public int getLeadingGap() { 946 return leadingGap; 947 } 948 getAfterCheckIconGap()949 public int getAfterCheckIconGap() { 950 return afterCheckIconGap; 951 } 952 getMinTextOffset()953 public int getMinTextOffset() { 954 return minTextOffset; 955 } 956 getViewRect()957 public Rectangle getViewRect() { 958 return viewRect; 959 } 960 getIconSize()961 public RectSize getIconSize() { 962 return iconSize; 963 } 964 getTextSize()965 public RectSize getTextSize() { 966 return textSize; 967 } 968 getAccSize()969 public RectSize getAccSize() { 970 return accSize; 971 } 972 getCheckSize()973 public RectSize getCheckSize() { 974 return checkSize; 975 } 976 getArrowSize()977 public RectSize getArrowSize() { 978 return arrowSize; 979 } 980 getLabelSize()981 public RectSize getLabelSize() { 982 return labelSize; 983 } 984 setMenuItem(JMenuItem mi)985 protected void setMenuItem(JMenuItem mi) { 986 this.mi = mi; 987 } 988 setMenuItemParent(JComponent miParent)989 protected void setMenuItemParent(JComponent miParent) { 990 this.miParent = miParent; 991 } 992 setFont(Font font)993 protected void setFont(Font font) { 994 this.font = font; 995 } 996 setAccFont(Font accFont)997 protected void setAccFont(Font accFont) { 998 this.accFont = accFont; 999 } 1000 setFontMetrics(FontMetrics fm)1001 protected void setFontMetrics(FontMetrics fm) { 1002 this.fm = fm; 1003 } 1004 setAccFontMetrics(FontMetrics accFm)1005 protected void setAccFontMetrics(FontMetrics accFm) { 1006 this.accFm = accFm; 1007 } 1008 setIcon(Icon icon)1009 protected void setIcon(Icon icon) { 1010 this.icon = icon; 1011 } 1012 setCheckIcon(Icon checkIcon)1013 protected void setCheckIcon(Icon checkIcon) { 1014 this.checkIcon = checkIcon; 1015 } 1016 setArrowIcon(Icon arrowIcon)1017 protected void setArrowIcon(Icon arrowIcon) { 1018 this.arrowIcon = arrowIcon; 1019 } 1020 setText(String text)1021 protected void setText(String text) { 1022 this.text = text; 1023 } 1024 setAccText(String accText)1025 protected void setAccText(String accText) { 1026 this.accText = accText; 1027 } 1028 setColumnLayout(boolean columnLayout)1029 protected void setColumnLayout(boolean columnLayout) { 1030 isColumnLayout = columnLayout; 1031 } 1032 setUseCheckAndArrow(boolean useCheckAndArrow)1033 protected void setUseCheckAndArrow(boolean useCheckAndArrow) { 1034 this.useCheckAndArrow = useCheckAndArrow; 1035 } 1036 setLeftToRight(boolean leftToRight)1037 protected void setLeftToRight(boolean leftToRight) { 1038 isLeftToRight = leftToRight; 1039 } 1040 setTopLevelMenu(boolean topLevelMenu)1041 protected void setTopLevelMenu(boolean topLevelMenu) { 1042 isTopLevelMenu = topLevelMenu; 1043 } 1044 setHtmlView(View htmlView)1045 protected void setHtmlView(View htmlView) { 1046 this.htmlView = htmlView; 1047 } 1048 setVerticalAlignment(int verticalAlignment)1049 protected void setVerticalAlignment(int verticalAlignment) { 1050 this.verticalAlignment = verticalAlignment; 1051 } 1052 setHorizontalAlignment(int horizontalAlignment)1053 protected void setHorizontalAlignment(int horizontalAlignment) { 1054 this.horizontalAlignment = horizontalAlignment; 1055 } 1056 setVerticalTextPosition(int verticalTextPosition)1057 protected void setVerticalTextPosition(int verticalTextPosition) { 1058 this.verticalTextPosition = verticalTextPosition; 1059 } 1060 setHorizontalTextPosition(int horizontalTextPosition)1061 protected void setHorizontalTextPosition(int horizontalTextPosition) { 1062 this.horizontalTextPosition = horizontalTextPosition; 1063 } 1064 setGap(int gap)1065 protected void setGap(int gap) { 1066 this.gap = gap; 1067 } 1068 setLeadingGap(int leadingGap)1069 protected void setLeadingGap(int leadingGap) { 1070 this.leadingGap = leadingGap; 1071 } 1072 setAfterCheckIconGap(int afterCheckIconGap)1073 protected void setAfterCheckIconGap(int afterCheckIconGap) { 1074 this.afterCheckIconGap = afterCheckIconGap; 1075 } 1076 setMinTextOffset(int minTextOffset)1077 protected void setMinTextOffset(int minTextOffset) { 1078 this.minTextOffset = minTextOffset; 1079 } 1080 setViewRect(Rectangle viewRect)1081 protected void setViewRect(Rectangle viewRect) { 1082 this.viewRect = viewRect; 1083 } 1084 setIconSize(RectSize iconSize)1085 protected void setIconSize(RectSize iconSize) { 1086 this.iconSize = iconSize; 1087 } 1088 setTextSize(RectSize textSize)1089 protected void setTextSize(RectSize textSize) { 1090 this.textSize = textSize; 1091 } 1092 setAccSize(RectSize accSize)1093 protected void setAccSize(RectSize accSize) { 1094 this.accSize = accSize; 1095 } 1096 setCheckSize(RectSize checkSize)1097 protected void setCheckSize(RectSize checkSize) { 1098 this.checkSize = checkSize; 1099 } 1100 setArrowSize(RectSize arrowSize)1101 protected void setArrowSize(RectSize arrowSize) { 1102 this.arrowSize = arrowSize; 1103 } 1104 setLabelSize(RectSize labelSize)1105 protected void setLabelSize(RectSize labelSize) { 1106 this.labelSize = labelSize; 1107 } 1108 getLeftTextExtraWidth()1109 public int getLeftTextExtraWidth() { 1110 return leftTextExtraWidth; 1111 } 1112 1113 /** 1114 * Returns false if the component is a JMenu and it is a top 1115 * level menu (on the menubar). 1116 */ useCheckAndArrow(JMenuItem menuItem)1117 public static boolean useCheckAndArrow(JMenuItem menuItem) { 1118 boolean b = true; 1119 if ((menuItem instanceof JMenu) && 1120 (((JMenu) menuItem).isTopLevelMenu())) { 1121 b = false; 1122 } 1123 return b; 1124 } 1125 1126 public static class LayoutResult { 1127 private Rectangle iconRect; 1128 private Rectangle textRect; 1129 private Rectangle accRect; 1130 private Rectangle checkRect; 1131 private Rectangle arrowRect; 1132 private Rectangle labelRect; 1133 LayoutResult()1134 public LayoutResult() { 1135 iconRect = new Rectangle(); 1136 textRect = new Rectangle(); 1137 accRect = new Rectangle(); 1138 checkRect = new Rectangle(); 1139 arrowRect = new Rectangle(); 1140 labelRect = new Rectangle(); 1141 } 1142 LayoutResult(Rectangle iconRect, Rectangle textRect, Rectangle accRect, Rectangle checkRect, Rectangle arrowRect, Rectangle labelRect)1143 public LayoutResult(Rectangle iconRect, Rectangle textRect, 1144 Rectangle accRect, Rectangle checkRect, 1145 Rectangle arrowRect, Rectangle labelRect) { 1146 this.iconRect = iconRect; 1147 this.textRect = textRect; 1148 this.accRect = accRect; 1149 this.checkRect = checkRect; 1150 this.arrowRect = arrowRect; 1151 this.labelRect = labelRect; 1152 } 1153 getIconRect()1154 public Rectangle getIconRect() { 1155 return iconRect; 1156 } 1157 setIconRect(Rectangle iconRect)1158 public void setIconRect(Rectangle iconRect) { 1159 this.iconRect = iconRect; 1160 } 1161 getTextRect()1162 public Rectangle getTextRect() { 1163 return textRect; 1164 } 1165 setTextRect(Rectangle textRect)1166 public void setTextRect(Rectangle textRect) { 1167 this.textRect = textRect; 1168 } 1169 getAccRect()1170 public Rectangle getAccRect() { 1171 return accRect; 1172 } 1173 setAccRect(Rectangle accRect)1174 public void setAccRect(Rectangle accRect) { 1175 this.accRect = accRect; 1176 } 1177 getCheckRect()1178 public Rectangle getCheckRect() { 1179 return checkRect; 1180 } 1181 setCheckRect(Rectangle checkRect)1182 public void setCheckRect(Rectangle checkRect) { 1183 this.checkRect = checkRect; 1184 } 1185 getArrowRect()1186 public Rectangle getArrowRect() { 1187 return arrowRect; 1188 } 1189 setArrowRect(Rectangle arrowRect)1190 public void setArrowRect(Rectangle arrowRect) { 1191 this.arrowRect = arrowRect; 1192 } 1193 getLabelRect()1194 public Rectangle getLabelRect() { 1195 return labelRect; 1196 } 1197 setLabelRect(Rectangle labelRect)1198 public void setLabelRect(Rectangle labelRect) { 1199 this.labelRect = labelRect; 1200 } 1201 getAllRects()1202 public Map<String, Rectangle> getAllRects() { 1203 Map<String, Rectangle> result = new HashMap<String, Rectangle>(); 1204 result.put("checkRect", checkRect); 1205 result.put("iconRect", iconRect); 1206 result.put("textRect", textRect); 1207 result.put("accRect", accRect); 1208 result.put("arrowRect", arrowRect); 1209 result.put("labelRect", labelRect); 1210 return result; 1211 } 1212 } 1213 1214 public static class ColumnAlignment { 1215 private int checkAlignment; 1216 private int iconAlignment; 1217 private int textAlignment; 1218 private int accAlignment; 1219 private int arrowAlignment; 1220 1221 public static final ColumnAlignment LEFT_ALIGNMENT = 1222 new ColumnAlignment( 1223 SwingConstants.LEFT, 1224 SwingConstants.LEFT, 1225 SwingConstants.LEFT, 1226 SwingConstants.LEFT, 1227 SwingConstants.LEFT 1228 ); 1229 1230 public static final ColumnAlignment RIGHT_ALIGNMENT = 1231 new ColumnAlignment( 1232 SwingConstants.RIGHT, 1233 SwingConstants.RIGHT, 1234 SwingConstants.RIGHT, 1235 SwingConstants.RIGHT, 1236 SwingConstants.RIGHT 1237 ); 1238 ColumnAlignment(int checkAlignment, int iconAlignment, int textAlignment, int accAlignment, int arrowAlignment)1239 public ColumnAlignment(int checkAlignment, int iconAlignment, 1240 int textAlignment, int accAlignment, 1241 int arrowAlignment) { 1242 this.checkAlignment = checkAlignment; 1243 this.iconAlignment = iconAlignment; 1244 this.textAlignment = textAlignment; 1245 this.accAlignment = accAlignment; 1246 this.arrowAlignment = arrowAlignment; 1247 } 1248 getCheckAlignment()1249 public int getCheckAlignment() { 1250 return checkAlignment; 1251 } 1252 getIconAlignment()1253 public int getIconAlignment() { 1254 return iconAlignment; 1255 } 1256 getTextAlignment()1257 public int getTextAlignment() { 1258 return textAlignment; 1259 } 1260 getAccAlignment()1261 public int getAccAlignment() { 1262 return accAlignment; 1263 } 1264 getArrowAlignment()1265 public int getArrowAlignment() { 1266 return arrowAlignment; 1267 } 1268 } 1269 1270 public static class RectSize { 1271 private int width; 1272 private int height; 1273 private int origWidth; 1274 private int maxWidth; 1275 RectSize()1276 public RectSize() { 1277 } 1278 RectSize(int width, int height, int origWidth, int maxWidth)1279 public RectSize(int width, int height, int origWidth, int maxWidth) { 1280 this.width = width; 1281 this.height = height; 1282 this.origWidth = origWidth; 1283 this.maxWidth = maxWidth; 1284 } 1285 getWidth()1286 public int getWidth() { 1287 return width; 1288 } 1289 getHeight()1290 public int getHeight() { 1291 return height; 1292 } 1293 getOrigWidth()1294 public int getOrigWidth() { 1295 return origWidth; 1296 } 1297 getMaxWidth()1298 public int getMaxWidth() { 1299 return maxWidth; 1300 } 1301 setWidth(int width)1302 public void setWidth(int width) { 1303 this.width = width; 1304 } 1305 setHeight(int height)1306 public void setHeight(int height) { 1307 this.height = height; 1308 } 1309 setOrigWidth(int origWidth)1310 public void setOrigWidth(int origWidth) { 1311 this.origWidth = origWidth; 1312 } 1313 setMaxWidth(int maxWidth)1314 public void setMaxWidth(int maxWidth) { 1315 this.maxWidth = maxWidth; 1316 } 1317 toString()1318 public String toString() { 1319 return "[w=" + width + ",h=" + height + ",ow=" 1320 + origWidth + ",mw=" + maxWidth + "]"; 1321 } 1322 } 1323 } 1324