| /* |
| * Copyright 2002-2005 Sun Microsystems, Inc. All Rights Reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Sun designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Sun in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| * CA 95054 USA or visit www.sun.com if you need additional information or |
| * have any questions. |
| */ |
| package sun.swing.plaf.synth; |
| |
| import javax.swing.plaf.synth.*; |
| import java.awt.*; |
| import java.util.*; |
| import javax.swing.*; |
| import javax.swing.border.Border; |
| import javax.swing.plaf.*; |
| |
| /** |
| * Default implementation of SynthStyle. Has setters for the various |
| * SynthStyle methods. Many of the properties can be specified for all states, |
| * using SynthStyle directly, or a specific state using one of the StateInfo |
| * methods. |
| * <p> |
| * Beyond the constructor a subclass should override the <code>addTo</code> |
| * and <code>clone</code> methods, these are used when the Styles are being |
| * merged into a resulting style. |
| * |
| * @author Scott Violet |
| */ |
| public class DefaultSynthStyle extends SynthStyle implements Cloneable { |
| private static final String PENDING = "Pending"; |
| |
| /** |
| * Should the component be opaque? |
| */ |
| private boolean opaque; |
| /** |
| * Insets. |
| */ |
| private Insets insets; |
| /** |
| * Information specific to ComponentState. |
| */ |
| private StateInfo[] states; |
| /** |
| * User specific data. |
| */ |
| private Map data; |
| |
| /** |
| * Font to use if there is no matching StateInfo, or the StateInfo doesn't |
| * define one. |
| */ |
| private Font font; |
| |
| /** |
| * SynthGraphics, may be null. |
| */ |
| private SynthGraphicsUtils synthGraphics; |
| |
| /** |
| * Painter to use if the StateInfo doesn't have one. |
| */ |
| private SynthPainter painter; |
| |
| |
| /** |
| * Nullary constructor, intended for subclassers. |
| */ |
| public DefaultSynthStyle() { |
| } |
| |
| /** |
| * Creates a new DefaultSynthStyle that is a copy of the passed in |
| * style. Any StateInfo's of the passed in style are clonsed as well. |
| * |
| * @param style Style to duplicate |
| */ |
| public DefaultSynthStyle(DefaultSynthStyle style) { |
| opaque = style.opaque; |
| if (style.insets != null) { |
| insets = new Insets(style.insets.top, style.insets.left, |
| style.insets.bottom, style.insets.right); |
| } |
| if (style.states != null) { |
| states = new StateInfo[style.states.length]; |
| for (int counter = style.states.length - 1; counter >= 0; |
| counter--) { |
| states[counter] = (StateInfo)style.states[counter].clone(); |
| } |
| } |
| if (style.data != null) { |
| data = new HashMap(); |
| data.putAll(style.data); |
| } |
| font = style.font; |
| synthGraphics = style.synthGraphics; |
| painter = style.painter; |
| } |
| |
| /** |
| * Creates a new DefaultSynthStyle. |
| * |
| * @param insets Insets for the Style |
| * @param opaque Whether or not the background is completely painted in |
| * an opaque color |
| * @param states StateInfos describing properties per state |
| * @param data Style specific data. |
| */ |
| public DefaultSynthStyle(Insets insets, boolean opaque, |
| StateInfo[] states, Map data) { |
| this.insets = insets; |
| this.opaque = opaque; |
| this.states = states; |
| this.data = data; |
| } |
| |
| public Color getColor(SynthContext context, ColorType type) { |
| return getColor(context.getComponent(), context.getRegion(), |
| context.getComponentState(), type); |
| } |
| |
| public Color getColor(JComponent c, Region id, int state, |
| ColorType type) { |
| // For the enabled state, prefer the widget's colors |
| if (!id.isSubregion() && state == SynthConstants.ENABLED) { |
| if (type == ColorType.BACKGROUND) { |
| return c.getBackground(); |
| } |
| else if (type == ColorType.FOREGROUND) { |
| return c.getForeground(); |
| } |
| else if (type == ColorType.TEXT_FOREGROUND) { |
| // If getForeground returns a non-UIResource it means the |
| // developer has explicitly set the foreground, use it over |
| // that of TEXT_FOREGROUND as that is typically the expected |
| // behavior. |
| Color color = c.getForeground(); |
| if (!(color instanceof UIResource)) { |
| return color; |
| } |
| } |
| } |
| // Then use what we've locally defined |
| Color color = getColorForState(c, id, state, type); |
| if (color == null) { |
| // No color, fallback to that of the widget. |
| if (type == ColorType.BACKGROUND || |
| type == ColorType.TEXT_BACKGROUND) { |
| return c.getBackground(); |
| } |
| else if (type == ColorType.FOREGROUND || |
| type == ColorType.TEXT_FOREGROUND) { |
| return c.getForeground(); |
| } |
| } |
| return color; |
| } |
| |
| protected Color getColorForState(SynthContext context, ColorType type) { |
| return getColorForState(context.getComponent(), context.getRegion(), |
| context.getComponentState(), type); |
| } |
| |
| /** |
| * Returns the color for the specified state. |
| * |
| * @param c JComponent the style is associated with |
| * @param id Region identifier |
| * @param state State of the region. |
| * @param type Type of color being requested. |
| * @return Color to render with |
| */ |
| protected Color getColorForState(JComponent c, Region id, int state, |
| ColorType type) { |
| // Use the best state. |
| StateInfo si = getStateInfo(state); |
| Color color; |
| if (si != null && (color = si.getColor(type)) != null) { |
| return color; |
| } |
| if (si == null || si.getComponentState() != 0) { |
| si = getStateInfo(0); |
| if (si != null) { |
| return si.getColor(type); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Sets the font that is used if there is no matching StateInfo, or |
| * it does not define a font. |
| * |
| * @param font Font to use for rendering |
| */ |
| public void setFont(Font font) { |
| this.font = font; |
| } |
| |
| public Font getFont(SynthContext state) { |
| return getFont(state.getComponent(), state.getRegion(), |
| state.getComponentState()); |
| } |
| |
| public Font getFont(JComponent c, Region id, int state) { |
| if (!id.isSubregion() && state == SynthConstants.ENABLED) { |
| return c.getFont(); |
| } |
| Font cFont = c.getFont(); |
| if (cFont != null && !(cFont instanceof UIResource)) { |
| return cFont; |
| } |
| return getFontForState(c, id, state); |
| } |
| |
| /** |
| * Returns the font for the specified state. This should NOT callback |
| * to the JComponent. |
| * |
| * @param c JComponent the style is associated with |
| * @param id Region identifier |
| * @param state State of the region. |
| * @return Font to render with |
| */ |
| protected Font getFontForState(JComponent c, Region id, int state) { |
| if (c == null) { |
| return this.font; |
| } |
| // First pass, look for the best match |
| StateInfo si = getStateInfo(state); |
| Font font; |
| if (si != null && (font = si.getFont()) != null) { |
| return font; |
| } |
| if (si == null || si.getComponentState() != 0) { |
| si = getStateInfo(0); |
| if (si != null && (font = si.getFont()) != null) { |
| return font; |
| } |
| } |
| // Fallback font. |
| return this.font; |
| } |
| |
| protected Font getFontForState(SynthContext context) { |
| return getFontForState(context.getComponent(), context.getRegion(), |
| context.getComponentState()); |
| } |
| |
| /** |
| * Sets the SynthGraphicsUtils that will be used for rendering. |
| * |
| * @param graphics SynthGraphics |
| */ |
| public void setGraphicsUtils(SynthGraphicsUtils graphics) { |
| this.synthGraphics = graphics; |
| } |
| |
| /** |
| * Returns a SynthGraphicsUtils. |
| * |
| * @param context SynthContext indentifying requestor |
| * @return SynthGraphicsUtils |
| */ |
| public SynthGraphicsUtils getGraphicsUtils(SynthContext context) { |
| if (synthGraphics == null) { |
| return super.getGraphicsUtils(context); |
| } |
| return synthGraphics; |
| } |
| |
| /** |
| * Sets the insets. |
| * |
| * @param Insets. |
| */ |
| public void setInsets(Insets insets) { |
| this.insets = insets; |
| } |
| |
| /** |
| * Returns the Insets. If <code>to</code> is non-null the resulting |
| * insets will be placed in it, otherwise a new Insets object will be |
| * created and returned. |
| * |
| * @param context SynthContext indentifying requestor |
| * @param to Where to place Insets |
| * @return Insets. |
| */ |
| public Insets getInsets(SynthContext state, Insets to) { |
| if (to == null) { |
| to = new Insets(0, 0, 0, 0); |
| } |
| if (insets != null) { |
| to.left = insets.left; |
| to.right = insets.right; |
| to.top = insets.top; |
| to.bottom = insets.bottom; |
| } |
| else { |
| to.left = to.right = to.top = to.bottom = 0; |
| } |
| return to; |
| } |
| |
| /** |
| * Sets the Painter to use for the border. |
| * |
| * @param painter Painter for the Border. |
| */ |
| public void setPainter(SynthPainter painter) { |
| this.painter = painter; |
| } |
| |
| /** |
| * Returns the Painter for the passed in Component. This may return null. |
| * |
| * @param ss SynthContext indentifying requestor |
| * @return Painter for the border |
| */ |
| public SynthPainter getPainter(SynthContext ss) { |
| return painter; |
| } |
| |
| /** |
| * Sets whether or not the JComponent should be opaque. |
| * |
| * @param opaque Whether or not the JComponent should be opaque. |
| */ |
| public void setOpaque(boolean opaque) { |
| this.opaque = opaque; |
| } |
| |
| /** |
| * Returns the value to initialize the opacity property of the Component |
| * to. A Style should NOT assume the opacity will remain this value, the |
| * developer may reset it or override it. |
| * |
| * @param ss SynthContext indentifying requestor |
| * @return opaque Whether or not the JComponent is opaque. |
| */ |
| public boolean isOpaque(SynthContext ss) { |
| return opaque; |
| } |
| |
| /** |
| * Sets style specific values. This does NOT copy the data, it |
| * assigns it directly to this Style. |
| * |
| * @param data Style specific values |
| */ |
| public void setData(Map data) { |
| this.data = data; |
| } |
| |
| /** |
| * Returns the style specific data. |
| * |
| * @return Style specific data. |
| */ |
| public Map getData() { |
| return data; |
| } |
| |
| /** |
| * Getter for a region specific style property. |
| * |
| * @param state SynthContext indentifying requestor |
| * @param key Property being requested. |
| * @return Value of the named property |
| */ |
| public Object get(SynthContext state, Object key) { |
| // Look for the best match |
| StateInfo si = getStateInfo(state.getComponentState()); |
| if (si != null && si.getData() != null && getKeyFromData(si.getData(), key) != null) { |
| return getKeyFromData(si.getData(), key); |
| } |
| si = getStateInfo(0); |
| if (si != null && si.getData() != null && getKeyFromData(si.getData(), key) != null) { |
| return getKeyFromData(si.getData(), key); |
| } |
| if(getKeyFromData(data, key) != null) |
| return getKeyFromData(data, key); |
| return getDefaultValue(state, key); |
| } |
| |
| |
| private Object getKeyFromData(Map stateData, Object key) { |
| Object value = null; |
| if (stateData != null) { |
| |
| synchronized(stateData) { |
| value = stateData.get(key); |
| } |
| while (value == PENDING) { |
| synchronized(stateData) { |
| try { |
| stateData.wait(); |
| } catch (InterruptedException ie) {} |
| value = stateData.get(key); |
| } |
| } |
| if (value instanceof UIDefaults.LazyValue) { |
| synchronized(stateData) { |
| stateData.put(key, PENDING); |
| } |
| value = ((UIDefaults.LazyValue)value).createValue(null); |
| synchronized(stateData) { |
| stateData.put(key, value); |
| stateData.notifyAll(); |
| } |
| } |
| } |
| return value; |
| } |
| |
| /** |
| * Returns the default value for a particular property. This is only |
| * invoked if this style doesn't define a property for <code>key</code>. |
| * |
| * @param state SynthContext indentifying requestor |
| * @param key Property being requested. |
| * @return Value of the named property |
| */ |
| public Object getDefaultValue(SynthContext context, Object key) { |
| return super.get(context, key); |
| } |
| |
| /** |
| * Creates a clone of this style. |
| * |
| * @return Clone of this style |
| */ |
| public Object clone() { |
| DefaultSynthStyle style; |
| try { |
| style = (DefaultSynthStyle)super.clone(); |
| } catch (CloneNotSupportedException cnse) { |
| return null; |
| } |
| if (states != null) { |
| style.states = new StateInfo[states.length]; |
| for (int counter = states.length - 1; counter >= 0; counter--) { |
| style.states[counter] = (StateInfo)states[counter].clone(); |
| } |
| } |
| if (data != null) { |
| style.data = new HashMap(); |
| style.data.putAll(data); |
| } |
| return style; |
| } |
| |
| /** |
| * Merges the contents of this Style with that of the passed in Style, |
| * returning the resulting merged syle. Properties of this |
| * <code>DefaultSynthStyle</code> will take precedence over those of the |
| * passed in <code>DefaultSynthStyle</code>. For example, if this |
| * style specifics a non-null font, the returned style will have its |
| * font so to that regardless of the <code>style</code>'s font. |
| * |
| * @param style Style to add our styles to |
| * @return Merged style. |
| */ |
| public DefaultSynthStyle addTo(DefaultSynthStyle style) { |
| if (insets != null) { |
| style.insets = this.insets; |
| } |
| if (font != null) { |
| style.font = this.font; |
| } |
| if (painter != null) { |
| style.painter = this.painter; |
| } |
| if (synthGraphics != null) { |
| style.synthGraphics = this.synthGraphics; |
| } |
| style.opaque = opaque; |
| if (states != null) { |
| if (style.states == null) { |
| style.states = new StateInfo[states.length]; |
| for (int counter = states.length - 1; counter >= 0; counter--){ |
| if (states[counter] != null) { |
| style.states[counter] = (StateInfo)states[counter]. |
| clone(); |
| } |
| } |
| } |
| else { |
| // Find the number of new states in unique, merging any |
| // matching states as we go. Also, move any merge styles |
| // to the end to give them precedence. |
| int unique = 0; |
| // Number of StateInfos that match. |
| int matchCount = 0; |
| int maxOStyles = style.states.length; |
| for (int thisCounter = states.length - 1; thisCounter >= 0; |
| thisCounter--) { |
| int state = states[thisCounter].getComponentState(); |
| boolean found = false; |
| |
| for (int oCounter = maxOStyles - 1 - matchCount; |
| oCounter >= 0; oCounter--) { |
| if (state == style.states[oCounter]. |
| getComponentState()) { |
| style.states[oCounter] = states[thisCounter]. |
| addTo(style.states[oCounter]); |
| // Move StateInfo to end, giving it precedence. |
| StateInfo tmp = style.states[maxOStyles - 1 - |
| matchCount]; |
| style.states[maxOStyles - 1 - matchCount] = |
| style.states[oCounter]; |
| style.states[oCounter] = tmp; |
| matchCount++; |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| unique++; |
| } |
| } |
| if (unique != 0) { |
| // There are states that exist in this Style that |
| // don't exist in the other style, recreate the array |
| // and add them. |
| StateInfo[] newStates = new StateInfo[ |
| unique + maxOStyles]; |
| int newIndex = maxOStyles; |
| |
| System.arraycopy(style.states, 0, newStates, 0,maxOStyles); |
| for (int thisCounter = states.length - 1; thisCounter >= 0; |
| thisCounter--) { |
| int state = states[thisCounter].getComponentState(); |
| boolean found = false; |
| |
| for (int oCounter = maxOStyles - 1; oCounter >= 0; |
| oCounter--) { |
| if (state == style.states[oCounter]. |
| getComponentState()) { |
| found = true; |
| break; |
| } |
| } |
| if (!found) { |
| newStates[newIndex++] = (StateInfo)states[ |
| thisCounter].clone(); |
| } |
| } |
| style.states = newStates; |
| } |
| } |
| } |
| if (data != null) { |
| if (style.data == null) { |
| style.data = new HashMap(); |
| } |
| style.data.putAll(data); |
| } |
| return style; |
| } |
| |
| /** |
| * Sets the array of StateInfo's which are used to specify properties |
| * specific to a particular style. |
| * |
| * @param states StateInfos |
| */ |
| public void setStateInfo(StateInfo[] states) { |
| this.states = states; |
| } |
| |
| /** |
| * Returns the array of StateInfo's that that are used to specify |
| * properties specific to a particular style. |
| * |
| * @return Array of StateInfos. |
| */ |
| public StateInfo[] getStateInfo() { |
| return states; |
| } |
| |
| /** |
| * Returns the best matching StateInfo for a particular state. |
| * |
| * @param state Component state. |
| * @return Best matching StateInfo, or null |
| */ |
| public StateInfo getStateInfo(int state) { |
| // Use the StateInfo with the most bits that matches that of state. |
| // If there is none, than fallback to |
| // the StateInfo with a state of 0, indicating it'll match anything. |
| |
| // Consider if we have 3 StateInfos a, b and c with states: |
| // SELECTED, SELECTED | ENABLED, 0 |
| // |
| // Input Return Value |
| // ----- ------------ |
| // SELECTED a |
| // SELECTED | ENABLED b |
| // MOUSE_OVER c |
| // SELECTED | ENABLED | FOCUSED b |
| // ENABLED c |
| |
| if (states != null) { |
| int bestCount = 0; |
| int bestIndex = -1; |
| int wildIndex = -1; |
| |
| if (state == 0) { |
| for (int counter = states.length - 1; counter >= 0;counter--) { |
| if (states[counter].getComponentState() == 0) { |
| return states[counter]; |
| } |
| } |
| return null; |
| } |
| for (int counter = states.length - 1; counter >= 0; counter--) { |
| int oState = states[counter].getComponentState(); |
| |
| if (oState == 0) { |
| if (wildIndex == -1) { |
| wildIndex = counter; |
| } |
| } |
| else if ((state & oState) == oState) { |
| // This is key, we need to make sure all bits of the |
| // StateInfo match, otherwise a StateInfo with |
| // SELECTED | ENABLED would match ENABLED, which we |
| // don't want. |
| |
| // This comes from BigInteger.bitCnt |
| int bitCount = oState; |
| bitCount -= (0xaaaaaaaa & bitCount) >>> 1; |
| bitCount = (bitCount & 0x33333333) + ((bitCount >>> 2) & |
| 0x33333333); |
| bitCount = bitCount + (bitCount >>> 4) & 0x0f0f0f0f; |
| bitCount += bitCount >>> 8; |
| bitCount += bitCount >>> 16; |
| bitCount = bitCount & 0xff; |
| if (bitCount > bestCount) { |
| bestIndex = counter; |
| bestCount = bitCount; |
| } |
| } |
| } |
| if (bestIndex != -1) { |
| return states[bestIndex]; |
| } |
| if (wildIndex != -1) { |
| return states[wildIndex]; |
| } |
| } |
| return null; |
| } |
| |
| |
| public String toString() { |
| StringBuffer buf = new StringBuffer(); |
| |
| buf.append(super.toString()).append(','); |
| |
| buf.append("data=").append(data).append(','); |
| |
| buf.append("font=").append(font).append(','); |
| |
| buf.append("insets=").append(insets).append(','); |
| |
| buf.append("synthGraphics=").append(synthGraphics).append(','); |
| |
| buf.append("painter=").append(painter).append(','); |
| |
| StateInfo[] states = getStateInfo(); |
| if (states != null) { |
| buf.append("states["); |
| for (StateInfo state : states) { |
| buf.append(state.toString()).append(','); |
| } |
| buf.append(']').append(','); |
| } |
| |
| // remove last newline |
| buf.deleteCharAt(buf.length() - 1); |
| |
| return buf.toString(); |
| } |
| |
| |
| /** |
| * StateInfo represents Style information specific to the state of |
| * a component. |
| */ |
| public static class StateInfo { |
| private Map data; |
| private Font font; |
| private Color[] colors; |
| private int state; |
| |
| /** |
| * Creates a new StateInfo. |
| */ |
| public StateInfo() { |
| } |
| |
| /** |
| * Creates a new StateInfo with the specified properties |
| * |
| * @param state Component state(s) that this StateInfo should be used |
| * for |
| * @param painter Painter responsible for rendering |
| * @param bgPainter Painter responsible for rendering the background |
| * @param font Font for this state |
| * @param colors Colors for this state |
| */ |
| public StateInfo(int state, Font font, Color[] colors) { |
| this.state = state; |
| this.font = font; |
| this.colors = colors; |
| } |
| |
| /** |
| * Creates a new StateInfo that is a copy of the passed in |
| * StateInfo. |
| * |
| * @param info StateInfo to copy. |
| */ |
| public StateInfo(StateInfo info) { |
| this.state = info.state; |
| this.font = info.font; |
| if(info.data != null) { |
| if(data == null) { |
| data = new HashMap(); |
| } |
| data.putAll(info.data); |
| } |
| if (info.colors != null) { |
| this.colors = new Color[info.colors.length]; |
| System.arraycopy(info.colors, 0, colors, 0,info.colors.length); |
| } |
| } |
| |
| public Map getData() { |
| return data; |
| } |
| |
| public void setData(Map data) { |
| this.data = data; |
| } |
| |
| /** |
| * Sets the font for this state. |
| * |
| * @param font Font to use for rendering |
| */ |
| public void setFont(Font font) { |
| this.font = font; |
| } |
| |
| /** |
| * Returns the font for this state. |
| * |
| * @return Returns the font to use for rendering this state |
| */ |
| public Font getFont() { |
| return font; |
| } |
| |
| /** |
| * Sets the array of colors to use for rendering this state. This |
| * is indexed by <code>ColorType.getID()</code>. |
| * |
| * @param colors Array of colors |
| */ |
| public void setColors(Color[] colors) { |
| this.colors = colors; |
| } |
| |
| /** |
| * Returns the array of colors to use for rendering this state. This |
| * is indexed by <code>ColorType.getID()</code>. |
| * |
| * @return Array of colors |
| */ |
| public Color[] getColors() { |
| return colors; |
| } |
| |
| /** |
| * Returns the Color to used for the specified ColorType. |
| * |
| * @return Color. |
| */ |
| public Color getColor(ColorType type) { |
| if (colors != null) { |
| int id = type.getID(); |
| |
| if (id < colors.length) { |
| return colors[id]; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Merges the contents of this StateInfo with that of the passed in |
| * StateInfo, returning the resulting merged StateInfo. Properties of |
| * this <code>StateInfo</code> will take precedence over those of the |
| * passed in <code>StateInfo</code>. For example, if this |
| * StateInfo specifics a non-null font, the returned StateInfo will |
| * have its font so to that regardless of the <code>StateInfo</code>'s |
| * font. |
| * |
| * @param info StateInfo to add our styles to |
| * @return Merged StateInfo. |
| */ |
| public StateInfo addTo(StateInfo info) { |
| if (font != null) { |
| info.font = font; |
| } |
| if(data != null) { |
| if(info.data == null) { |
| info.data = new HashMap(); |
| } |
| info.data.putAll(data); |
| } |
| if (colors != null) { |
| if (info.colors == null) { |
| info.colors = new Color[colors.length]; |
| System.arraycopy(colors, 0, info.colors, 0, |
| colors.length); |
| } |
| else { |
| if (info.colors.length < colors.length) { |
| Color[] old = info.colors; |
| |
| info.colors = new Color[colors.length]; |
| System.arraycopy(old, 0, info.colors, 0, old.length); |
| } |
| for (int counter = colors.length - 1; counter >= 0; |
| counter--) { |
| if (colors[counter] != null) { |
| info.colors[counter] = colors[counter]; |
| } |
| } |
| } |
| } |
| return info; |
| } |
| |
| /** |
| * Sets the state this StateInfo corresponds to. |
| * |
| * @see SynthConstants |
| * @param state info. |
| */ |
| public void setComponentState(int state) { |
| this.state = state; |
| } |
| |
| /** |
| * Returns the state this StateInfo corresponds to. |
| * |
| * @see SynthConstants |
| * @return state info. |
| */ |
| public int getComponentState() { |
| return state; |
| } |
| |
| /** |
| * Returns the number of states that are similar between the |
| * ComponentState this StateInfo represents and val. |
| */ |
| private int getMatchCount(int val) { |
| // This comes from BigInteger.bitCnt |
| val &= state; |
| val -= (0xaaaaaaaa & val) >>> 1; |
| val = (val & 0x33333333) + ((val >>> 2) & 0x33333333); |
| val = val + (val >>> 4) & 0x0f0f0f0f; |
| val += val >>> 8; |
| val += val >>> 16; |
| return val & 0xff; |
| } |
| |
| /** |
| * Creates and returns a copy of this StateInfo. |
| * |
| * @return Copy of this StateInfo. |
| */ |
| public Object clone() { |
| return new StateInfo(this); |
| } |
| |
| public String toString() { |
| StringBuffer buf = new StringBuffer(); |
| |
| buf.append(super.toString()).append(','); |
| |
| buf.append("state=").append(Integer.toString(state)).append(','); |
| |
| buf.append("font=").append(font).append(','); |
| |
| if (colors != null) { |
| buf.append("colors=").append(Arrays.asList(colors)). |
| append(','); |
| } |
| return buf.toString(); |
| } |
| } |
| } |