alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (DefaultSynthStyle.java)

This example Java source code file (DefaultSynthStyle.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

awt, border, color, colortype, defaultsynthstyle, font, gui, hashmap, insets, map, object, pending, plaf, region, stateinfo, stringbuffer, swing, synthpainter, uiresource, util

The DefaultSynthStyle.java Java example source code

/*
 * Copyright (c) 2002, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.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
 * and <code>clone 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 identifying 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 is non-null the resulting
     * insets will be placed in it, otherwise a new Insets object will be
     * created and returned.
     *
     * @param context SynthContext identifying 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 identifying 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 identifying 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 identifying 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.
     *
     * @param state SynthContext identifying 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 will take precedence over those of the
     * passed in <code>DefaultSynthStyle. 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'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().
         *
         * @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().
         *
         * @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 will take precedence over those of the
         * passed in <code>StateInfo. 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'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();
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java DefaultSynthStyle.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.