1621 lines · 53.8 KB · Java
RawDownload
/* * Copyright (c) 1997, 2008, 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 javax.swing.text; import java.awt.*;import java.util.*;import java.io.*; import javax.swing.SwingUtilities;import javax.swing.event.ChangeListener;import javax.swing.event.EventListenerList;import javax.swing.event.ChangeEvent;import java.lang.ref.WeakReference;import java.util.WeakHashMap; import sun.font.FontUtilities; /** * A pool of styles and their associated resources.  This class determines * the lifetime of a group of resources by being a container that holds * caches for various resources such as font and color that get reused * by the various style definitions.  This can be shared by multiple * documents if desired to maximize the sharing of related resources. * <p> * This class also provides efficient support for small sets of attributes * and compresses them by sharing across uses and taking advantage of * their immutable nature.  Since many styles are replicated, the potential * for sharing is significant, and copies can be extremely cheap. * Larger sets reduce the possibility of sharing, and therefore revert * automatically to a less space-efficient implementation. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing.  As of 1.4, support for long term storage * of all JavaBeans<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @author  Timothy Prinzing */public class StyleContext implements Serializable, AbstractDocument.AttributeContext {     /**     * Returns default AttributeContext shared by all documents that     * don't bother to define/supply their own context.     *     * @return the context     */    public static final StyleContext getDefaultStyleContext() {        if (defaultContext == null) {            defaultContext = new StyleContext();        }        return defaultContext;    }     private static StyleContext defaultContext;     /**     * Creates a new StyleContext object.     */    public StyleContext() {        styles = new NamedStyle(null);        addStyle(DEFAULT_STYLE, null);    }     /**     * Adds a new style into the style hierarchy.  Style attributes     * resolve from bottom up so an attribute specified in a child     * will override an attribute specified in the parent.     *     * @param nm   the name of the style (must be unique within the     *   collection of named styles in the document).  The name may     *   be null if the style is unnamed, but the caller is responsible     *   for managing the reference returned as an unnamed style can't     *   be fetched by name.  An unnamed style may be useful for things     *   like character attribute overrides such as found in a style     *   run.     * @param parent the parent style.  This may be null if unspecified     *   attributes need not be resolved in some other style.     * @return the created style     */    public Style addStyle(String nm, Style parent) {        Style style = new NamedStyle(nm, parent);        if (nm != null) {            // add a named style, a class of attributes            styles.addAttribute(nm, style);        }        return style;    }     /**     * Removes a named style previously added to the document.     *     * @param nm  the name of the style to remove     */    public void removeStyle(String nm) {        styles.removeAttribute(nm);    }     /**     * Fetches a named style previously added to the document     *     * @param nm  the name of the style     * @return the style     */    public Style getStyle(String nm) {        return (Style) styles.getAttribute(nm);    }     /**     * Fetches the names of the styles defined.     *     * @return the list of names as an enumeration     */    public Enumeration<?> getStyleNames() {        return styles.getAttributeNames();    }     /**     * Adds a listener to track when styles are added     * or removed.     *     * @param l the change listener     */    public void addChangeListener(ChangeListener l) {        styles.addChangeListener(l);    }     /**     * Removes a listener that was tracking styles being     * added or removed.     *     * @param l the change listener     */    public void removeChangeListener(ChangeListener l) {        styles.removeChangeListener(l);    }     /**     * Returns an array of all the <code>ChangeListener</code>s added     * to this StyleContext with addChangeListener().     *     * @return all of the <code>ChangeListener</code>s added or an empty     *         array if no listeners have been added     * @since 1.4     */    public ChangeListener[] getChangeListeners() {        return ((NamedStyle)styles).getChangeListeners();    }     /**     * Gets the font from an attribute set.  This is     * implemented to try and fetch a cached font     * for the given AttributeSet, and if that fails     * the font features are resolved and the     * font is fetched from the low-level font cache.     *     * @param attr the attribute set     * @return the font     */    public Font getFont(AttributeSet attr) {        // PENDING(prinz) add cache behavior        int style = Font.PLAIN;        if (StyleConstants.isBold(attr)) {            style |= Font.BOLD;        }        if (StyleConstants.isItalic(attr)) {            style |= Font.ITALIC;        }        String family = StyleConstants.getFontFamily(attr);        int size = StyleConstants.getFontSize(attr);         /**         * if either superscript or subscript is         * is set, we need to reduce the font size         * by 2.         */        if (StyleConstants.isSuperscript(attr) ||            StyleConstants.isSubscript(attr)) {            size -= 2;        }         return getFont(family, style, size);    }     /**     * Takes a set of attributes and turn it into a foreground color     * specification.  This might be used to specify things     * like brighter, more hue, etc.  By default it simply returns     * the value specified by the StyleConstants.Foreground attribute.     *     * @param attr the set of attributes     * @return the color     */    public Color getForeground(AttributeSet attr) {        return StyleConstants.getForeground(attr);    }     /**     * Takes a set of attributes and turn it into a background color     * specification.  This might be used to specify things     * like brighter, more hue, etc.  By default it simply returns     * the value specified by the StyleConstants.Background attribute.     *     * @param attr the set of attributes     * @return the color     */    public Color getBackground(AttributeSet attr) {        return StyleConstants.getBackground(attr);    }     /**     * Gets a new font.  This returns a Font from a cache     * if a cached font exists.  If not, a Font is added to     * the cache.  This is basically a low-level cache for     * 1.1 font features.     *     * @param family the font family (such as "Monospaced")     * @param style the style of the font (such as Font.PLAIN)     * @param size the point size >= 1     * @return the new font     */    public Font getFont(String family, int style, int size) {        fontSearch.setValue(family, style, size);        Font f = fontTable.get(fontSearch);        if (f == null) {            // haven't seen this one yet.            Style defaultStyle =                getStyle(StyleContext.DEFAULT_STYLE);            if (defaultStyle != null) {                final String FONT_ATTRIBUTE_KEY = "FONT_ATTRIBUTE_KEY";                Font defaultFont =                    (Font) defaultStyle.getAttribute(FONT_ATTRIBUTE_KEY);                if (defaultFont != null                      && defaultFont.getFamily().equalsIgnoreCase(family)) {                    f = defaultFont.deriveFont(style, size);                }            }            if (f == null) {                f = new Font(family, style, size);            }            if (! FontUtilities.fontSupportsDefaultEncoding(f)) {                f = FontUtilities.getCompositeFontUIResource(f);            }            FontKey key = new FontKey(family, style, size);            fontTable.put(key, f);        }        return f;    }     /**     * Returns font metrics for a font.     *     * @param f the font     * @return the metrics     */    public FontMetrics getFontMetrics(Font f) {        // The Toolkit implementations cache, so we just forward        // to the default toolkit.        return Toolkit.getDefaultToolkit().getFontMetrics(f);    }     // --- AttributeContext methods --------------------     /**     * Adds an attribute to the given set, and returns     * the new representative set.     * <p>     * This method is thread safe, although most Swing methods     * are not. Please see     * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How     * to Use Threads</A> for more information.     *     * @param old the old attribute set     * @param name the non-null attribute name     * @param value the attribute value     * @return the updated attribute set     * @see MutableAttributeSet#addAttribute     */    public synchronized AttributeSet addAttribute(AttributeSet old, Object name, Object value) {        if ((old.getAttributeCount() + 1) <= getCompressionThreshold()) {            // build a search key and find/create an immutable and unique            // set.            search.removeAttributes(search);            search.addAttributes(old);            search.addAttribute(name, value);            reclaim(old);            return getImmutableUniqueSet();        }        MutableAttributeSet ma = getMutableAttributeSet(old);        ma.addAttribute(name, value);        return ma;    }     /**     * Adds a set of attributes to the element.     * <p>     * This method is thread safe, although most Swing methods     * are not. Please see     * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How     * to Use Threads</A> for more information.     *     * @param old the old attribute set     * @param attr the attributes to add     * @return the updated attribute set     * @see MutableAttributeSet#addAttribute     */    public synchronized AttributeSet addAttributes(AttributeSet old, AttributeSet attr) {        if ((old.getAttributeCount() + attr.getAttributeCount()) <= getCompressionThreshold()) {            // build a search key and find/create an immutable and unique            // set.            search.removeAttributes(search);            search.addAttributes(old);            search.addAttributes(attr);            reclaim(old);            return getImmutableUniqueSet();        }        MutableAttributeSet ma = getMutableAttributeSet(old);        ma.addAttributes(attr);        return ma;    }     /**     * Removes an attribute from the set.     * <p>     * This method is thread safe, although most Swing methods     * are not. Please see     * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How     * to Use Threads</A> for more information.     *     * @param old the old set of attributes     * @param name the non-null attribute name     * @return the updated attribute set     * @see MutableAttributeSet#removeAttribute     */    public synchronized AttributeSet removeAttribute(AttributeSet old, Object name) {        if ((old.getAttributeCount() - 1) <= getCompressionThreshold()) {            // build a search key and find/create an immutable and unique            // set.            search.removeAttributes(search);            search.addAttributes(old);            search.removeAttribute(name);            reclaim(old);            return getImmutableUniqueSet();        }        MutableAttributeSet ma = getMutableAttributeSet(old);        ma.removeAttribute(name);        return ma;    }     /**     * Removes a set of attributes for the element.     * <p>     * This method is thread safe, although most Swing methods     * are not. Please see     * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How     * to Use Threads</A> for more information.     *     * @param old the old attribute set     * @param names the attribute names     * @return the updated attribute set     * @see MutableAttributeSet#removeAttributes     */    public synchronized AttributeSet removeAttributes(AttributeSet old, Enumeration<?> names) {        if (old.getAttributeCount() <= getCompressionThreshold()) {            // build a search key and find/create an immutable and unique            // set.            search.removeAttributes(search);            search.addAttributes(old);            search.removeAttributes(names);            reclaim(old);            return getImmutableUniqueSet();        }        MutableAttributeSet ma = getMutableAttributeSet(old);        ma.removeAttributes(names);        return ma;    }     /**     * Removes a set of attributes for the element.     * <p>     * This method is thread safe, although most Swing methods     * are not. Please see     * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How     * to Use Threads</A> for more information.     *     * @param old the old attribute set     * @param attrs the attributes     * @return the updated attribute set     * @see MutableAttributeSet#removeAttributes     */    public synchronized AttributeSet removeAttributes(AttributeSet old, AttributeSet attrs) {        if (old.getAttributeCount() <= getCompressionThreshold()) {            // build a search key and find/create an immutable and unique            // set.            search.removeAttributes(search);            search.addAttributes(old);            search.removeAttributes(attrs);            reclaim(old);            return getImmutableUniqueSet();        }        MutableAttributeSet ma = getMutableAttributeSet(old);        ma.removeAttributes(attrs);        return ma;    }     /**     * Fetches an empty AttributeSet.     *     * @return the set     */    public AttributeSet getEmptySet() {        return SimpleAttributeSet.EMPTY;    }     /**     * Returns a set no longer needed by the MutableAttributeSet implmentation.     * This is useful for operation under 1.1 where there are no weak     * references.  This would typically be called by the finalize method     * of the MutableAttributeSet implementation.     * <p>     * This method is thread safe, although most Swing methods     * are not. Please see     * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How     * to Use Threads</A> for more information.     *     * @param a the set to reclaim     */    public void reclaim(AttributeSet a) {        if (SwingUtilities.isEventDispatchThread()) {            attributesPool.size(); // force WeakHashMap to expunge stale entries        }        // if current thread is not event dispatching thread        // do not bother with expunging stale entries.    }     // --- local methods -----------------------------------------------     /**     * Returns the maximum number of key/value pairs to try and     * compress into unique/immutable sets.  Any sets above this     * limit will use hashtables and be a MutableAttributeSet.     *     * @return the threshold     */    protected int getCompressionThreshold() {        return THRESHOLD;    }     /**     * Create a compact set of attributes that might be shared.     * This is a hook for subclasses that want to alter the     * behavior of SmallAttributeSet.  This can be reimplemented     * to return an AttributeSet that provides some sort of     * attribute conversion.     *     * @param a The set of attributes to be represented in the     *  the compact form.     */    protected SmallAttributeSet createSmallAttributeSet(AttributeSet a) {        return new SmallAttributeSet(a);    }     /**     * Create a large set of attributes that should trade off     * space for time.  This set will not be shared.  This is     * a hook for subclasses that want to alter the behavior     * of the larger attribute storage format (which is     * SimpleAttributeSet by default).   This can be reimplemented     * to return a MutableAttributeSet that provides some sort of     * attribute conversion.     *     * @param a The set of attributes to be represented in the     *  the larger form.     */    protected MutableAttributeSet createLargeAttributeSet(AttributeSet a) {

Lines 1–500 of 1621.