0N/A/*
2362N/A * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/Apackage javax.swing.text;
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.util.*;
0N/Aimport java.io.*;
0N/A
0N/Aimport javax.swing.SwingUtilities;
0N/Aimport javax.swing.event.ChangeListener;
0N/Aimport javax.swing.event.EventListenerList;
0N/Aimport javax.swing.event.ChangeEvent;
0N/Aimport java.lang.ref.WeakReference;
0N/Aimport java.util.WeakHashMap;
0N/A
1686N/Aimport sun.font.FontUtilities;
0N/A
0N/A/**
0N/A * A pool of styles and their associated resources. This class determines
0N/A * the lifetime of a group of resources by being a container that holds
0N/A * caches for various resources such as font and color that get reused
0N/A * by the various style definitions. This can be shared by multiple
0N/A * documents if desired to maximize the sharing of related resources.
0N/A * <p>
0N/A * This class also provides efficient support for small sets of attributes
0N/A * and compresses them by sharing across uses and taking advantage of
0N/A * their immutable nature. Since many styles are replicated, the potential
0N/A * for sharing is significant, and copies can be extremely cheap.
0N/A * Larger sets reduce the possibility of sharing, and therefore revert
0N/A * automatically to a less space-efficient implementation.
0N/A * <p>
0N/A * <strong>Warning:</strong>
0N/A * Serialized objects of this class will not be compatible with
0N/A * future Swing releases. The current serialization support is
0N/A * appropriate for short term storage or RMI between applications running
0N/A * the same version of Swing. As of 1.4, support for long term storage
0N/A * of all JavaBeans<sup><font size="-2">TM</font></sup>
0N/A * has been added to the <code>java.beans</code> package.
0N/A * Please see {@link java.beans.XMLEncoder}.
0N/A *
0N/A * @author Timothy Prinzing
0N/A */
0N/Apublic class StyleContext implements Serializable, AbstractDocument.AttributeContext {
0N/A
0N/A /**
0N/A * Returns default AttributeContext shared by all documents that
0N/A * don't bother to define/supply their own context.
0N/A *
0N/A * @return the context
0N/A */
0N/A public static final StyleContext getDefaultStyleContext() {
0N/A if (defaultContext == null) {
0N/A defaultContext = new StyleContext();
0N/A }
0N/A return defaultContext;
0N/A }
0N/A
0N/A private static StyleContext defaultContext;
0N/A
0N/A /**
0N/A * Creates a new StyleContext object.
0N/A */
0N/A public StyleContext() {
0N/A styles = new NamedStyle(null);
0N/A addStyle(DEFAULT_STYLE, null);
0N/A }
0N/A
0N/A /**
0N/A * Adds a new style into the style hierarchy. Style attributes
0N/A * resolve from bottom up so an attribute specified in a child
0N/A * will override an attribute specified in the parent.
0N/A *
0N/A * @param nm the name of the style (must be unique within the
0N/A * collection of named styles in the document). The name may
0N/A * be null if the style is unnamed, but the caller is responsible
0N/A * for managing the reference returned as an unnamed style can't
0N/A * be fetched by name. An unnamed style may be useful for things
0N/A * like character attribute overrides such as found in a style
0N/A * run.
0N/A * @param parent the parent style. This may be null if unspecified
0N/A * attributes need not be resolved in some other style.
0N/A * @return the created style
0N/A */
0N/A public Style addStyle(String nm, Style parent) {
0N/A Style style = new NamedStyle(nm, parent);
0N/A if (nm != null) {
0N/A // add a named style, a class of attributes
0N/A styles.addAttribute(nm, style);
0N/A }
0N/A return style;
0N/A }
0N/A
0N/A /**
0N/A * Removes a named style previously added to the document.
0N/A *
0N/A * @param nm the name of the style to remove
0N/A */
0N/A public void removeStyle(String nm) {
0N/A styles.removeAttribute(nm);
0N/A }
0N/A
0N/A /**
0N/A * Fetches a named style previously added to the document
0N/A *
0N/A * @param nm the name of the style
0N/A * @return the style
0N/A */
0N/A public Style getStyle(String nm) {
0N/A return (Style) styles.getAttribute(nm);
0N/A }
0N/A
0N/A /**
0N/A * Fetches the names of the styles defined.
0N/A *
0N/A * @return the list of names as an enumeration
0N/A */
0N/A public Enumeration<?> getStyleNames() {
0N/A return styles.getAttributeNames();
0N/A }
0N/A
0N/A /**
0N/A * Adds a listener to track when styles are added
0N/A * or removed.
0N/A *
0N/A * @param l the change listener
0N/A */
0N/A public void addChangeListener(ChangeListener l) {
0N/A styles.addChangeListener(l);
0N/A }
0N/A
0N/A /**
0N/A * Removes a listener that was tracking styles being
0N/A * added or removed.
0N/A *
0N/A * @param l the change listener
0N/A */
0N/A public void removeChangeListener(ChangeListener l) {
0N/A styles.removeChangeListener(l);
0N/A }
0N/A
0N/A /**
0N/A * Returns an array of all the <code>ChangeListener</code>s added
0N/A * to this StyleContext with addChangeListener().
0N/A *
0N/A * @return all of the <code>ChangeListener</code>s added or an empty
0N/A * array if no listeners have been added
0N/A * @since 1.4
0N/A */
0N/A public ChangeListener[] getChangeListeners() {
0N/A return ((NamedStyle)styles).getChangeListeners();
0N/A }
0N/A
0N/A /**
0N/A * Gets the font from an attribute set. This is
0N/A * implemented to try and fetch a cached font
0N/A * for the given AttributeSet, and if that fails
0N/A * the font features are resolved and the
0N/A * font is fetched from the low-level font cache.
0N/A *
0N/A * @param attr the attribute set
0N/A * @return the font
0N/A */
0N/A public Font getFont(AttributeSet attr) {
0N/A // PENDING(prinz) add cache behavior
0N/A int style = Font.PLAIN;
0N/A if (StyleConstants.isBold(attr)) {
0N/A style |= Font.BOLD;
0N/A }
0N/A if (StyleConstants.isItalic(attr)) {
0N/A style |= Font.ITALIC;
0N/A }
0N/A String family = StyleConstants.getFontFamily(attr);
0N/A int size = StyleConstants.getFontSize(attr);
0N/A
0N/A /**
0N/A * if either superscript or subscript is
0N/A * is set, we need to reduce the font size
0N/A * by 2.
0N/A */
0N/A if (StyleConstants.isSuperscript(attr) ||
0N/A StyleConstants.isSubscript(attr)) {
0N/A size -= 2;
0N/A }
0N/A
0N/A return getFont(family, style, size);
0N/A }
0N/A
0N/A /**
0N/A * Takes a set of attributes and turn it into a foreground color
0N/A * specification. This might be used to specify things
0N/A * like brighter, more hue, etc. By default it simply returns
0N/A * the value specified by the StyleConstants.Foreground attribute.
0N/A *
0N/A * @param attr the set of attributes
0N/A * @return the color
0N/A */
0N/A public Color getForeground(AttributeSet attr) {
0N/A return StyleConstants.getForeground(attr);
0N/A }
0N/A
0N/A /**
0N/A * Takes a set of attributes and turn it into a background color
0N/A * specification. This might be used to specify things
0N/A * like brighter, more hue, etc. By default it simply returns
0N/A * the value specified by the StyleConstants.Background attribute.
0N/A *
0N/A * @param attr the set of attributes
0N/A * @return the color
0N/A */
0N/A public Color getBackground(AttributeSet attr) {
0N/A return StyleConstants.getBackground(attr);
0N/A }
0N/A
0N/A /**
0N/A * Gets a new font. This returns a Font from a cache
0N/A * if a cached font exists. If not, a Font is added to
0N/A * the cache. This is basically a low-level cache for
0N/A * 1.1 font features.
0N/A *
0N/A * @param family the font family (such as "Monospaced")
0N/A * @param style the style of the font (such as Font.PLAIN)
0N/A * @param size the point size >= 1
0N/A * @return the new font
0N/A */
0N/A public Font getFont(String family, int style, int size) {
0N/A fontSearch.setValue(family, style, size);
611N/A Font f = fontTable.get(fontSearch);
0N/A if (f == null) {
0N/A // haven't seen this one yet.
0N/A Style defaultStyle =
0N/A getStyle(StyleContext.DEFAULT_STYLE);
0N/A if (defaultStyle != null) {
0N/A final String FONT_ATTRIBUTE_KEY = "FONT_ATTRIBUTE_KEY";
0N/A Font defaultFont =
0N/A (Font) defaultStyle.getAttribute(FONT_ATTRIBUTE_KEY);
0N/A if (defaultFont != null
0N/A && defaultFont.getFamily().equalsIgnoreCase(family)) {
0N/A f = defaultFont.deriveFont(style, size);
0N/A }
0N/A }
0N/A if (f == null) {
0N/A f = new Font(family, style, size);
0N/A }
1686N/A if (! FontUtilities.fontSupportsDefaultEncoding(f)) {
1686N/A f = FontUtilities.getCompositeFontUIResource(f);
0N/A }
0N/A FontKey key = new FontKey(family, style, size);
0N/A fontTable.put(key, f);
0N/A }
0N/A return f;
0N/A }
0N/A
0N/A /**
0N/A * Returns font metrics for a font.
0N/A *
0N/A * @param f the font
0N/A * @return the metrics
0N/A */
0N/A public FontMetrics getFontMetrics(Font f) {
0N/A // The Toolkit implementations cache, so we just forward
0N/A // to the default toolkit.
0N/A return Toolkit.getDefaultToolkit().getFontMetrics(f);
0N/A }
0N/A
0N/A // --- AttributeContext methods --------------------
0N/A
0N/A /**
0N/A * Adds an attribute to the given set, and returns
0N/A * the new representative set.
0N/A * <p>
0N/A * This method is thread safe, although most Swing methods
0N/A * are not. Please see
0N/A * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
0N/A * to Use Threads</A> for more information.
0N/A *
0N/A * @param old the old attribute set
0N/A * @param name the non-null attribute name
0N/A * @param value the attribute value
0N/A * @return the updated attribute set
0N/A * @see MutableAttributeSet#addAttribute
0N/A */
0N/A public synchronized AttributeSet addAttribute(AttributeSet old, Object name, Object value) {
0N/A if ((old.getAttributeCount() + 1) <= getCompressionThreshold()) {
0N/A // build a search key and find/create an immutable and unique
0N/A // set.
0N/A search.removeAttributes(search);
0N/A search.addAttributes(old);
0N/A search.addAttribute(name, value);
0N/A reclaim(old);
0N/A return getImmutableUniqueSet();
0N/A }
0N/A MutableAttributeSet ma = getMutableAttributeSet(old);
0N/A ma.addAttribute(name, value);
0N/A return ma;
0N/A }
0N/A
0N/A /**
0N/A * Adds a set of attributes to the element.
0N/A * <p>
0N/A * This method is thread safe, although most Swing methods
0N/A * are not. Please see
0N/A * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
0N/A * to Use Threads</A> for more information.
0N/A *
0N/A * @param old the old attribute set
0N/A * @param attr the attributes to add
0N/A * @return the updated attribute set
0N/A * @see MutableAttributeSet#addAttribute
0N/A */
0N/A public synchronized AttributeSet addAttributes(AttributeSet old, AttributeSet attr) {
0N/A if ((old.getAttributeCount() + attr.getAttributeCount()) <= getCompressionThreshold()) {
0N/A // build a search key and find/create an immutable and unique
0N/A // set.
0N/A search.removeAttributes(search);
0N/A search.addAttributes(old);
0N/A search.addAttributes(attr);
0N/A reclaim(old);
0N/A return getImmutableUniqueSet();
0N/A }
0N/A MutableAttributeSet ma = getMutableAttributeSet(old);
0N/A ma.addAttributes(attr);
0N/A return ma;
0N/A }
0N/A
0N/A /**
0N/A * Removes an attribute from the set.
0N/A * <p>
0N/A * This method is thread safe, although most Swing methods
0N/A * are not. Please see
0N/A * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
0N/A * to Use Threads</A> for more information.
0N/A *
0N/A * @param old the old set of attributes
0N/A * @param name the non-null attribute name
0N/A * @return the updated attribute set
0N/A * @see MutableAttributeSet#removeAttribute
0N/A */
0N/A public synchronized AttributeSet removeAttribute(AttributeSet old, Object name) {
0N/A if ((old.getAttributeCount() - 1) <= getCompressionThreshold()) {
0N/A // build a search key and find/create an immutable and unique
0N/A // set.
0N/A search.removeAttributes(search);
0N/A search.addAttributes(old);
0N/A search.removeAttribute(name);
0N/A reclaim(old);
0N/A return getImmutableUniqueSet();
0N/A }
0N/A MutableAttributeSet ma = getMutableAttributeSet(old);
0N/A ma.removeAttribute(name);
0N/A return ma;
0N/A }
0N/A
0N/A /**
0N/A * Removes a set of attributes for the element.
0N/A * <p>
0N/A * This method is thread safe, although most Swing methods
0N/A * are not. Please see
0N/A * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
0N/A * to Use Threads</A> for more information.
0N/A *
0N/A * @param old the old attribute set
0N/A * @param names the attribute names
0N/A * @return the updated attribute set
0N/A * @see MutableAttributeSet#removeAttributes
0N/A */
0N/A public synchronized AttributeSet removeAttributes(AttributeSet old, Enumeration<?> names) {
0N/A if (old.getAttributeCount() <= getCompressionThreshold()) {
0N/A // build a search key and find/create an immutable and unique
0N/A // set.
0N/A search.removeAttributes(search);
0N/A search.addAttributes(old);
0N/A search.removeAttributes(names);
0N/A reclaim(old);
0N/A return getImmutableUniqueSet();
0N/A }
0N/A MutableAttributeSet ma = getMutableAttributeSet(old);
0N/A ma.removeAttributes(names);
0N/A return ma;
0N/A }
0N/A
0N/A /**
0N/A * Removes a set of attributes for the element.
0N/A * <p>
0N/A * This method is thread safe, although most Swing methods
0N/A * are not. Please see
0N/A * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
0N/A * to Use Threads</A> for more information.
0N/A *
0N/A * @param old the old attribute set
0N/A * @param attrs the attributes
0N/A * @return the updated attribute set
0N/A * @see MutableAttributeSet#removeAttributes
0N/A */
0N/A public synchronized AttributeSet removeAttributes(AttributeSet old, AttributeSet attrs) {
0N/A if (old.getAttributeCount() <= getCompressionThreshold()) {
0N/A // build a search key and find/create an immutable and unique
0N/A // set.
0N/A search.removeAttributes(search);
0N/A search.addAttributes(old);
0N/A search.removeAttributes(attrs);
0N/A reclaim(old);
0N/A return getImmutableUniqueSet();
0N/A }
0N/A MutableAttributeSet ma = getMutableAttributeSet(old);
0N/A ma.removeAttributes(attrs);
0N/A return ma;
0N/A }
0N/A
0N/A /**
0N/A * Fetches an empty AttributeSet.
0N/A *
0N/A * @return the set
0N/A */
0N/A public AttributeSet getEmptySet() {
0N/A return SimpleAttributeSet.EMPTY;
0N/A }
0N/A
0N/A /**
0N/A * Returns a set no longer needed by the MutableAttributeSet implmentation.
0N/A * This is useful for operation under 1.1 where there are no weak
0N/A * references. This would typically be called by the finalize method
0N/A * of the MutableAttributeSet implementation.
0N/A * <p>
0N/A * This method is thread safe, although most Swing methods
0N/A * are not. Please see
0N/A * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How
0N/A * to Use Threads</A> for more information.
0N/A *
0N/A * @param a the set to reclaim
0N/A */
0N/A public void reclaim(AttributeSet a) {
0N/A if (SwingUtilities.isEventDispatchThread()) {
0N/A attributesPool.size(); // force WeakHashMap to expunge stale entries
0N/A }
0N/A // if current thread is not event dispatching thread
0N/A // do not bother with expunging stale entries.
0N/A }
0N/A
0N/A // --- local methods -----------------------------------------------
0N/A
0N/A /**
0N/A * Returns the maximum number of key/value pairs to try and
0N/A * compress into unique/immutable sets. Any sets above this
0N/A * limit will use hashtables and be a MutableAttributeSet.
0N/A *
0N/A * @return the threshold
0N/A */
0N/A protected int getCompressionThreshold() {
0N/A return THRESHOLD;
0N/A }
0N/A
0N/A /**
0N/A * Create a compact set of attributes that might be shared.
0N/A * This is a hook for subclasses that want to alter the
0N/A * behavior of SmallAttributeSet. This can be reimplemented
0N/A * to return an AttributeSet that provides some sort of
0N/A * attribute conversion.
0N/A *
0N/A * @param a The set of attributes to be represented in the
0N/A * the compact form.
0N/A */
0N/A protected SmallAttributeSet createSmallAttributeSet(AttributeSet a) {
0N/A return new SmallAttributeSet(a);
0N/A }
0N/A
0N/A /**
0N/A * Create a large set of attributes that should trade off
0N/A * space for time. This set will not be shared. This is
0N/A * a hook for subclasses that want to alter the behavior
0N/A * of the larger attribute storage format (which is
0N/A * SimpleAttributeSet by default). This can be reimplemented
0N/A * to return a MutableAttributeSet that provides some sort of
0N/A * attribute conversion.
0N/A *
0N/A * @param a The set of attributes to be represented in the
0N/A * the larger form.
0N/A */
0N/A protected MutableAttributeSet createLargeAttributeSet(AttributeSet a) {
0N/A return new SimpleAttributeSet(a);
0N/A }
0N/A
0N/A /**
0N/A * Clean the unused immutable sets out of the hashtable.
0N/A */
0N/A synchronized void removeUnusedSets() {
0N/A attributesPool.size(); // force WeakHashMap to expunge stale entries
0N/A }
0N/A
0N/A /**
0N/A * Search for an existing attribute set using the current search
0N/A * parameters. If a matching set is found, return it. If a match
0N/A * is not found, we create a new set and add it to the pool.
0N/A */
0N/A AttributeSet getImmutableUniqueSet() {
0N/A // PENDING(prinz) should consider finding a alternative to
0N/A // generating extra garbage on search key.
0N/A SmallAttributeSet key = createSmallAttributeSet(search);
611N/A WeakReference<SmallAttributeSet> reference = attributesPool.get(key);
0N/A SmallAttributeSet a;
611N/A if (reference == null || (a = reference.get()) == null) {
0N/A a = key;
611N/A attributesPool.put(a, new WeakReference<SmallAttributeSet>(a));
0N/A }
0N/A return a;
0N/A }
0N/A
0N/A /**
0N/A * Creates a mutable attribute set to hand out because the current
0N/A * needs are too big to try and use a shared version.
0N/A */
0N/A MutableAttributeSet getMutableAttributeSet(AttributeSet a) {
0N/A if (a instanceof MutableAttributeSet &&
0N/A a != SimpleAttributeSet.EMPTY) {
0N/A return (MutableAttributeSet) a;
0N/A }
0N/A return createLargeAttributeSet(a);
0N/A }
0N/A
0N/A /**
0N/A * Converts a StyleContext to a String.
0N/A *
0N/A * @return the string
0N/A */
0N/A public String toString() {
0N/A removeUnusedSets();
0N/A String s = "";
611N/A for (SmallAttributeSet set : attributesPool.keySet()) {
0N/A s = s + set + "\n";
0N/A }
0N/A return s;
0N/A }
0N/A
0N/A // --- serialization ---------------------------------------------
0N/A
0N/A /**
0N/A * Context-specific handling of writing out attributes
0N/A */
0N/A public void writeAttributes(ObjectOutputStream out,
0N/A AttributeSet a) throws IOException {
0N/A writeAttributeSet(out, a);
0N/A }
0N/A
0N/A /**
0N/A * Context-specific handling of reading in attributes
0N/A */
0N/A public void readAttributes(ObjectInputStream in,
0N/A MutableAttributeSet a) throws ClassNotFoundException, IOException {
0N/A readAttributeSet(in, a);
0N/A }
0N/A
0N/A /**
0N/A * Writes a set of attributes to the given object stream
0N/A * for the purpose of serialization. This will take
0N/A * special care to deal with static attribute keys that
0N/A * have been registered wit the
0N/A * <code>registerStaticAttributeKey</code> method.
0N/A * Any attribute key not regsitered as a static key
0N/A * will be serialized directly. All values are expected
0N/A * to be serializable.
0N/A *
0N/A * @param out the output stream
0N/A * @param a the attribute set
0N/A * @exception IOException on any I/O error
0N/A */
0N/A public static void writeAttributeSet(ObjectOutputStream out,
0N/A AttributeSet a) throws IOException {
0N/A int n = a.getAttributeCount();
0N/A out.writeInt(n);
0N/A Enumeration keys = a.getAttributeNames();
0N/A while (keys.hasMoreElements()) {
0N/A Object key = keys.nextElement();
0N/A if (key instanceof Serializable) {
0N/A out.writeObject(key);
0N/A } else {
0N/A Object ioFmt = freezeKeyMap.get(key);
0N/A if (ioFmt == null) {
0N/A throw new NotSerializableException(key.getClass().
0N/A getName() + " is not serializable as a key in an AttributeSet");
0N/A }
0N/A out.writeObject(ioFmt);
0N/A }
0N/A Object value = a.getAttribute(key);
0N/A Object ioFmt = freezeKeyMap.get(value);
0N/A if (value instanceof Serializable) {
0N/A out.writeObject((ioFmt != null) ? ioFmt : value);
0N/A } else {
0N/A if (ioFmt == null) {
0N/A throw new NotSerializableException(value.getClass().
0N/A getName() + " is not serializable as a value in an AttributeSet");
0N/A }
0N/A out.writeObject(ioFmt);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Reads a set of attributes from the given object input
0N/A * stream that have been previously written out with
0N/A * <code>writeAttributeSet</code>. This will try to restore
0N/A * keys that were static objects to the static objects in
0N/A * the current virtual machine considering only those keys
0N/A * that have been registered with the
0N/A * <code>registerStaticAttributeKey</code> method.
0N/A * The attributes retrieved from the stream will be placed
0N/A * into the given mutable set.
0N/A *
0N/A * @param in the object stream to read the attribute data from.
0N/A * @param a the attribute set to place the attribute
0N/A * definitions in.
0N/A * @exception ClassNotFoundException passed upward if encountered
0N/A * when reading the object stream.
0N/A * @exception IOException passed upward if encountered when
0N/A * reading the object stream.
0N/A */
0N/A public static void readAttributeSet(ObjectInputStream in,
0N/A MutableAttributeSet a) throws ClassNotFoundException, IOException {
0N/A
0N/A int n = in.readInt();
0N/A for (int i = 0; i < n; i++) {
0N/A Object key = in.readObject();
0N/A Object value = in.readObject();
0N/A if (thawKeyMap != null) {
0N/A Object staticKey = thawKeyMap.get(key);
0N/A if (staticKey != null) {
0N/A key = staticKey;
0N/A }
0N/A Object staticValue = thawKeyMap.get(value);
0N/A if (staticValue != null) {
0N/A value = staticValue;
0N/A }
0N/A }
0N/A a.addAttribute(key, value);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Registers an object as a static object that is being
0N/A * used as a key in attribute sets. This allows the key
0N/A * to be treated specially for serialization.
0N/A * <p>
0N/A * For operation under a 1.1 virtual machine, this
0N/A * uses the value returned by <code>toString</code>
0N/A * concatenated to the classname. The value returned
0N/A * by toString should not have the class reference
0N/A * in it (ie it should be reimplemented from the
0N/A * definition in Object) in order to be the same when
0N/A * recomputed later.
0N/A *
0N/A * @param key the non-null object key
0N/A */
0N/A public static void registerStaticAttributeKey(Object key) {
0N/A String ioFmt = key.getClass().getName() + "." + key.toString();
0N/A if (freezeKeyMap == null) {
611N/A freezeKeyMap = new Hashtable<Object, String>();
611N/A thawKeyMap = new Hashtable<String, Object>();
0N/A }
0N/A freezeKeyMap.put(key, ioFmt);
0N/A thawKeyMap.put(ioFmt, key);
0N/A }
0N/A
0N/A /**
0N/A * Returns the object previously registered with
0N/A * <code>registerStaticAttributeKey</code>.
0N/A */
0N/A public static Object getStaticAttribute(Object key) {
0N/A if (thawKeyMap == null || key == null) {
0N/A return null;
0N/A }
0N/A return thawKeyMap.get(key);
0N/A }
0N/A
0N/A /**
0N/A * Returns the String that <code>key</code> will be registered with
0N/A * @see #getStaticAttribute
0N/A * @see #registerStaticAttributeKey
0N/A */
0N/A public static Object getStaticAttributeKey(Object key) {
0N/A return key.getClass().getName() + "." + key.toString();
0N/A }
0N/A
0N/A private void writeObject(java.io.ObjectOutputStream s)
0N/A throws IOException
0N/A {
0N/A // clean out unused sets before saving
0N/A removeUnusedSets();
0N/A
0N/A s.defaultWriteObject();
0N/A }
0N/A
0N/A private void readObject(ObjectInputStream s)
0N/A throws ClassNotFoundException, IOException
0N/A {
0N/A fontSearch = new FontKey(null, 0, 0);
611N/A fontTable = new Hashtable<FontKey, Font>();
0N/A search = new SimpleAttributeSet();
0N/A attributesPool = Collections.
611N/A synchronizedMap(new WeakHashMap<SmallAttributeSet, WeakReference<SmallAttributeSet>>());
0N/A s.defaultReadObject();
0N/A }
0N/A
0N/A // --- variables ---------------------------------------------------
0N/A
0N/A /**
0N/A * The name given to the default logical style attached
0N/A * to paragraphs.
0N/A */
0N/A public static final String DEFAULT_STYLE = "default";
0N/A
611N/A private static Hashtable<Object, String> freezeKeyMap;
611N/A private static Hashtable<String, Object> thawKeyMap;
0N/A
0N/A private Style styles;
0N/A private transient FontKey fontSearch = new FontKey(null, 0, 0);
611N/A private transient Hashtable<FontKey, Font> fontTable = new Hashtable<FontKey, Font>();
0N/A
611N/A private transient Map<SmallAttributeSet, WeakReference<SmallAttributeSet>> attributesPool = Collections.
611N/A synchronizedMap(new WeakHashMap<SmallAttributeSet, WeakReference<SmallAttributeSet>>());
0N/A private transient MutableAttributeSet search = new SimpleAttributeSet();
0N/A
0N/A /**
0N/A * Number of immutable sets that are not currently
0N/A * being used. This helps indicate when the sets need
0N/A * to be cleaned out of the hashtable they are stored
0N/A * in.
0N/A */
0N/A private int unusedSets;
0N/A
0N/A /**
0N/A * The threshold for no longer sharing the set of attributes
0N/A * in an immutable table.
0N/A */
0N/A static final int THRESHOLD = 9;
0N/A
0N/A /**
0N/A * This class holds a small number of attributes in an array.
0N/A * The storage format is key, value, key, value, etc. The size
0N/A * of the set is the length of the array divided by two. By
0N/A * default, this is the class that will be used to store attributes
0N/A * when held in the compact sharable form.
0N/A */
0N/A public class SmallAttributeSet implements AttributeSet {
0N/A
0N/A public SmallAttributeSet(Object[] attributes) {
0N/A this.attributes = attributes;
0N/A updateResolveParent();
0N/A }
0N/A
0N/A public SmallAttributeSet(AttributeSet attrs) {
0N/A int n = attrs.getAttributeCount();
0N/A Object[] tbl = new Object[2 * n];
0N/A Enumeration names = attrs.getAttributeNames();
0N/A int i = 0;
0N/A while (names.hasMoreElements()) {
0N/A tbl[i] = names.nextElement();
0N/A tbl[i+1] = attrs.getAttribute(tbl[i]);
0N/A i += 2;
0N/A }
0N/A attributes = tbl;
0N/A updateResolveParent();
0N/A }
0N/A
0N/A private void updateResolveParent() {
0N/A resolveParent = null;
0N/A Object[] tbl = attributes;
0N/A for (int i = 0; i < tbl.length; i += 2) {
0N/A if (tbl[i] == StyleConstants.ResolveAttribute) {
0N/A resolveParent = (AttributeSet)tbl[i + 1];
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A
0N/A Object getLocalAttribute(Object nm) {
0N/A if (nm == StyleConstants.ResolveAttribute) {
0N/A return resolveParent;
0N/A }
0N/A Object[] tbl = attributes;
0N/A for (int i = 0; i < tbl.length; i += 2) {
0N/A if (nm.equals(tbl[i])) {
0N/A return tbl[i+1];
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A // --- Object methods -------------------------
0N/A
0N/A /**
0N/A * Returns a string showing the key/value pairs
0N/A */
0N/A public String toString() {
0N/A String s = "{";
0N/A Object[] tbl = attributes;
0N/A for (int i = 0; i < tbl.length; i += 2) {
0N/A if (tbl[i+1] instanceof AttributeSet) {
0N/A // don't recurse
0N/A s = s + tbl[i] + "=" + "AttributeSet" + ",";
0N/A } else {
0N/A s = s + tbl[i] + "=" + tbl[i+1] + ",";
0N/A }
0N/A }
0N/A s = s + "}";
0N/A return s;
0N/A }
0N/A
0N/A /**
0N/A * Returns a hashcode for this set of attributes.
0N/A * @return a hashcode value for this set of attributes.
0N/A */
0N/A public int hashCode() {
0N/A int code = 0;
0N/A Object[] tbl = attributes;
0N/A for (int i = 1; i < tbl.length; i += 2) {
0N/A code ^= tbl[i].hashCode();
0N/A }
0N/A return code;
0N/A }
0N/A
0N/A /**
0N/A * Compares this object to the specifed object.
0N/A * The result is <code>true</code> if the object is an equivalent
0N/A * set of attributes.
0N/A * @param obj the object to compare with.
0N/A * @return <code>true</code> if the objects are equal;
0N/A * <code>false</code> otherwise.
0N/A */
0N/A public boolean equals(Object obj) {
0N/A if (obj instanceof AttributeSet) {
0N/A AttributeSet attrs = (AttributeSet) obj;
0N/A return ((getAttributeCount() == attrs.getAttributeCount()) &&
0N/A containsAttributes(attrs));
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Clones a set of attributes. Since the set is immutable, a
0N/A * clone is basically the same set.
0N/A *
0N/A * @return the set of attributes
0N/A */
0N/A public Object clone() {
0N/A return this;
0N/A }
0N/A
0N/A // --- AttributeSet methods ----------------------------
0N/A
0N/A /**
0N/A * Gets the number of attributes that are defined.
0N/A *
0N/A * @return the number of attributes
0N/A * @see AttributeSet#getAttributeCount
0N/A */
0N/A public int getAttributeCount() {
0N/A return attributes.length / 2;
0N/A }
0N/A
0N/A /**
0N/A * Checks whether a given attribute is defined.
0N/A *
0N/A * @param key the attribute key
0N/A * @return true if the attribute is defined
0N/A * @see AttributeSet#isDefined
0N/A */
0N/A public boolean isDefined(Object key) {
0N/A Object[] a = attributes;
0N/A int n = a.length;
0N/A for (int i = 0; i < n; i += 2) {
0N/A if (key.equals(a[i])) {
0N/A return true;
0N/A }
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Checks whether two attribute sets are equal.
0N/A *
0N/A * @param attr the attribute set to check against
0N/A * @return true if the same
0N/A * @see AttributeSet#isEqual
0N/A */
0N/A public boolean isEqual(AttributeSet attr) {
0N/A if (attr instanceof SmallAttributeSet) {
0N/A return attr == this;
0N/A }
0N/A return ((getAttributeCount() == attr.getAttributeCount()) &&
0N/A containsAttributes(attr));
0N/A }
0N/A
0N/A /**
0N/A * Copies a set of attributes.
0N/A *
0N/A * @return the copy
0N/A * @see AttributeSet#copyAttributes
0N/A */
0N/A public AttributeSet copyAttributes() {
0N/A return this;
0N/A }
0N/A
0N/A /**
0N/A * Gets the value of an attribute.
0N/A *
0N/A * @param key the attribute name
0N/A * @return the attribute value
0N/A * @see AttributeSet#getAttribute
0N/A */
0N/A public Object getAttribute(Object key) {
0N/A Object value = getLocalAttribute(key);
0N/A if (value == null) {
0N/A AttributeSet parent = getResolveParent();
0N/A if (parent != null)
0N/A value = parent.getAttribute(key);
0N/A }
0N/A return value;
0N/A }
0N/A
0N/A /**
0N/A * Gets the names of all attributes.
0N/A *
0N/A * @return the attribute names
0N/A * @see AttributeSet#getAttributeNames
0N/A */
0N/A public Enumeration<?> getAttributeNames() {
0N/A return new KeyEnumeration(attributes);
0N/A }
0N/A
0N/A /**
0N/A * Checks whether a given attribute name/value is defined.
0N/A *
0N/A * @param name the attribute name
0N/A * @param value the attribute value
0N/A * @return true if the name/value is defined
0N/A * @see AttributeSet#containsAttribute
0N/A */
0N/A public boolean containsAttribute(Object name, Object value) {
0N/A return value.equals(getAttribute(name));
0N/A }
0N/A
0N/A /**
0N/A * Checks whether the attribute set contains all of
0N/A * the given attributes.
0N/A *
0N/A * @param attrs the attributes to check
0N/A * @return true if the element contains all the attributes
0N/A * @see AttributeSet#containsAttributes
0N/A */
0N/A public boolean containsAttributes(AttributeSet attrs) {
0N/A boolean result = true;
0N/A
0N/A Enumeration names = attrs.getAttributeNames();
0N/A while (result && names.hasMoreElements()) {
0N/A Object name = names.nextElement();
0N/A result = attrs.getAttribute(name).equals(getAttribute(name));
0N/A }
0N/A
0N/A return result;
0N/A }
0N/A
0N/A /**
0N/A * If not overriden, the resolving parent defaults to
0N/A * the parent element.
0N/A *
0N/A * @return the attributes from the parent
0N/A * @see AttributeSet#getResolveParent
0N/A */
0N/A public AttributeSet getResolveParent() {
0N/A return resolveParent;
0N/A }
0N/A
0N/A // --- variables -----------------------------------------
0N/A
0N/A Object[] attributes;
0N/A // This is also stored in attributes
0N/A AttributeSet resolveParent;
0N/A }
0N/A
0N/A /**
0N/A * An enumeration of the keys in a SmallAttributeSet.
0N/A */
0N/A class KeyEnumeration implements Enumeration<Object> {
0N/A
0N/A KeyEnumeration(Object[] attr) {
0N/A this.attr = attr;
0N/A i = 0;
0N/A }
0N/A
0N/A /**
0N/A * Tests if this enumeration contains more elements.
0N/A *
0N/A * @return <code>true</code> if this enumeration contains more elements;
0N/A * <code>false</code> otherwise.
0N/A * @since JDK1.0
0N/A */
0N/A public boolean hasMoreElements() {
0N/A return i < attr.length;
0N/A }
0N/A
0N/A /**
0N/A * Returns the next element of this enumeration.
0N/A *
0N/A * @return the next element of this enumeration.
0N/A * @exception NoSuchElementException if no more elements exist.
0N/A * @since JDK1.0
0N/A */
0N/A public Object nextElement() {
0N/A if (i < attr.length) {
0N/A Object o = attr[i];
0N/A i += 2;
0N/A return o;
0N/A }
0N/A throw new NoSuchElementException();
0N/A }
0N/A
0N/A Object[] attr;
0N/A int i;
0N/A }
0N/A
0N/A /**
0N/A * Sorts the key strings so that they can be very quickly compared
0N/A * in the attribute set searchs.
0N/A */
0N/A class KeyBuilder {
0N/A
0N/A public void initialize(AttributeSet a) {
0N/A if (a instanceof SmallAttributeSet) {
0N/A initialize(((SmallAttributeSet)a).attributes);
0N/A } else {
0N/A keys.removeAllElements();
0N/A data.removeAllElements();
0N/A Enumeration names = a.getAttributeNames();
0N/A while (names.hasMoreElements()) {
0N/A Object name = names.nextElement();
0N/A addAttribute(name, a.getAttribute(name));
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Initialize with a set of already sorted
0N/A * keys (data from an existing SmallAttributeSet).
0N/A */
0N/A private void initialize(Object[] sorted) {
0N/A keys.removeAllElements();
0N/A data.removeAllElements();
0N/A int n = sorted.length;
0N/A for (int i = 0; i < n; i += 2) {
0N/A keys.addElement(sorted[i]);
0N/A data.addElement(sorted[i+1]);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Creates a table of sorted key/value entries
0N/A * suitable for creation of an instance of
0N/A * SmallAttributeSet.
0N/A */
0N/A public Object[] createTable() {
0N/A int n = keys.size();
0N/A Object[] tbl = new Object[2 * n];
0N/A for (int i = 0; i < n; i ++) {
0N/A int offs = 2 * i;
0N/A tbl[offs] = keys.elementAt(i);
0N/A tbl[offs + 1] = data.elementAt(i);
0N/A }
0N/A return tbl;
0N/A }
0N/A
0N/A /**
0N/A * The number of key/value pairs contained
0N/A * in the current key being forged.
0N/A */
0N/A int getCount() {
0N/A return keys.size();
0N/A }
0N/A
0N/A /**
0N/A * Adds a key/value to the set.
0N/A */
0N/A public void addAttribute(Object key, Object value) {
0N/A keys.addElement(key);
0N/A data.addElement(value);
0N/A }
0N/A
0N/A /**
0N/A * Adds a set of key/value pairs to the set.
0N/A */
0N/A public void addAttributes(AttributeSet attr) {
0N/A if (attr instanceof SmallAttributeSet) {
0N/A // avoid searching the keys, they are already interned.
0N/A Object[] tbl = ((SmallAttributeSet)attr).attributes;
0N/A int n = tbl.length;
0N/A for (int i = 0; i < n; i += 2) {
0N/A addAttribute(tbl[i], tbl[i+1]);
0N/A }
0N/A } else {
0N/A Enumeration names = attr.getAttributeNames();
0N/A while (names.hasMoreElements()) {
0N/A Object name = names.nextElement();
0N/A addAttribute(name, attr.getAttribute(name));
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Removes the given name from the set.
0N/A */
0N/A public void removeAttribute(Object key) {
0N/A int n = keys.size();
0N/A for (int i = 0; i < n; i++) {
0N/A if (keys.elementAt(i).equals(key)) {
0N/A keys.removeElementAt(i);
0N/A data.removeElementAt(i);
0N/A return;
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Removes the set of keys from the set.
0N/A */
0N/A public void removeAttributes(Enumeration names) {
0N/A while (names.hasMoreElements()) {
0N/A Object name = names.nextElement();
0N/A removeAttribute(name);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Removes the set of matching attributes from the set.
0N/A */
0N/A public void removeAttributes(AttributeSet attr) {
0N/A Enumeration names = attr.getAttributeNames();
0N/A while (names.hasMoreElements()) {
0N/A Object name = names.nextElement();
0N/A Object value = attr.getAttribute(name);
0N/A removeSearchAttribute(name, value);
0N/A }
0N/A }
0N/A
0N/A private void removeSearchAttribute(Object ikey, Object value) {
0N/A int n = keys.size();
0N/A for (int i = 0; i < n; i++) {
0N/A if (keys.elementAt(i).equals(ikey)) {
0N/A if (data.elementAt(i).equals(value)) {
0N/A keys.removeElementAt(i);
0N/A data.removeElementAt(i);
0N/A }
0N/A return;
0N/A }
0N/A }
0N/A }
0N/A
611N/A private Vector<Object> keys = new Vector<Object>();
611N/A private Vector<Object> data = new Vector<Object>();
0N/A }
0N/A
0N/A /**
0N/A * key for a font table
0N/A */
0N/A static class FontKey {
0N/A
0N/A private String family;
0N/A private int style;
0N/A private int size;
0N/A
0N/A /**
0N/A * Constructs a font key.
0N/A */
0N/A public FontKey(String family, int style, int size) {
0N/A setValue(family, style, size);
0N/A }
0N/A
0N/A public void setValue(String family, int style, int size) {
0N/A this.family = (family != null) ? family.intern() : null;
0N/A this.style = style;
0N/A this.size = size;
0N/A }
0N/A
0N/A /**
0N/A * Returns a hashcode for this font.
0N/A * @return a hashcode value for this font.
0N/A */
0N/A public int hashCode() {
0N/A int fhash = (family != null) ? family.hashCode() : 0;
0N/A return fhash ^ style ^ size;
0N/A }
0N/A
0N/A /**
0N/A * Compares this object to the specifed object.
0N/A * The result is <code>true</code> if and only if the argument is not
0N/A * <code>null</code> and is a <code>Font</code> object with the same
0N/A * name, style, and point size as this font.
0N/A * @param obj the object to compare this font with.
0N/A * @return <code>true</code> if the objects are equal;
0N/A * <code>false</code> otherwise.
0N/A */
0N/A public boolean equals(Object obj) {
0N/A if (obj instanceof FontKey) {
0N/A FontKey font = (FontKey)obj;
0N/A return (size == font.size) && (style == font.style) && (family == font.family);
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A }
0N/A
0N/A /**
0N/A * A collection of attributes, typically used to represent
0N/A * character and paragraph styles. This is an implementation
0N/A * of MutableAttributeSet that can be observed if desired.
0N/A * These styles will take advantage of immutability while
0N/A * the sets are small enough, and may be substantially more
0N/A * efficient than something like SimpleAttributeSet.
0N/A * <p>
0N/A * <strong>Warning:</strong>
0N/A * Serialized objects of this class will not be compatible with
0N/A * future Swing releases. The current serialization support is
0N/A * appropriate for short term storage or RMI between applications running
0N/A * the same version of Swing. As of 1.4, support for long term storage
0N/A * of all JavaBeans<sup><font size="-2">TM</font></sup>
0N/A * has been added to the <code>java.beans</code> package.
0N/A * Please see {@link java.beans.XMLEncoder}.
0N/A */
0N/A public class NamedStyle implements Style, Serializable {
0N/A
0N/A /**
0N/A * Creates a new named style.
0N/A *
0N/A * @param name the style name, null for unnamed
0N/A * @param parent the parent style, null if none
0N/A * @since 1.4
0N/A */
0N/A public NamedStyle(String name, Style parent) {
0N/A attributes = getEmptySet();
0N/A if (name != null) {
0N/A setName(name);
0N/A }
0N/A if (parent != null) {
0N/A setResolveParent(parent);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Creates a new named style.
0N/A *
0N/A * @param parent the parent style, null if none
0N/A * @since 1.4
0N/A */
0N/A public NamedStyle(Style parent) {
0N/A this(null, parent);
0N/A }
0N/A
0N/A /**
0N/A * Creates a new named style, with a null name and parent.
0N/A */
0N/A public NamedStyle() {
0N/A attributes = getEmptySet();
0N/A }
0N/A
0N/A /**
0N/A * Converts the style to a string.
0N/A *
0N/A * @return the string
0N/A */
0N/A public String toString() {
0N/A return "NamedStyle:" + getName() + " " + attributes;
0N/A }
0N/A
0N/A /**
0N/A * Fetches the name of the style. A style is not required to be named,
0N/A * so null is returned if there is no name associated with the style.
0N/A *
0N/A * @return the name
0N/A */
0N/A public String getName() {
0N/A if (isDefined(StyleConstants.NameAttribute)) {
0N/A return getAttribute(StyleConstants.NameAttribute).toString();
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Changes the name of the style. Does nothing with a null name.
0N/A *
0N/A * @param name the new name
0N/A */
0N/A public void setName(String name) {
0N/A if (name != null) {
0N/A this.addAttribute(StyleConstants.NameAttribute, name);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Adds a change listener.
0N/A *
0N/A * @param l the change listener
0N/A */
0N/A public void addChangeListener(ChangeListener l) {
0N/A listenerList.add(ChangeListener.class, l);
0N/A }
0N/A
0N/A /**
0N/A * Removes a change listener.
0N/A *
0N/A * @param l the change listener
0N/A */
0N/A public void removeChangeListener(ChangeListener l) {
0N/A listenerList.remove(ChangeListener.class, l);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns an array of all the <code>ChangeListener</code>s added
0N/A * to this NamedStyle with addChangeListener().
0N/A *
0N/A * @return all of the <code>ChangeListener</code>s added or an empty
0N/A * array if no listeners have been added
0N/A * @since 1.4
0N/A */
0N/A public ChangeListener[] getChangeListeners() {
611N/A return listenerList.getListeners(ChangeListener.class);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Notifies all listeners that have registered interest for
0N/A * notification on this event type. The event instance
0N/A * is lazily created using the parameters passed into
0N/A * the fire method.
0N/A *
0N/A * @see EventListenerList
0N/A */
0N/A protected void fireStateChanged() {
0N/A // Guaranteed to return a non-null array
0N/A Object[] listeners = listenerList.getListenerList();
0N/A // Process the listeners last to first, notifying
0N/A // those that are interested in this event
0N/A for (int i = listeners.length-2; i>=0; i-=2) {
0N/A if (listeners[i]==ChangeListener.class) {
0N/A // Lazily create the event:
0N/A if (changeEvent == null)
0N/A changeEvent = new ChangeEvent(this);
0N/A ((ChangeListener)listeners[i+1]).stateChanged(changeEvent);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Return an array of all the listeners of the given type that
0N/A * were added to this model.
0N/A *
0N/A * @return all of the objects receiving <em>listenerType</em> notifications
0N/A * from this model
0N/A *
0N/A * @since 1.3
0N/A */
0N/A public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
0N/A return listenerList.getListeners(listenerType);
0N/A }
0N/A
0N/A // --- AttributeSet ----------------------------
0N/A // delegated to the immutable field "attributes"
0N/A
0N/A /**
0N/A * Gets the number of attributes that are defined.
0N/A *
0N/A * @return the number of attributes >= 0
0N/A * @see AttributeSet#getAttributeCount
0N/A */
0N/A public int getAttributeCount() {
0N/A return attributes.getAttributeCount();
0N/A }
0N/A
0N/A /**
0N/A * Checks whether a given attribute is defined.
0N/A *
0N/A * @param attrName the non-null attribute name
0N/A * @return true if the attribute is defined
0N/A * @see AttributeSet#isDefined
0N/A */
0N/A public boolean isDefined(Object attrName) {
0N/A return attributes.isDefined(attrName);
0N/A }
0N/A
0N/A /**
0N/A * Checks whether two attribute sets are equal.
0N/A *
0N/A * @param attr the attribute set to check against
0N/A * @return true if the same
0N/A * @see AttributeSet#isEqual
0N/A */
0N/A public boolean isEqual(AttributeSet attr) {
0N/A return attributes.isEqual(attr);
0N/A }
0N/A
0N/A /**
0N/A * Copies a set of attributes.
0N/A *
0N/A * @return the copy
0N/A * @see AttributeSet#copyAttributes
0N/A */
0N/A public AttributeSet copyAttributes() {
0N/A NamedStyle a = new NamedStyle();
0N/A a.attributes = attributes.copyAttributes();
0N/A return a;
0N/A }
0N/A
0N/A /**
0N/A * Gets the value of an attribute.
0N/A *
0N/A * @param attrName the non-null attribute name
0N/A * @return the attribute value
0N/A * @see AttributeSet#getAttribute
0N/A */
0N/A public Object getAttribute(Object attrName) {
0N/A return attributes.getAttribute(attrName);
0N/A }
0N/A
0N/A /**
0N/A * Gets the names of all attributes.
0N/A *
0N/A * @return the attribute names as an enumeration
0N/A * @see AttributeSet#getAttributeNames
0N/A */
0N/A public Enumeration<?> getAttributeNames() {
0N/A return attributes.getAttributeNames();
0N/A }
0N/A
0N/A /**
0N/A * Checks whether a given attribute name/value is defined.
0N/A *
0N/A * @param name the non-null attribute name
0N/A * @param value the attribute value
0N/A * @return true if the name/value is defined
0N/A * @see AttributeSet#containsAttribute
0N/A */
0N/A public boolean containsAttribute(Object name, Object value) {
0N/A return attributes.containsAttribute(name, value);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Checks whether the element contains all the attributes.
0N/A *
0N/A * @param attrs the attributes to check
0N/A * @return true if the element contains all the attributes
0N/A * @see AttributeSet#containsAttributes
0N/A */
0N/A public boolean containsAttributes(AttributeSet attrs) {
0N/A return attributes.containsAttributes(attrs);
0N/A }
0N/A
0N/A /**
0N/A * Gets attributes from the parent.
0N/A * If not overriden, the resolving parent defaults to
0N/A * the parent element.
0N/A *
0N/A * @return the attributes from the parent
0N/A * @see AttributeSet#getResolveParent
0N/A */
0N/A public AttributeSet getResolveParent() {
0N/A return attributes.getResolveParent();
0N/A }
0N/A
0N/A // --- MutableAttributeSet ----------------------------------
0N/A // should fetch a new immutable record for the field
0N/A // "attributes".
0N/A
0N/A /**
0N/A * Adds an attribute.
0N/A *
0N/A * @param name the non-null attribute name
0N/A * @param value the attribute value
0N/A * @see MutableAttributeSet#addAttribute
0N/A */
0N/A public void addAttribute(Object name, Object value) {
0N/A StyleContext context = StyleContext.this;
0N/A attributes = context.addAttribute(attributes, name, value);
0N/A fireStateChanged();
0N/A }
0N/A
0N/A /**
0N/A * Adds a set of attributes to the element.
0N/A *
0N/A * @param attr the attributes to add
0N/A * @see MutableAttributeSet#addAttribute
0N/A */
0N/A public void addAttributes(AttributeSet attr) {
0N/A StyleContext context = StyleContext.this;
0N/A attributes = context.addAttributes(attributes, attr);
0N/A fireStateChanged();
0N/A }
0N/A
0N/A /**
0N/A * Removes an attribute from the set.
0N/A *
0N/A * @param name the non-null attribute name
0N/A * @see MutableAttributeSet#removeAttribute
0N/A */
0N/A public void removeAttribute(Object name) {
0N/A StyleContext context = StyleContext.this;
0N/A attributes = context.removeAttribute(attributes, name);
0N/A fireStateChanged();
0N/A }
0N/A
0N/A /**
0N/A * Removes a set of attributes for the element.
0N/A *
0N/A * @param names the attribute names
0N/A * @see MutableAttributeSet#removeAttributes
0N/A */
0N/A public void removeAttributes(Enumeration<?> names) {
0N/A StyleContext context = StyleContext.this;
0N/A attributes = context.removeAttributes(attributes, names);
0N/A fireStateChanged();
0N/A }
0N/A
0N/A /**
0N/A * Removes a set of attributes for the element.
0N/A *
0N/A * @param attrs the attributes
0N/A * @see MutableAttributeSet#removeAttributes
0N/A */
0N/A public void removeAttributes(AttributeSet attrs) {
0N/A StyleContext context = StyleContext.this;
0N/A if (attrs == this) {
0N/A attributes = context.getEmptySet();
0N/A } else {
0N/A attributes = context.removeAttributes(attributes, attrs);
0N/A }
0N/A fireStateChanged();
0N/A }
0N/A
0N/A /**
0N/A * Sets the resolving parent.
0N/A *
0N/A * @param parent the parent, null if none
0N/A * @see MutableAttributeSet#setResolveParent
0N/A */
0N/A public void setResolveParent(AttributeSet parent) {
0N/A if (parent != null) {
0N/A addAttribute(StyleConstants.ResolveAttribute, parent);
0N/A } else {
0N/A removeAttribute(StyleConstants.ResolveAttribute);
0N/A }
0N/A }
0N/A
0N/A // --- serialization ---------------------------------------------
0N/A
0N/A private void writeObject(ObjectOutputStream s) throws IOException {
0N/A s.defaultWriteObject();
0N/A writeAttributeSet(s, attributes);
0N/A }
0N/A
0N/A private void readObject(ObjectInputStream s)
0N/A throws ClassNotFoundException, IOException
0N/A {
0N/A s.defaultReadObject();
0N/A attributes = SimpleAttributeSet.EMPTY;
0N/A readAttributeSet(s, this);
0N/A }
0N/A
0N/A // --- member variables -----------------------------------------------
0N/A
0N/A /**
0N/A * The change listeners for the model.
0N/A */
0N/A protected EventListenerList listenerList = new EventListenerList();
0N/A
0N/A /**
0N/A * Only one ChangeEvent is needed per model instance since the
0N/A * event's only (read-only) state is the source property. The source
0N/A * of events generated here is always "this".
0N/A */
0N/A protected transient ChangeEvent changeEvent = null;
0N/A
0N/A /**
0N/A * Inner AttributeSet implementation, which may be an
0N/A * immutable unique set being shared.
0N/A */
0N/A private transient AttributeSet attributes;
0N/A
0N/A }
0N/A
0N/A static {
0N/A // initialize the static key registry with the StyleConstants keys
0N/A try {
0N/A int n = StyleConstants.keys.length;
0N/A for (int i = 0; i < n; i++) {
0N/A StyleContext.registerStaticAttributeKey(StyleConstants.keys[i]);
0N/A }
0N/A } catch (Throwable e) {
0N/A e.printStackTrace();
0N/A }
0N/A }
0N/A
0N/A
0N/A}