blob: de209df68eb195ba9f8fe16c23f0f883fdec4cda [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2002-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package sun.swing.plaf.synth;
26
27import javax.swing.plaf.synth.*;
28import java.awt.*;
29import java.util.*;
30import javax.swing.*;
31import javax.swing.border.Border;
32import javax.swing.plaf.*;
33
34/**
35 * Default implementation of SynthStyle. Has setters for the various
36 * SynthStyle methods. Many of the properties can be specified for all states,
37 * using SynthStyle directly, or a specific state using one of the StateInfo
38 * methods.
39 * <p>
40 * Beyond the constructor a subclass should override the <code>addTo</code>
41 * and <code>clone</code> methods, these are used when the Styles are being
42 * merged into a resulting style.
43 *
44 * @author Scott Violet
45 */
46public class DefaultSynthStyle extends SynthStyle implements Cloneable {
47 private static final Object PENDING = new String("Pending");
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 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 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 indentifying 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.
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 context SynthContext indentifying 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 indentifying 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 indentifying 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 data) {
370 this.data = data;
371 }
372
373 /**
374 * Returns the style specific data.
375 *
376 * @return Style specific data.
377 */
378 public Map getData() {
379 return data;
380 }
381
382 /**
383 * Getter for a region specific style property.
384 *
385 * @param state SynthContext indentifying 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 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 state SynthContext indentifying 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 StringBuffer buf = new StringBuffer();
677
678 buf.append(super.toString()).append(',');
679
680 buf.append("data=").append(data).append(',');
681
682 buf.append("font=").append(font).append(',');
683
684 buf.append("insets=").append(insets).append(',');
685
686 buf.append("synthGraphics=").append(synthGraphics).append(',');
687
688 buf.append("painter=").append(painter).append(',');
689
690 StateInfo[] states = getStateInfo();
691 if (states != null) {
692 buf.append("states[");
693 for (int i = 0; i < states.length; i++) {
694 buf.append(states[i].toString()).append(',');
695 }
696 buf.append(']').append(',');
697 }
698
699 // remove last newline
700 buf.deleteCharAt(buf.length() - 1);
701
702 return buf.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 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 painter Painter responsible for rendering
728 * @param bgPainter Painter responsible for rendering the background
729 * @param font Font for this state
730 * @param colors Colors for this state
731 */
732 public StateInfo(int state, Font font, Color[] colors) {
733 this.state = state;
734 this.font = font;
735 this.colors = colors;
736 }
737
738 /**
739 * Creates a new StateInfo that is a copy of the passed in
740 * StateInfo.
741 *
742 * @param info StateInfo to copy.
743 */
744 public StateInfo(StateInfo info) {
745 this.state = info.state;
746 this.font = info.font;
747 if(info.data != null) {
748 if(data == null) {
749 data = new HashMap();
750 }
751 data.putAll(info.data);
752 }
753 if (info.colors != null) {
754 this.colors = new Color[info.colors.length];
755 System.arraycopy(info.colors, 0, colors, 0,info.colors.length);
756 }
757 }
758
759 public Map getData() {
760 return data;
761 }
762
763 public void setData(Map data) {
764 this.data = data;
765 }
766
767 /**
768 * Sets the font for this state.
769 *
770 * @param font Font to use for rendering
771 */
772 public void setFont(Font font) {
773 this.font = font;
774 }
775
776 /**
777 * Returns the font for this state.
778 *
779 * @return Returns the font to use for rendering this state
780 */
781 public Font getFont() {
782 return font;
783 }
784
785 /**
786 * Sets the array of colors to use for rendering this state. This
787 * is indexed by <code>ColorType.getID()</code>.
788 *
789 * @param colors Array of colors
790 */
791 public void setColors(Color[] colors) {
792 this.colors = colors;
793 }
794
795 /**
796 * Returns the array of colors to use for rendering this state. This
797 * is indexed by <code>ColorType.getID()</code>.
798 *
799 * @return Array of colors
800 */
801 public Color[] getColors() {
802 return colors;
803 }
804
805 /**
806 * Returns the Color to used for the specified ColorType.
807 *
808 * @return Color.
809 */
810 public Color getColor(ColorType type) {
811 if (colors != null) {
812 int id = type.getID();
813
814 if (id < colors.length) {
815 return colors[id];
816 }
817 }
818 return null;
819 }
820
821 /**
822 * Merges the contents of this StateInfo with that of the passed in
823 * StateInfo, returning the resulting merged StateInfo. Properties of
824 * this <code>StateInfo</code> will take precedence over those of the
825 * passed in <code>StateInfo</code>. For example, if this
826 * StateInfo specifics a non-null font, the returned StateInfo will
827 * have its font so to that regardless of the <code>StateInfo</code>'s
828 * font.
829 *
830 * @param info StateInfo to add our styles to
831 * @return Merged StateInfo.
832 */
833 public StateInfo addTo(StateInfo info) {
834 if (font != null) {
835 info.font = font;
836 }
837 if(data != null) {
838 if(info.data == null) {
839 info.data = new HashMap();
840 }
841 info.data.putAll(data);
842 }
843 if (colors != null) {
844 if (info.colors == null) {
845 info.colors = new Color[colors.length];
846 System.arraycopy(colors, 0, info.colors, 0,
847 colors.length);
848 }
849 else {
850 if (info.colors.length < colors.length) {
851 Color[] old = info.colors;
852
853 info.colors = new Color[colors.length];
854 System.arraycopy(old, 0, info.colors, 0, old.length);
855 }
856 for (int counter = colors.length - 1; counter >= 0;
857 counter--) {
858 if (colors[counter] != null) {
859 info.colors[counter] = colors[counter];
860 }
861 }
862 }
863 }
864 return info;
865 }
866
867 /**
868 * Sets the state this StateInfo corresponds to.
869 *
870 * @see SynthConstants
871 * @param state info.
872 */
873 public void setComponentState(int state) {
874 this.state = state;
875 }
876
877 /**
878 * Returns the state this StateInfo corresponds to.
879 *
880 * @see SynthConstants
881 * @return state info.
882 */
883 public int getComponentState() {
884 return state;
885 }
886
887 /**
888 * Returns the number of states that are similar between the
889 * ComponentState this StateInfo represents and val.
890 */
891 private final int getMatchCount(int val) {
892 // This comes from BigInteger.bitCnt
893 val &= state;
894 val -= (0xaaaaaaaa & val) >>> 1;
895 val = (val & 0x33333333) + ((val >>> 2) & 0x33333333);
896 val = val + (val >>> 4) & 0x0f0f0f0f;
897 val += val >>> 8;
898 val += val >>> 16;
899 return val & 0xff;
900 }
901
902 /**
903 * Creates and returns a copy of this StateInfo.
904 *
905 * @return Copy of this StateInfo.
906 */
907 public Object clone() {
908 return new StateInfo(this);
909 }
910
911 public String toString() {
912 StringBuffer buf = new StringBuffer();
913
914 buf.append(super.toString()).append(',');
915
916 buf.append("state=").append(Integer.toString(state)).append(',');
917
918 buf.append("font=").append(font).append(',');
919
920 if (colors != null) {
921 buf.append("colors=").append(Arrays.asList(colors)).
922 append(',');
923 }
924 return buf.toString();
925 }
926 }
927}