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