1 /* 2 * Copyright (c) 2002, 2014, 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 package sun.swing.plaf.synth; 26 27 import javax.swing.plaf.synth.*; 28 import java.awt.*; 29 import java.util.*; 30 import javax.swing.*; 31 import javax.swing.plaf.*; 32 33 /** 34 * Default implementation of SynthStyle. Has setters for the various 35 * SynthStyle methods. Many of the properties can be specified for all states, 36 * using SynthStyle directly, or a specific state using one of the StateInfo 37 * methods. 38 * <p> 39 * Beyond the constructor a subclass should override the <code>addTo</code> 40 * and <code>clone</code> methods, these are used when the Styles are being 41 * merged into a resulting style. 42 * 43 * @author Scott Violet 44 */ 45 public class DefaultSynthStyle extends SynthStyle implements Cloneable { 46 47 private static final Object PENDING = new Object(); 48 49 /** 50 * Should the component be opaque? 51 */ 52 private boolean opaque; 53 /** 54 * Insets. 55 */ 56 private Insets insets; 57 /** 58 * Information specific to ComponentState. 59 */ 60 private StateInfo[] states; 61 /** 62 * User specific data. 63 */ 64 private Map<Object, Object> data; 65 66 /** 67 * Font to use if there is no matching StateInfo, or the StateInfo doesn't 68 * define one. 69 */ 70 private Font font; 71 72 /** 73 * SynthGraphics, may be null. 74 */ 75 private SynthGraphicsUtils synthGraphics; 76 77 /** 78 * Painter to use if the StateInfo doesn't have one. 79 */ 80 private SynthPainter painter; 81 82 83 /** 84 * Nullary constructor, intended for subclassers. 85 */ 86 public DefaultSynthStyle() { 87 } 88 89 /** 90 * Creates a new DefaultSynthStyle that is a copy of the passed in 91 * style. Any StateInfo's of the passed in style are clonsed as well. 92 * 93 * @param style Style to duplicate 94 */ 95 public DefaultSynthStyle(DefaultSynthStyle style) { 96 opaque = style.opaque; 97 if (style.insets != null) { 98 insets = new Insets(style.insets.top, style.insets.left, 99 style.insets.bottom, style.insets.right); 100 } 101 if (style.states != null) { 102 states = new StateInfo[style.states.length]; 103 for (int counter = style.states.length - 1; counter >= 0; 104 counter--) { 105 states[counter] = (StateInfo)style.states[counter].clone(); 106 } 107 } 108 if (style.data != null) { 109 data = new HashMap<>(); 110 data.putAll(style.data); 111 } 112 font = style.font; 113 synthGraphics = style.synthGraphics; 114 painter = style.painter; 115 } 116 117 /** 118 * Creates a new DefaultSynthStyle. 119 * 120 * @param insets Insets for the Style 121 * @param opaque Whether or not the background is completely painted in 122 * an opaque color 123 * @param states StateInfos describing properties per state 124 * @param data Style specific data. 125 */ 126 public DefaultSynthStyle(Insets insets, boolean opaque, 127 StateInfo[] states, Map<Object, Object> data) { 128 this.insets = insets; 129 this.opaque = opaque; 130 this.states = states; 131 this.data = data; 132 } 133 134 public Color getColor(SynthContext context, ColorType type) { 135 return getColor(context.getComponent(), context.getRegion(), 136 context.getComponentState(), type); 137 } 138 139 public Color getColor(JComponent c, Region id, int state, 140 ColorType type) { 141 // For the enabled state, prefer the widget's colors 142 if (!id.isSubregion() && state == SynthConstants.ENABLED) { 143 if (type == ColorType.BACKGROUND) { 144 return c.getBackground(); 145 } 146 else if (type == ColorType.FOREGROUND) { 147 return c.getForeground(); 148 } 149 else if (type == ColorType.TEXT_FOREGROUND) { 150 // If getForeground returns a non-UIResource it means the 151 // developer has explicitly set the foreground, use it over 152 // that of TEXT_FOREGROUND as that is typically the expected 153 // behavior. 154 Color color = c.getForeground(); 155 if (!(color instanceof UIResource)) { 156 return color; 157 } 158 } 159 } 160 // Then use what we've locally defined 161 Color color = getColorForState(c, id, state, type); 162 if (color == null) { 163 // No color, fallback to that of the widget. 164 if (type == ColorType.BACKGROUND || 165 type == ColorType.TEXT_BACKGROUND) { 166 return c.getBackground(); 167 } 168 else if (type == ColorType.FOREGROUND || 169 type == ColorType.TEXT_FOREGROUND) { 170 return c.getForeground(); 171 } 172 } 173 return color; 174 } 175 176 protected Color getColorForState(SynthContext context, ColorType type) { 177 return getColorForState(context.getComponent(), context.getRegion(), 178 context.getComponentState(), type); 179 } 180 181 /** 182 * Returns the color for the specified state. 183 * 184 * @param c JComponent the style is associated with 185 * @param id Region identifier 186 * @param state State of the region. 187 * @param type Type of color being requested. 188 * @return Color to render with 189 */ 190 protected Color getColorForState(JComponent c, Region id, int state, 191 ColorType type) { 192 // Use the best state. 193 StateInfo si = getStateInfo(state); 194 Color color; 195 if (si != null && (color = si.getColor(type)) != null) { 196 return color; 197 } 198 if (si == null || si.getComponentState() != 0) { 199 si = getStateInfo(0); 200 if (si != null) { 201 return si.getColor(type); 202 } 203 } 204 return null; 205 } 206 207 /** 208 * Sets the font that is used if there is no matching StateInfo, or 209 * it does not define a font. 210 * 211 * @param font Font to use for rendering 212 */ 213 public void setFont(Font font) { 214 this.font = font; 215 } 216 217 public Font getFont(SynthContext state) { 218 return getFont(state.getComponent(), state.getRegion(), 219 state.getComponentState()); 220 } 221 222 public Font getFont(JComponent c, Region id, int state) { 223 if (!id.isSubregion() && state == SynthConstants.ENABLED) { 224 return c.getFont(); 225 } 226 Font cFont = c.getFont(); 227 if (cFont != null && !(cFont instanceof UIResource)) { 228 return cFont; 229 } 230 return getFontForState(c, id, state); 231 } 232 233 /** 234 * Returns the font for the specified state. This should NOT callback 235 * to the JComponent. 236 * 237 * @param c JComponent the style is associated with 238 * @param id Region identifier 239 * @param state State of the region. 240 * @return Font to render with 241 */ 242 protected Font getFontForState(JComponent c, Region id, int state) { 243 if (c == null) { 244 return this.font; 245 } 246 // First pass, look for the best match 247 StateInfo si = getStateInfo(state); 248 Font font; 249 if (si != null && (font = si.getFont()) != null) { 250 return font; 251 } 252 if (si == null || si.getComponentState() != 0) { 253 si = getStateInfo(0); 254 if (si != null && (font = si.getFont()) != null) { 255 return font; 256 } 257 } 258 // Fallback font. 259 return this.font; 260 } 261 262 protected Font getFontForState(SynthContext context) { 263 return getFontForState(context.getComponent(), context.getRegion(), 264 context.getComponentState()); 265 } 266 267 /** 268 * Sets the SynthGraphicsUtils that will be used for rendering. 269 * 270 * @param graphics SynthGraphics 271 */ 272 public void setGraphicsUtils(SynthGraphicsUtils graphics) { 273 this.synthGraphics = graphics; 274 } 275 276 /** 277 * Returns a SynthGraphicsUtils. 278 * 279 * @param context SynthContext identifying requestor 280 * @return SynthGraphicsUtils 281 */ 282 public SynthGraphicsUtils getGraphicsUtils(SynthContext context) { 283 if (synthGraphics == null) { 284 return super.getGraphicsUtils(context); 285 } 286 return synthGraphics; 287 } 288 289 /** 290 * Sets the insets. 291 * 292 * @param insets the new insets. 293 */ 294 public void setInsets(Insets insets) { 295 this.insets = insets; 296 } 297 298 /** 299 * Returns the Insets. If <code>to</code> is non-null the resulting 300 * insets will be placed in it, otherwise a new Insets object will be 301 * created and returned. 302 * 303 * @param state SynthContext identifying requestor 304 * @param to Where to place Insets 305 * @return Insets. 306 */ 307 public Insets getInsets(SynthContext state, Insets to) { 308 if (to == null) { 309 to = new Insets(0, 0, 0, 0); 310 } 311 if (insets != null) { 312 to.left = insets.left; 313 to.right = insets.right; 314 to.top = insets.top; 315 to.bottom = insets.bottom; 316 } 317 else { 318 to.left = to.right = to.top = to.bottom = 0; 319 } 320 return to; 321 } 322 323 /** 324 * Sets the Painter to use for the border. 325 * 326 * @param painter Painter for the Border. 327 */ 328 public void setPainter(SynthPainter painter) { 329 this.painter = painter; 330 } 331 332 /** 333 * Returns the Painter for the passed in Component. This may return null. 334 * 335 * @param ss SynthContext identifying requestor 336 * @return Painter for the border 337 */ 338 public SynthPainter getPainter(SynthContext ss) { 339 return painter; 340 } 341 342 /** 343 * Sets whether or not the JComponent should be opaque. 344 * 345 * @param opaque Whether or not the JComponent should be opaque. 346 */ 347 public void setOpaque(boolean opaque) { 348 this.opaque = opaque; 349 } 350 351 /** 352 * Returns the value to initialize the opacity property of the Component 353 * to. A Style should NOT assume the opacity will remain this value, the 354 * developer may reset it or override it. 355 * 356 * @param ss SynthContext identifying requestor 357 * @return opaque Whether or not the JComponent is opaque. 358 */ 359 public boolean isOpaque(SynthContext ss) { 360 return opaque; 361 } 362 363 /** 364 * Sets style specific values. This does NOT copy the data, it 365 * assigns it directly to this Style. 366 * 367 * @param data Style specific values 368 */ 369 public void setData(Map<Object, Object> data) { 370 this.data = data; 371 } 372 373 /** 374 * Returns the style specific data. 375 * 376 * @return Style specific data. 377 */ 378 public Map<Object, Object> getData() { 379 return data; 380 } 381 382 /** 383 * Getter for a region specific style property. 384 * 385 * @param state SynthContext identifying requestor 386 * @param key Property being requested. 387 * @return Value of the named property 388 */ 389 public Object get(SynthContext state, Object key) { 390 // Look for the best match 391 StateInfo si = getStateInfo(state.getComponentState()); 392 if (si != null && si.getData() != null && getKeyFromData(si.getData(), key) != null) { 393 return getKeyFromData(si.getData(), key); 394 } 395 si = getStateInfo(0); 396 if (si != null && si.getData() != null && getKeyFromData(si.getData(), key) != null) { 397 return getKeyFromData(si.getData(), key); 398 } 399 if(getKeyFromData(data, key) != null) 400 return getKeyFromData(data, key); 401 return getDefaultValue(state, key); 402 } 403 404 405 private Object getKeyFromData(Map<Object, Object> stateData, Object key) { 406 Object value = null; 407 if (stateData != null) { 408 409 synchronized(stateData) { 410 value = stateData.get(key); 411 } 412 while (value == PENDING) { 413 synchronized(stateData) { 414 try { 415 stateData.wait(); 416 } catch (InterruptedException ie) {} 417 value = stateData.get(key); 418 } 419 } 420 if (value instanceof UIDefaults.LazyValue) { 421 synchronized(stateData) { 422 stateData.put(key, PENDING); 423 } 424 value = ((UIDefaults.LazyValue)value).createValue(null); 425 synchronized(stateData) { 426 stateData.put(key, value); 427 stateData.notifyAll(); 428 } 429 } 430 } 431 return value; 432 } 433 434 /** 435 * Returns the default value for a particular property. This is only 436 * invoked if this style doesn't define a property for <code>key</code>. 437 * 438 * @param context SynthContext identifying requestor 439 * @param key Property being requested. 440 * @return Value of the named property 441 */ 442 public Object getDefaultValue(SynthContext context, Object key) { 443 return super.get(context, key); 444 } 445 446 /** 447 * Creates a clone of this style. 448 * 449 * @return Clone of this style 450 */ 451 public Object clone() { 452 DefaultSynthStyle style; 453 try { 454 style = (DefaultSynthStyle)super.clone(); 455 } catch (CloneNotSupportedException cnse) { 456 return null; 457 } 458 if (states != null) { 459 style.states = new StateInfo[states.length]; 460 for (int counter = states.length - 1; counter >= 0; counter--) { 461 style.states[counter] = (StateInfo)states[counter].clone(); 462 } 463 } 464 if (data != null) { 465 style.data = new HashMap<>(); 466 style.data.putAll(data); 467 } 468 return style; 469 } 470 471 /** 472 * Merges the contents of this Style with that of the passed in Style, 473 * returning the resulting merged syle. Properties of this 474 * <code>DefaultSynthStyle</code> will take precedence over those of the 475 * passed in <code>DefaultSynthStyle</code>. For example, if this 476 * style specifics a non-null font, the returned style will have its 477 * font so to that regardless of the <code>style</code>'s font. 478 * 479 * @param style Style to add our styles to 480 * @return Merged style. 481 */ 482 public DefaultSynthStyle addTo(DefaultSynthStyle style) { 483 if (insets != null) { 484 style.insets = this.insets; 485 } 486 if (font != null) { 487 style.font = this.font; 488 } 489 if (painter != null) { 490 style.painter = this.painter; 491 } 492 if (synthGraphics != null) { 493 style.synthGraphics = this.synthGraphics; 494 } 495 style.opaque = opaque; 496 if (states != null) { 497 if (style.states == null) { 498 style.states = new StateInfo[states.length]; 499 for (int counter = states.length - 1; counter >= 0; counter--){ 500 if (states[counter] != null) { 501 style.states[counter] = (StateInfo)states[counter]. 502 clone(); 503 } 504 } 505 } 506 else { 507 // Find the number of new states in unique, merging any 508 // matching states as we go. Also, move any merge styles 509 // to the end to give them precedence. 510 int unique = 0; 511 // Number of StateInfos that match. 512 int matchCount = 0; 513 int maxOStyles = style.states.length; 514 for (int thisCounter = states.length - 1; thisCounter >= 0; 515 thisCounter--) { 516 int state = states[thisCounter].getComponentState(); 517 boolean found = false; 518 519 for (int oCounter = maxOStyles - 1 - matchCount; 520 oCounter >= 0; oCounter--) { 521 if (state == style.states[oCounter]. 522 getComponentState()) { 523 style.states[oCounter] = states[thisCounter]. 524 addTo(style.states[oCounter]); 525 // Move StateInfo to end, giving it precedence. 526 StateInfo tmp = style.states[maxOStyles - 1 - 527 matchCount]; 528 style.states[maxOStyles - 1 - matchCount] = 529 style.states[oCounter]; 530 style.states[oCounter] = tmp; 531 matchCount++; 532 found = true; 533 break; 534 } 535 } 536 if (!found) { 537 unique++; 538 } 539 } 540 if (unique != 0) { 541 // There are states that exist in this Style that 542 // don't exist in the other style, recreate the array 543 // and add them. 544 StateInfo[] newStates = new StateInfo[ 545 unique + maxOStyles]; 546 int newIndex = maxOStyles; 547 548 System.arraycopy(style.states, 0, newStates, 0,maxOStyles); 549 for (int thisCounter = states.length - 1; thisCounter >= 0; 550 thisCounter--) { 551 int state = states[thisCounter].getComponentState(); 552 boolean found = false; 553 554 for (int oCounter = maxOStyles - 1; oCounter >= 0; 555 oCounter--) { 556 if (state == style.states[oCounter]. 557 getComponentState()) { 558 found = true; 559 break; 560 } 561 } 562 if (!found) { 563 newStates[newIndex++] = (StateInfo)states[ 564 thisCounter].clone(); 565 } 566 } 567 style.states = newStates; 568 } 569 } 570 } 571 if (data != null) { 572 if (style.data == null) { 573 style.data = new HashMap<>(); 574 } 575 style.data.putAll(data); 576 } 577 return style; 578 } 579 580 /** 581 * Sets the array of StateInfo's which are used to specify properties 582 * specific to a particular style. 583 * 584 * @param states StateInfos 585 */ 586 public void setStateInfo(StateInfo[] states) { 587 this.states = states; 588 } 589 590 /** 591 * Returns the array of StateInfo's that that are used to specify 592 * properties specific to a particular style. 593 * 594 * @return Array of StateInfos. 595 */ 596 public StateInfo[] getStateInfo() { 597 return states; 598 } 599 600 /** 601 * Returns the best matching StateInfo for a particular state. 602 * 603 * @param state Component state. 604 * @return Best matching StateInfo, or null 605 */ 606 public StateInfo getStateInfo(int state) { 607 // Use the StateInfo with the most bits that matches that of state. 608 // If there is none, than fallback to 609 // the StateInfo with a state of 0, indicating it'll match anything. 610 611 // Consider if we have 3 StateInfos a, b and c with states: 612 // SELECTED, SELECTED | ENABLED, 0 613 // 614 // Input Return Value 615 // ----- ------------ 616 // SELECTED a 617 // SELECTED | ENABLED b 618 // MOUSE_OVER c 619 // SELECTED | ENABLED | FOCUSED b 620 // ENABLED c 621 622 if (states != null) { 623 int bestCount = 0; 624 int bestIndex = -1; 625 int wildIndex = -1; 626 627 if (state == 0) { 628 for (int counter = states.length - 1; counter >= 0;counter--) { 629 if (states[counter].getComponentState() == 0) { 630 return states[counter]; 631 } 632 } 633 return null; 634 } 635 for (int counter = states.length - 1; counter >= 0; counter--) { 636 int oState = states[counter].getComponentState(); 637 638 if (oState == 0) { 639 if (wildIndex == -1) { 640 wildIndex = counter; 641 } 642 } 643 else if ((state & oState) == oState) { 644 // This is key, we need to make sure all bits of the 645 // StateInfo match, otherwise a StateInfo with 646 // SELECTED | ENABLED would match ENABLED, which we 647 // don't want. 648 649 // This comes from BigInteger.bitCnt 650 int bitCount = oState; 651 bitCount -= (0xaaaaaaaa & bitCount) >>> 1; 652 bitCount = (bitCount & 0x33333333) + ((bitCount >>> 2) & 653 0x33333333); 654 bitCount = bitCount + (bitCount >>> 4) & 0x0f0f0f0f; 655 bitCount += bitCount >>> 8; 656 bitCount += bitCount >>> 16; 657 bitCount = bitCount & 0xff; 658 if (bitCount > bestCount) { 659 bestIndex = counter; 660 bestCount = bitCount; 661 } 662 } 663 } 664 if (bestIndex != -1) { 665 return states[bestIndex]; 666 } 667 if (wildIndex != -1) { 668 return states[wildIndex]; 669 } 670 } 671 return null; 672 } 673 674 675 public String toString() { 676 StringBuilder sb = new StringBuilder(); 677 678 sb.append(super.toString()).append(','); 679 680 sb.append("data=").append(data).append(','); 681 682 sb.append("font=").append(font).append(','); 683 684 sb.append("insets=").append(insets).append(','); 685 686 sb.append("synthGraphics=").append(synthGraphics).append(','); 687 688 sb.append("painter=").append(painter).append(','); 689 690 StateInfo[] states = getStateInfo(); 691 if (states != null) { 692 sb.append("states["); 693 for (StateInfo state : states) { 694 sb.append(state.toString()).append(','); 695 } 696 sb.append(']').append(','); 697 } 698 699 // remove last newline 700 sb.deleteCharAt(sb.length() - 1); 701 702 return sb.toString(); 703 } 704 705 706 /** 707 * StateInfo represents Style information specific to the state of 708 * a component. 709 */ 710 public static class StateInfo { 711 private Map<Object, Object> data; 712 private Font font; 713 private Color[] colors; 714 private int state; 715 716 /** 717 * Creates a new StateInfo. 718 */ 719 public StateInfo() { 720 } 721 722 /** 723 * Creates a new StateInfo with the specified properties 724 * 725 * @param state Component state(s) that this StateInfo should be used 726 * for 727 * @param font Font for this state 728 * @param colors Colors for this state 729 */ 730 public StateInfo(int state, Font font, Color[] colors) { 731 this.state = state; 732 this.font = font; 733 this.colors = colors; 734 } 735 736 /** 737 * Creates a new StateInfo that is a copy of the passed in 738 * StateInfo. 739 * 740 * @param info StateInfo to copy. 741 */ 742 public StateInfo(StateInfo info) { 743 this.state = info.state; 744 this.font = info.font; 745 if(info.data != null) { 746 if(data == null) { 747 data = new HashMap<>(); 748 } 749 data.putAll(info.data); 750 } 751 if (info.colors != null) { 752 this.colors = new Color[info.colors.length]; 753 System.arraycopy(info.colors, 0, colors, 0,info.colors.length); 754 } 755 } 756 757 public Map<Object, Object> getData() { 758 return data; 759 } 760 761 public void setData(Map<Object, Object> data) { 762 this.data = data; 763 } 764 765 /** 766 * Sets the font for this state. 767 * 768 * @param font Font to use for rendering 769 */ 770 public void setFont(Font font) { 771 this.font = font; 772 } 773 774 /** 775 * Returns the font for this state. 776 * 777 * @return Returns the font to use for rendering this state 778 */ 779 public Font getFont() { 780 return font; 781 } 782 783 /** 784 * Sets the array of colors to use for rendering this state. This 785 * is indexed by <code>ColorType.getID()</code>. 786 * 787 * @param colors Array of colors 788 */ 789 public void setColors(Color[] colors) { 790 this.colors = colors; 791 } 792 793 /** 794 * Returns the array of colors to use for rendering this state. This 795 * is indexed by <code>ColorType.getID()</code>. 796 * 797 * @return Array of colors 798 */ 799 public Color[] getColors() { 800 return colors; 801 } 802 803 /** 804 * Returns the Color to used for the specified ColorType. 805 * 806 * @return Color. 807 */ 808 public Color getColor(ColorType type) { 809 if (colors != null) { 810 int id = type.getID(); 811 812 if (id < colors.length) { 813 return colors[id]; 814 } 815 } 816 return null; 817 } 818 819 /** 820 * Merges the contents of this StateInfo with that of the passed in 821 * StateInfo, returning the resulting merged StateInfo. Properties of 822 * this <code>StateInfo</code> will take precedence over those of the 823 * passed in <code>StateInfo</code>. For example, if this 824 * StateInfo specifics a non-null font, the returned StateInfo will 825 * have its font so to that regardless of the <code>StateInfo</code>'s 826 * font. 827 * 828 * @param info StateInfo to add our styles to 829 * @return Merged StateInfo. 830 */ 831 public StateInfo addTo(StateInfo info) { 832 if (font != null) { 833 info.font = font; 834 } 835 if(data != null) { 836 if(info.data == null) { 837 info.data = new HashMap<>(); 838 } 839 info.data.putAll(data); 840 } 841 if (colors != null) { 842 if (info.colors == null) { 843 info.colors = new Color[colors.length]; 844 System.arraycopy(colors, 0, info.colors, 0, 845 colors.length); 846 } 847 else { 848 if (info.colors.length < colors.length) { 849 Color[] old = info.colors; 850 851 info.colors = new Color[colors.length]; 852 System.arraycopy(old, 0, info.colors, 0, old.length); 853 } 854 for (int counter = colors.length - 1; counter >= 0; 855 counter--) { 856 if (colors[counter] != null) { 857 info.colors[counter] = colors[counter]; 858 } 859 } 860 } 861 } 862 return info; 863 } 864 865 /** 866 * Sets the state this StateInfo corresponds to. 867 * 868 * @see SynthConstants 869 * @param state info. 870 */ 871 public void setComponentState(int state) { 872 this.state = state; 873 } 874 875 /** 876 * Returns the state this StateInfo corresponds to. 877 * 878 * @see SynthConstants 879 * @return state info. 880 */ 881 public int getComponentState() { 882 return state; 883 } 884 885 /** 886 * Returns the number of states that are similar between the 887 * ComponentState this StateInfo represents and val. 888 */ 889 private int getMatchCount(int val) { 890 // This comes from BigInteger.bitCnt 891 val &= state; 892 val -= (0xaaaaaaaa & val) >>> 1; 893 val = (val & 0x33333333) + ((val >>> 2) & 0x33333333); 894 val = val + (val >>> 4) & 0x0f0f0f0f; 895 val += val >>> 8; 896 val += val >>> 16; 897 return val & 0xff; 898 } 899 900 /** 901 * Creates and returns a copy of this StateInfo. 902 * 903 * @return Copy of this StateInfo. 904 */ 905 public Object clone() { 906 return new StateInfo(this); 907 } 908 909 public String toString() { 910 StringBuilder sb = new StringBuilder(); 911 912 sb.append(super.toString()).append(','); 913 914 sb.append("state=").append(Integer.toString(state)).append(','); 915 916 sb.append("font=").append(font).append(','); 917 918 if (colors != null) { 919 sb.append("colors=").append(Arrays.asList(colors)). 920 append(','); 921 } 922 return sb.toString(); 923 } 924 } 925 }