KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > text > StyleContext


1 /*
2  * @(#)StyleContext.java 1.79 05/11/10
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7 package javax.swing.text;
8
9 import java.awt.*;
10 import java.util.*;
11 import java.io.*;
12
13 import javax.swing.SwingUtilities JavaDoc;
14 import javax.swing.event.ChangeListener JavaDoc;
15 import javax.swing.event.EventListenerList JavaDoc;
16 import javax.swing.event.ChangeEvent JavaDoc;
17 import java.lang.ref.WeakReference JavaDoc;
18 import java.util.WeakHashMap JavaDoc;
19
20 import sun.font.FontManager;
21
22 /**
23  * A pool of styles and their associated resources. This class determines
24  * the lifetime of a group of resources by being a container that holds
25  * caches for various resources such as font and color that get reused
26  * by the various style definitions. This can be shared by multiple
27  * documents if desired to maximize the sharing of related resources.
28  * <p>
29  * This class also provides efficient support for small sets of attributes
30  * and compresses them by sharing across uses and taking advantage of
31  * their immutable nature. Since many styles are replicated, the potential
32  * for sharing is significant, and copies can be extremely cheap.
33  * Larger sets reduce the possibility of sharing, and therefore revert
34  * automatically to a less space-efficient implementation.
35  * <p>
36  * <strong>Warning:</strong>
37  * Serialized objects of this class will not be compatible with
38  * future Swing releases. The current serialization support is
39  * appropriate for short term storage or RMI between applications running
40  * the same version of Swing. As of 1.4, support for long term storage
41  * of all JavaBeans<sup><font size="-2">TM</font></sup>
42  * has been added to the <code>java.beans</code> package.
43  * Please see {@link java.beans.XMLEncoder}.
44  *
45  * @author Timothy Prinzing
46  * @version 1.79 11/10/05
47  */

48 public class StyleContext implements Serializable, AbstractDocument.AttributeContext JavaDoc {
49
50     /**
51      * Returns default AttributeContext shared by all documents that
52      * don't bother to define/supply their own context.
53      *
54      * @return the context
55      */

56     public static final StyleContext JavaDoc getDefaultStyleContext() {
57         if (defaultContext == null) {
58             defaultContext = new StyleContext JavaDoc();
59         }
60         return defaultContext;
61     }
62
63     private static StyleContext JavaDoc defaultContext;
64
65     /**
66      * Creates a new StyleContext object.
67      */

68     public StyleContext() {
69         styles = new NamedStyle(null);
70         addStyle(DEFAULT_STYLE, null);
71     }
72
73     /**
74      * Adds a new style into the style hierarchy. Style attributes
75      * resolve from bottom up so an attribute specified in a child
76      * will override an attribute specified in the parent.
77      *
78      * @param nm the name of the style (must be unique within the
79      * collection of named styles in the document). The name may
80      * be null if the style is unnamed, but the caller is responsible
81      * for managing the reference returned as an unnamed style can't
82      * be fetched by name. An unnamed style may be useful for things
83      * like character attribute overrides such as found in a style
84      * run.
85      * @param parent the parent style. This may be null if unspecified
86      * attributes need not be resolved in some other style.
87      * @return the created style
88      */

89     public Style JavaDoc addStyle(String JavaDoc nm, Style JavaDoc parent) {
90         Style JavaDoc style = new NamedStyle(nm, parent);
91         if (nm != null) {
92             // add a named style, a class of attributes
93
styles.addAttribute(nm, style);
94         }
95         return style;
96     }
97
98     /**
99      * Removes a named style previously added to the document.
100      *
101      * @param nm the name of the style to remove
102      */

103     public void removeStyle(String JavaDoc nm) {
104         styles.removeAttribute(nm);
105     }
106
107     /**
108      * Fetches a named style previously added to the document
109      *
110      * @param nm the name of the style
111      * @return the style
112      */

113     public Style JavaDoc getStyle(String JavaDoc nm) {
114         return (Style JavaDoc) styles.getAttribute(nm);
115     }
116
117     /**
118      * Fetches the names of the styles defined.
119      *
120      * @return the list of names as an enumeration
121      */

122     public Enumeration<?> getStyleNames() {
123         return styles.getAttributeNames();
124     }
125
126     /**
127      * Adds a listener to track when styles are added
128      * or removed.
129      *
130      * @param l the change listener
131      */

132     public void addChangeListener(ChangeListener JavaDoc l) {
133         styles.addChangeListener(l);
134     }
135
136     /**
137      * Removes a listener that was tracking styles being
138      * added or removed.
139      *
140      * @param l the change listener
141      */

142     public void removeChangeListener(ChangeListener JavaDoc l) {
143         styles.removeChangeListener(l);
144     }
145
146     /**
147      * Returns an array of all the <code>ChangeListener</code>s added
148      * to this StyleContext with addChangeListener().
149      *
150      * @return all of the <code>ChangeListener</code>s added or an empty
151      * array if no listeners have been added
152      * @since 1.4
153      */

154     public ChangeListener JavaDoc[] getChangeListeners() {
155         return ((NamedStyle)styles).getChangeListeners();
156     }
157
158     /**
159      * Gets the font from an attribute set. This is
160      * implemented to try and fetch a cached font
161      * for the given AttributeSet, and if that fails
162      * the font features are resolved and the
163      * font is fetched from the low-level font cache.
164      *
165      * @param attr the attribute set
166      * @return the font
167      */

168     public Font getFont(AttributeSet JavaDoc attr) {
169         // PENDING(prinz) add cache behavior
170
int style = Font.PLAIN;
171         if (StyleConstants.isBold(attr)) {
172             style |= Font.BOLD;
173         }
174         if (StyleConstants.isItalic(attr)) {
175             style |= Font.ITALIC;
176         }
177         String JavaDoc family = StyleConstants.getFontFamily(attr);
178         int size = StyleConstants.getFontSize(attr);
179
180     /**
181      * if either superscript or subscript is
182      * is set, we need to reduce the font size
183      * by 2.
184      */

185     if (StyleConstants.isSuperscript(attr) ||
186         StyleConstants.isSubscript(attr)) {
187         size -= 2;
188     }
189
190         return getFont(family, style, size);
191     }
192
193     /**
194      * Takes a set of attributes and turn it into a foreground color
195      * specification. This might be used to specify things
196      * like brighter, more hue, etc. By default it simply returns
197      * the value specified by the StyleConstants.Foreground attribute.
198      *
199      * @param attr the set of attributes
200      * @return the color
201      */

202     public Color getForeground(AttributeSet JavaDoc attr) {
203     return StyleConstants.getForeground(attr);
204     }
205
206     /**
207      * Takes a set of attributes and turn it into a background color
208      * specification. This might be used to specify things
209      * like brighter, more hue, etc. By default it simply returns
210      * the value specified by the StyleConstants.Background attribute.
211      *
212      * @param attr the set of attributes
213      * @return the color
214      */

215     public Color getBackground(AttributeSet JavaDoc attr) {
216     return StyleConstants.getBackground(attr);
217     }
218
219     /**
220      * Gets a new font. This returns a Font from a cache
221      * if a cached font exists. If not, a Font is added to
222      * the cache. This is basically a low-level cache for
223      * 1.1 font features.
224      *
225      * @param family the font family (such as "Monospaced")
226      * @param style the style of the font (such as Font.PLAIN)
227      * @param size the point size >= 1
228      * @return the new font
229      */

230     public Font getFont(String JavaDoc family, int style, int size) {
231         fontSearch.setValue(family, style, size);
232         Font f = (Font) fontTable.get(fontSearch);
233         if (f == null) {
234             // haven't seen this one yet.
235
Style JavaDoc defaultStyle =
236                 getStyle(StyleContext.DEFAULT_STYLE);
237             if (defaultStyle != null) {
238                 final String JavaDoc FONT_ATTRIBUTE_KEY = "FONT_ATTRIBUTE_KEY";
239                 Font defaultFont =
240                     (Font) defaultStyle.getAttribute(FONT_ATTRIBUTE_KEY);
241                 if (defaultFont != null
242                       && defaultFont.getFamily().equalsIgnoreCase(family)) {
243                     f = defaultFont.deriveFont(style, size);
244                 }
245             }
246             if (f == null) {
247                 f = new Font(family, style, size);
248             }
249             if (! FontManager.fontSupportsDefaultEncoding(f)) {
250                 f = FontManager.getCompositeFontUIResource(f);
251             }
252             FontKey key = new FontKey(family, style, size);
253             fontTable.put(key, f);
254         }
255         return f;
256     }
257
258     /**
259      * Returns font metrics for a font.
260      *
261      * @param f the font
262      * @return the metrics
263      */

264     public FontMetrics getFontMetrics(Font f) {
265         // The Toolkit implementations cache, so we just forward
266
// to the default toolkit.
267
return Toolkit.getDefaultToolkit().getFontMetrics(f);
268     }
269
270     // --- AttributeContext methods --------------------
271

272     /**
273      * Adds an attribute to the given set, and returns
274      * the new representative set.
275      * <p>
276      * This method is thread safe, although most Swing methods
277      * are not. Please see
278      * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
279      * and Swing</A> for more information.
280      *
281      * @param old the old attribute set
282      * @param name the non-null attribute name
283      * @param value the attribute value
284      * @return the updated attribute set
285      * @see MutableAttributeSet#addAttribute
286      */

287     public synchronized AttributeSet JavaDoc addAttribute(AttributeSet JavaDoc old, Object JavaDoc name, Object JavaDoc value) {
288         if ((old.getAttributeCount() + 1) <= getCompressionThreshold()) {
289             // build a search key and find/create an immutable and unique
290
// set.
291
search.removeAttributes(search);
292             search.addAttributes(old);
293             search.addAttribute(name, value);
294             reclaim(old);
295             return getImmutableUniqueSet();
296         }
297         MutableAttributeSet JavaDoc ma = getMutableAttributeSet(old);
298         ma.addAttribute(name, value);
299         return ma;
300     }
301
302     /**
303      * Adds a set of attributes to the element.
304      * <p>
305      * This method is thread safe, although most Swing methods
306      * are not. Please see
307      * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
308      * and Swing</A> for more information.
309      *
310      * @param old the old attribute set
311      * @param attr the attributes to add
312      * @return the updated attribute set
313      * @see MutableAttributeSet#addAttribute
314      */

315     public synchronized AttributeSet JavaDoc addAttributes(AttributeSet JavaDoc old, AttributeSet JavaDoc attr) {
316         if ((old.getAttributeCount() + attr.getAttributeCount()) <= getCompressionThreshold()) {
317             // build a search key and find/create an immutable and unique
318
// set.
319
search.removeAttributes(search);
320             search.addAttributes(old);
321             search.addAttributes(attr);
322             reclaim(old);
323             return getImmutableUniqueSet();
324         }
325         MutableAttributeSet JavaDoc ma = getMutableAttributeSet(old);
326         ma.addAttributes(attr);
327         return ma;
328     }
329
330     /**
331      * Removes an attribute from the set.
332      * <p>
333      * This method is thread safe, although most Swing methods
334      * are not. Please see
335      * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
336      * and Swing</A> for more information.
337      *
338      * @param old the old set of attributes
339      * @param name the non-null attribute name
340      * @return the updated attribute set
341      * @see MutableAttributeSet#removeAttribute
342      */

343     public synchronized AttributeSet JavaDoc removeAttribute(AttributeSet JavaDoc old, Object JavaDoc name) {
344         if ((old.getAttributeCount() - 1) <= getCompressionThreshold()) {
345             // build a search key and find/create an immutable and unique
346
// set.
347
search.removeAttributes(search);
348             search.addAttributes(old);
349             search.removeAttribute(name);
350             reclaim(old);
351             return getImmutableUniqueSet();
352         }
353         MutableAttributeSet JavaDoc ma = getMutableAttributeSet(old);
354         ma.removeAttribute(name);
355         return ma;
356     }
357
358     /**
359      * Removes a set of attributes for the element.
360      * <p>
361      * This method is thread safe, although most Swing methods
362      * are not. Please see
363      * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
364      * and Swing</A> for more information.
365      *
366      * @param old the old attribute set
367      * @param names the attribute names
368      * @return the updated attribute set
369      * @see MutableAttributeSet#removeAttributes
370      */

371     public synchronized AttributeSet JavaDoc removeAttributes(AttributeSet JavaDoc old, Enumeration<?> names) {
372         if (old.getAttributeCount() <= getCompressionThreshold()) {
373             // build a search key and find/create an immutable and unique
374
// set.
375
search.removeAttributes(search);
376             search.addAttributes(old);
377             search.removeAttributes(names);
378             reclaim(old);
379             return getImmutableUniqueSet();
380         }
381         MutableAttributeSet JavaDoc ma = getMutableAttributeSet(old);
382         ma.removeAttributes(names);
383         return ma;
384     }
385
386     /**
387      * Removes a set of attributes for the element.
388      * <p>
389      * This method is thread safe, although most Swing methods
390      * are not. Please see
391      * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
392      * and Swing</A> for more information.
393      *
394      * @param old the old attribute set
395      * @param attrs the attributes
396      * @return the updated attribute set
397      * @see MutableAttributeSet#removeAttributes
398      */

399     public synchronized AttributeSet JavaDoc removeAttributes(AttributeSet JavaDoc old, AttributeSet JavaDoc attrs) {
400         if (old.getAttributeCount() <= getCompressionThreshold()) {
401             // build a search key and find/create an immutable and unique
402
// set.
403
search.removeAttributes(search);
404             search.addAttributes(old);
405             search.removeAttributes(attrs);
406             reclaim(old);
407             return getImmutableUniqueSet();
408         }
409         MutableAttributeSet JavaDoc ma = getMutableAttributeSet(old);
410         ma.removeAttributes(attrs);
411         return ma;
412     }
413
414     /**
415      * Fetches an empty AttributeSet.
416      *
417      * @return the set
418      */

419     public AttributeSet JavaDoc getEmptySet() {
420         return SimpleAttributeSet.EMPTY;
421     }
422
423     /**
424      * Returns a set no longer needed by the MutableAttributeSet implmentation.
425      * This is useful for operation under 1.1 where there are no weak
426      * references. This would typically be called by the finalize method
427      * of the MutableAttributeSet implementation.
428      * <p>
429      * This method is thread safe, although most Swing methods
430      * are not. Please see
431      * <A HREF="http://java.sun.com/products/jfc/swingdoc-archive/threads.html">Threads
432      * and Swing</A> for more information.
433      *
434      * @param a the set to reclaim
435      */

436     public void reclaim(AttributeSet JavaDoc a) {
437     if (SwingUtilities.isEventDispatchThread()) {
438         attributesPool.size(); // force WeakHashMap to expunge stale entries
439
}
440     // if current thread is not event dispatching thread
441
// do not bother with expunging stale entries.
442
}
443
444     // --- local methods -----------------------------------------------
445

446     /**
447      * Returns the maximum number of key/value pairs to try and
448      * compress into unique/immutable sets. Any sets above this
449      * limit will use hashtables and be a MutableAttributeSet.
450      *
451      * @return the threshold
452      */

453     protected int getCompressionThreshold() {
454         return THRESHOLD;
455     }
456
457     /**
458      * Create a compact set of attributes that might be shared.
459      * This is a hook for subclasses that want to alter the
460      * behavior of SmallAttributeSet. This can be reimplemented
461      * to return an AttributeSet that provides some sort of
462      * attribute conversion.
463      *
464      * @param a The set of attributes to be represented in the
465      * the compact form.
466      */

467     protected SmallAttributeSet createSmallAttributeSet(AttributeSet JavaDoc a) {
468     return new SmallAttributeSet(a);
469     }
470
471     /**
472      * Create a large set of attributes that should trade off
473      * space for time. This set will not be shared. This is
474      * a hook for subclasses that want to alter the behavior
475      * of the larger attribute storage format (which is
476      * SimpleAttributeSet by default). This can be reimplemented
477      * to return a MutableAttributeSet that provides some sort of
478      * attribute conversion.
479      *
480      * @param a The set of attributes to be represented in the
481      * the larger form.
482      */

483     protected MutableAttributeSet JavaDoc createLargeAttributeSet(AttributeSet JavaDoc a) {
484         return new SimpleAttributeSet JavaDoc(a);
485     }
486
487     /**
488      * Clean the unused immutable sets out of the hashtable.
489      */

490     synchronized void removeUnusedSets() {
491     attributesPool.size(); // force WeakHashMap to expunge stale entries
492
}
493
494     /**
495      * Search for an existing attribute set using the current search
496      * parameters. If a matching set is found, return it. If a match
497      * is not found, we create a new set and add it to the pool.
498      */

499     AttributeSet JavaDoc getImmutableUniqueSet() {
500     // PENDING(prinz) should consider finding a alternative to
501
// generating extra garbage on search key.
502
SmallAttributeSet key = createSmallAttributeSet(search);
503     WeakReference JavaDoc reference = (WeakReference JavaDoc)attributesPool.get(key);
504         SmallAttributeSet a;
505         if (reference == null
506         || (a = (SmallAttributeSet)reference.get()) == null) {
507             a = key;
508             attributesPool.put(a, new WeakReference JavaDoc(a));
509         }
510         return a;
511     }
512
513     /**
514      * Creates a mutable attribute set to hand out because the current
515      * needs are too big to try and use a shared version.
516      */

517     MutableAttributeSet JavaDoc getMutableAttributeSet(AttributeSet JavaDoc a) {
518         if (a instanceof MutableAttributeSet JavaDoc &&
519         a != SimpleAttributeSet.EMPTY) {
520             return (MutableAttributeSet JavaDoc) a;
521         }
522         return createLargeAttributeSet(a);
523     }
524
525     /**
526      * Converts a StyleContext to a String.
527      *
528      * @return the string
529      */

530     public String JavaDoc toString() {
531         removeUnusedSets();
532         String JavaDoc s = "";
533         Iterator iterator = attributesPool.keySet().iterator();
534         while (iterator.hasNext()) {
535             SmallAttributeSet set = (SmallAttributeSet)iterator.next();
536             s = s + set + "\n";
537         }
538         return s;
539     }
540
541     // --- serialization ---------------------------------------------
542

543     /**
544      * Context-specific handling of writing out attributes
545      */

546     public void writeAttributes(ObjectOutputStream out,
547                   AttributeSet JavaDoc a) throws IOException {
548         writeAttributeSet(out, a);
549     }
550
551     /**
552      * Context-specific handling of reading in attributes
553      */

554     public void readAttributes(ObjectInputStream in,
555                    MutableAttributeSet JavaDoc a) throws ClassNotFoundException JavaDoc, IOException {
556         readAttributeSet(in, a);
557     }
558                   
559     /**
560      * Writes a set of attributes to the given object stream
561      * for the purpose of serialization. This will take
562      * special care to deal with static attribute keys that
563      * have been registered wit the
564      * <code>registerStaticAttributeKey</code> method.
565      * Any attribute key not regsitered as a static key
566      * will be serialized directly. All values are expected
567      * to be serializable.
568      *
569      * @param out the output stream
570      * @param a the attribute set
571      * @exception IOException on any I/O error
572      */

573     public static void writeAttributeSet(ObjectOutputStream out,
574                                          AttributeSet JavaDoc a) throws IOException {
575         int n = a.getAttributeCount();
576         out.writeInt(n);
577         Enumeration keys = a.getAttributeNames();
578         while (keys.hasMoreElements()) {
579             Object JavaDoc key = keys.nextElement();
580             if (key instanceof Serializable) {
581                 out.writeObject(key);
582             } else {
583                 Object JavaDoc ioFmt = freezeKeyMap.get(key);
584         if (ioFmt == null) {
585             throw new NotSerializableException(key.getClass().
586                      getName() + " is not serializable as a key in an AttributeSet");
587         }
588                 out.writeObject(ioFmt);
589             }
590             Object JavaDoc value = a.getAttribute(key);
591             Object JavaDoc ioFmt = freezeKeyMap.get(value);
592             if (value instanceof Serializable) {
593                 out.writeObject((ioFmt != null) ? ioFmt : value);
594             } else {
595         if (ioFmt == null) {
596             throw new NotSerializableException(value.getClass().
597                      getName() + " is not serializable as a value in an AttributeSet");
598         }
599                 out.writeObject(ioFmt);
600             }
601         }
602     }
603
604     /**
605      * Reads a set of attributes from the given object input
606      * stream that have been previously written out with
607      * <code>writeAttributeSet</code>. This will try to restore
608      * keys that were static objects to the static objects in
609      * the current virtual machine considering only those keys
610      * that have been registered with the
611      * <code>registerStaticAttributeKey</code> method.
612      * The attributes retrieved from the stream will be placed
613      * into the given mutable set.
614      *
615      * @param in the object stream to read the attribute data from.
616      * @param a the attribute set to place the attribute
617      * definitions in.
618      * @exception ClassNotFoundException passed upward if encountered
619      * when reading the object stream.
620      * @exception IOException passed upward if encountered when
621      * reading the object stream.
622      */

623     public static void readAttributeSet(ObjectInputStream in,
624         MutableAttributeSet JavaDoc a) throws ClassNotFoundException JavaDoc, IOException {
625
626         int n = in.readInt();
627         for (int i = 0; i < n; i++) {
628             Object JavaDoc key = in.readObject();
629             Object JavaDoc value = in.readObject();
630         if (thawKeyMap != null) {
631         Object JavaDoc staticKey = thawKeyMap.get(key);
632         if (staticKey != null) {
633             key = staticKey;
634         }
635         Object JavaDoc staticValue = thawKeyMap.get(value);
636         if (staticValue != null) {
637             value = staticValue;
638         }
639         }
640             a.addAttribute(key, value);
641         }
642     }
643
644     /**
645      * Registers an object as a static object that is being
646      * used as a key in attribute sets. This allows the key
647      * to be treated specially for serialization.
648      * <p>
649      * For operation under a 1.1 virtual machine, this
650      * uses the value returned by <code>toString</code>
651      * concatenated to the classname. The value returned
652      * by toString should not have the class reference
653      * in it (ie it should be reimplemented from the
654      * definition in Object) in order to be the same when
655      * recomputed later.
656      *
657      * @param key the non-null object key
658      */

659     public static void registerStaticAttributeKey(Object JavaDoc key) {
660         String JavaDoc ioFmt = key.getClass().getName() + "." + key.toString();
661         if (freezeKeyMap == null) {
662             freezeKeyMap = new Hashtable();
663             thawKeyMap = new Hashtable();
664         }
665         freezeKeyMap.put(key, ioFmt);
666         thawKeyMap.put(ioFmt, key);
667     }
668
669     /**
670      * Returns the object previously registered with
671      * <code>registerStaticAttributeKey</code>.
672      */

673     public static Object JavaDoc getStaticAttribute(Object JavaDoc key) {
674     if (thawKeyMap == null || key == null) {
675         return null;
676     }
677     return thawKeyMap.get(key);
678     }
679
680     /**
681      * Returns the String that <code>key</code> will be registered with
682      * @see #getStaticAttribute
683      * @see #registerStaticAttributeKey
684      */

685     public static Object JavaDoc getStaticAttributeKey(Object JavaDoc key) {
686         return key.getClass().getName() + "." + key.toString();
687     }
688
689     private void writeObject(java.io.ObjectOutputStream JavaDoc s)
690         throws IOException
691     {
692         // clean out unused sets before saving
693
removeUnusedSets();
694
695         s.defaultWriteObject();
696     }
697
698     private void readObject(ObjectInputStream s)
699       throws ClassNotFoundException JavaDoc, IOException
700     {
701         fontSearch = new FontKey(null, 0, 0);
702         fontTable = new Hashtable();
703         search = new SimpleAttributeSet JavaDoc();
704         attributesPool = Collections.
705         synchronizedMap(new WeakHashMap JavaDoc());
706         s.defaultReadObject();
707     }
708
709     // --- variables ---------------------------------------------------
710

711     /**
712      * The name given to the default logical style attached
713      * to paragraphs.
714      */

715     public static final String JavaDoc DEFAULT_STYLE = "default";
716
717     private static Hashtable freezeKeyMap;
718     private static Hashtable thawKeyMap;
719
720     private Style JavaDoc styles;
721     private transient FontKey fontSearch = new FontKey(null, 0, 0);
722     private transient Hashtable fontTable = new Hashtable();
723
724     private transient Map JavaDoc attributesPool = Collections.
725     synchronizedMap(new WeakHashMap JavaDoc());
726     private transient MutableAttributeSet JavaDoc search = new SimpleAttributeSet JavaDoc();
727
728     /**
729      * Number of immutable sets that are not currently
730      * being used. This helps indicate when the sets need
731      * to be cleaned out of the hashtable they are stored
732      * in.
733      */

734     private int unusedSets;
735
736     /**
737      * The threshold for no longer sharing the set of attributes
738      * in an immutable table.
739      */

740     static final int THRESHOLD = 9;
741     
742     /**
743      * This class holds a small number of attributes in an array.
744      * The storage format is key, value, key, value, etc. The size
745      * of the set is the length of the array divided by two. By
746      * default, this is the class that will be used to store attributes
747      * when held in the compact sharable form.
748      */

749     public class SmallAttributeSet implements AttributeSet JavaDoc {
750
751         public SmallAttributeSet(Object JavaDoc[] attributes) {
752             this.attributes = attributes;
753         updateResolveParent();
754         }
755
756         public SmallAttributeSet(AttributeSet JavaDoc attrs) {
757             int n = attrs.getAttributeCount();
758             Object JavaDoc[] tbl = new Object JavaDoc[2 * n];
759             Enumeration names = attrs.getAttributeNames();
760             int i = 0;
761             while (names.hasMoreElements()) {
762                 tbl[i] = names.nextElement();
763                 tbl[i+1] = attrs.getAttribute(tbl[i]);
764                 i += 2;
765             }
766             attributes = tbl;
767         updateResolveParent();
768         }
769
770     private void updateResolveParent() {
771         resolveParent = null;
772             Object JavaDoc[] tbl = attributes;
773             for (int i = 0; i < tbl.length; i += 2) {
774         if (tbl[i] == StyleConstants.ResolveAttribute) {
775             resolveParent = (AttributeSet JavaDoc)tbl[i + 1];
776             break;
777         }
778             }
779     }
780
781         Object JavaDoc getLocalAttribute(Object JavaDoc nm) {
782         if (nm == StyleConstants.ResolveAttribute) {
783         return resolveParent;
784         }
785             Object JavaDoc[] tbl = attributes;
786             for (int i = 0; i < tbl.length; i += 2) {
787                 if (nm.equals(tbl[i])) {
788                     return tbl[i+1];
789                 }
790             }
791             return null;
792         }
793
794         // --- Object methods -------------------------
795

796         /**
797          * Returns a string showing the key/value pairs
798          */

799         public String JavaDoc toString() {
800             String JavaDoc s = "{";
801             Object JavaDoc[] tbl = attributes;
802             for (int i = 0; i < tbl.length; i += 2) {
803                 if (tbl[i+1] instanceof AttributeSet JavaDoc) {
804                     // don't recurse
805
s = s + tbl[i] + "=" + "AttributeSet" + ",";
806                 } else {
807                     s = s + tbl[i] + "=" + tbl[i+1] + ",";
808                 }
809             }
810             s = s + "}";
811             return s;
812         }
813
814         /**
815          * Returns a hashcode for this set of attributes.
816          * @return a hashcode value for this set of attributes.
817          */

818         public int hashCode() {
819             int code = 0;
820             Object JavaDoc[] tbl = attributes;
821             for (int i = 1; i < tbl.length; i += 2) {
822                 code ^= tbl[i].hashCode();
823             }
824             return code;
825         }
826
827         /**
828          * Compares this object to the specifed object.
829          * The result is <code>true</code> if the object is an equivalent
830      * set of attributes.
831          * @param obj the object to compare with.
832          * @return <code>true</code> if the objects are equal;
833          * <code>false</code> otherwise.
834          */

835         public boolean equals(Object JavaDoc obj) {
836             if (obj instanceof AttributeSet JavaDoc) {
837                 AttributeSet JavaDoc attrs = (AttributeSet JavaDoc) obj;
838                 return ((getAttributeCount() == attrs.getAttributeCount()) &&
839                         containsAttributes(attrs));
840             }
841             return false;
842         }
843
844         /**
845          * Clones a set of attributes. Since the set is immutable, a
846          * clone is basically the same set.
847          *
848          * @return the set of attributes
849          */

850         public Object JavaDoc clone() {
851             return this;
852         }
853
854         // --- AttributeSet methods ----------------------------
855

856         /**
857          * Gets the number of attributes that are defined.
858          *
859          * @return the number of attributes
860          * @see AttributeSet#getAttributeCount
861          */

862         public int getAttributeCount() {
863             return attributes.length / 2;
864         }
865
866         /**
867          * Checks whether a given attribute is defined.
868          *
869          * @param key the attribute key
870          * @return true if the attribute is defined
871          * @see AttributeSet#isDefined
872          */

873         public boolean isDefined(Object JavaDoc key) {
874             Object JavaDoc[] a = attributes;
875             int n = a.length;
876             for (int i = 0; i < n; i += 2) {
877                 if (key.equals(a[i])) {
878                     return true;
879                 }
880             }
881             return false;
882         }
883
884         /**
885          * Checks whether two attribute sets are equal.
886          *
887          * @param attr the attribute set to check against
888          * @return true if the same
889          * @see AttributeSet#isEqual
890          */

891         public boolean isEqual(AttributeSet JavaDoc attr) {
892             if (attr instanceof SmallAttributeSet) {
893                 return attr == this;
894             }
895             return ((getAttributeCount() == attr.getAttributeCount()) &&
896                     containsAttributes(attr));
897         }
898
899         /**
900          * Copies a set of attributes.
901          *
902          * @return the copy
903          * @see AttributeSet#copyAttributes
904          */

905         public AttributeSet JavaDoc copyAttributes() {
906             return this;
907         }
908
909         /**
910          * Gets the value of an attribute.
911          *
912          * @param key the attribute name
913          * @return the attribute value
914          * @see AttributeSet#getAttribute
915          */

916         public Object JavaDoc getAttribute(Object JavaDoc key) {
917             Object JavaDoc value = getLocalAttribute(key);
918             if (value == null) {
919                 AttributeSet JavaDoc parent = getResolveParent();
920                 if (parent != null)
921                     value = parent.getAttribute(key);
922             }
923             return value;
924         }
925
926         /**
927          * Gets the names of all attributes.
928          *
929          * @return the attribute names
930          * @see AttributeSet#getAttributeNames
931          */

932         public Enumeration<?> getAttributeNames() {
933             return new KeyEnumeration(attributes);
934         }
935
936         /**
937          * Checks whether a given attribute name/value is defined.
938          *
939          * @param name the attribute name
940          * @param value the attribute value
941          * @return true if the name/value is defined
942          * @see AttributeSet#containsAttribute
943          */

944         public boolean containsAttribute(Object JavaDoc name, Object JavaDoc value) {
945             return value.equals(getAttribute(name));
946         }
947
948         /**
949          * Checks whether the attribute set contains all of
950          * the given attributes.
951          *
952          * @param attrs the attributes to check
953          * @return true if the element contains all the attributes
954          * @see AttributeSet#containsAttributes
955          */

956         public boolean containsAttributes(AttributeSet JavaDoc attrs) {
957             boolean result = true;
958
959             Enumeration names = attrs.getAttributeNames();
960             while (result && names.hasMoreElements()) {
961                 Object JavaDoc name = names.nextElement();
962                 result = attrs.getAttribute(name).equals(getAttribute(name));
963             }
964
965             return result;
966         }
967
968         /**
969          * If not overriden, the resolving parent defaults to
970          * the parent element.
971          *
972          * @return the attributes from the parent
973          * @see AttributeSet#getResolveParent
974          */

975         public AttributeSet JavaDoc getResolveParent() {
976             return resolveParent;
977         }
978
979         // --- variables -----------------------------------------
980

981         Object JavaDoc[] attributes;
982     // This is also stored in attributes
983
AttributeSet JavaDoc resolveParent;
984     }
985
986     /**
987      * An enumeration of the keys in a SmallAttributeSet.
988      */

989     class KeyEnumeration implements Enumeration<Object JavaDoc> {
990
991         KeyEnumeration(Object JavaDoc[] attr) {
992             this.attr = attr;
993             i = 0;
994         }
995
996         /**
997          * Tests if this enumeration contains more elements.
998          *
999          * @return <code>true</code> if this enumeration contains more elements;
1000         * <code>false</code> otherwise.
1001         * @since JDK1.0
1002         */

1003        public boolean hasMoreElements() {
1004            return i < attr.length;
1005        }
1006
1007        /**
1008         * Returns the next element of this enumeration.
1009         *
1010         * @return the next element of this enumeration.
1011         * @exception NoSuchElementException if no more elements exist.
1012         * @since JDK1.0
1013         */

1014        public Object JavaDoc nextElement() {
1015            if (i < attr.length) {
1016                Object JavaDoc o = attr[i];
1017                i += 2;
1018                return o;
1019            }
1020            throw new NoSuchElementException();
1021        }
1022
1023        Object JavaDoc[] attr;
1024        int i;
1025    }
1026
1027    /**
1028     * Sorts the key strings so that they can be very quickly compared
1029     * in the attribute set searchs.
1030     */

1031    class KeyBuilder {
1032
1033        public void initialize(AttributeSet JavaDoc a) {
1034            if (a instanceof SmallAttributeSet) {
1035                initialize(((SmallAttributeSet)a).attributes);
1036            } else {
1037                keys.removeAllElements();
1038                data.removeAllElements();
1039                Enumeration names = a.getAttributeNames();
1040                while (names.hasMoreElements()) {
1041                    Object JavaDoc name = names.nextElement();
1042                    addAttribute(name, a.getAttribute(name));
1043                }
1044            }
1045        }
1046
1047        /**
1048         * Initialize with a set of already sorted
1049         * keys (data from an existing SmallAttributeSet).
1050         */

1051        private void initialize(Object JavaDoc[] sorted) {
1052            keys.removeAllElements();
1053            data.removeAllElements();
1054            int n = sorted.length;
1055            for (int i = 0; i < n; i += 2) {
1056                keys.addElement(sorted[i]);
1057                data.addElement(sorted[i+1]);
1058            }
1059        }
1060
1061        /**
1062         * Creates a table of sorted key/value entries
1063         * suitable for creation of an instance of
1064         * SmallAttributeSet.
1065         */

1066        public Object JavaDoc[] createTable() {
1067            int n = keys.size();
1068            Object JavaDoc[] tbl = new Object JavaDoc[2 * n];
1069            for (int i = 0; i < n; i ++) {
1070                int offs = 2 * i;
1071                tbl[offs] = keys.elementAt(i);
1072                tbl[offs + 1] = data.elementAt(i);
1073            }
1074            return tbl;
1075        }
1076
1077        /**
1078         * The number of key/value pairs contained
1079         * in the current key being forged.
1080         */

1081        int getCount() {
1082            return keys.size();
1083        }
1084
1085        /**
1086         * Adds a key/value to the set.
1087         */

1088        public void addAttribute(Object JavaDoc key, Object JavaDoc value) {
1089            keys.addElement(key);
1090            data.addElement(value);
1091        }
1092
1093        /**
1094         * Adds a set of key/value pairs to the set.
1095         */

1096        public void addAttributes(AttributeSet JavaDoc attr) {
1097            if (attr instanceof SmallAttributeSet) {
1098                // avoid searching the keys, they are already interned.
1099
Object JavaDoc[] tbl = ((SmallAttributeSet)attr).attributes;
1100                int n = tbl.length;
1101                for (int i = 0; i < n; i += 2) {
1102                    addAttribute(tbl[i], tbl[i+1]);
1103                }
1104            } else {
1105                Enumeration names = attr.getAttributeNames();
1106                while (names.hasMoreElements()) {
1107                    Object JavaDoc name = names.nextElement();
1108                    addAttribute(name, attr.getAttribute(name));
1109                }
1110            }
1111        }
1112
1113        /**
1114         * Removes the given name from the set.
1115         */

1116        public void removeAttribute(Object JavaDoc key) {
1117            int n = keys.size();
1118            for (int i = 0; i < n; i++) {
1119                if (keys.elementAt(i).equals(key)) {
1120                    keys.removeElementAt(i);
1121                    data.removeElementAt(i);
1122                    return;
1123                }
1124            }
1125        }
1126
1127        /**
1128         * Removes the set of keys from the set.
1129         */

1130        public void removeAttributes(Enumeration names) {
1131            while (names.hasMoreElements()) {
1132                Object JavaDoc name = names.nextElement();
1133                removeAttribute(name);
1134            }
1135        }
1136
1137        /**
1138         * Removes the set of matching attributes from the set.
1139         */

1140        public void removeAttributes(AttributeSet JavaDoc attr) {
1141            Enumeration names = attr.getAttributeNames();
1142            while (names.hasMoreElements()) {
1143                Object JavaDoc name = names.nextElement();
1144                Object JavaDoc value = attr.getAttribute(name);
1145                removeSearchAttribute(name, value);
1146            }
1147        }
1148
1149        private void removeSearchAttribute(Object JavaDoc ikey, Object JavaDoc value) {
1150            int n = keys.size();
1151            for (int i = 0; i < n; i++) {
1152                if (keys.elementAt(i).equals(ikey)) {
1153                    if (data.elementAt(i).equals(value)) {
1154                        keys.removeElementAt(i);
1155                        data.removeElementAt(i);
1156                    }
1157                    return;
1158                }
1159            }
1160        }
1161
1162        private Vector keys = new Vector();
1163        private Vector data = new Vector();
1164    }
1165
1166    /**
1167     * key for a font table
1168     */

1169    static class FontKey {
1170
1171        private String JavaDoc family;
1172        private int style;
1173        private int size;
1174
1175        /**
1176         * Constructs a font key.
1177         */

1178        public FontKey(String JavaDoc family, int style, int size) {
1179            setValue(family, style, size);
1180        }
1181
1182        public void setValue(String JavaDoc family, int style, int size) {
1183            this.family = (family != null) ? family.intern() : null;
1184            this.style = style;
1185            this.size = size;
1186        }
1187
1188        /**
1189         * Returns a hashcode for this font.
1190         * @return a hashcode value for this font.
1191         */

1192        public int hashCode() {
1193        int fhash = (family != null) ? family.hashCode() : 0;
1194            return fhash ^ style ^ size;
1195        }
1196    
1197        /**
1198         * Compares this object to the specifed object.
1199         * The result is <code>true</code> if and only if the argument is not
1200         * <code>null</code> and is a <code>Font</code> object with the same
1201         * name, style, and point size as this font.
1202         * @param obj the object to compare this font with.
1203         * @return <code>true</code> if the objects are equal;
1204         * <code>false</code> otherwise.
1205         */

1206        public boolean equals(Object JavaDoc obj) {
1207            if (obj instanceof FontKey) {
1208                FontKey font = (FontKey)obj;
1209                return (size == font.size) && (style == font.style) && (family == font.family);
1210            }
1211            return false;
1212        }
1213
1214    }
1215
1216    /**
1217     * A collection of attributes, typically used to represent
1218     * character and paragraph styles. This is an implementation
1219     * of MutableAttributeSet that can be observed if desired.
1220     * These styles will take advantage of immutability while
1221     * the sets are small enough, and may be substantially more
1222     * efficient than something like SimpleAttributeSet.
1223     * <p>
1224     * <strong>Warning:</strong>
1225     * Serialized objects of this class will not be compatible with
1226     * future Swing releases. The current serialization support is
1227     * appropriate for short term storage or RMI between applications running
1228     * the same version of Swing. As of 1.4, support for long term storage
1229     * of all JavaBeans<sup><font size="-2">TM</font></sup>
1230     * has been added to the <code>java.beans</code> package.
1231     * Please see {@link java.beans.XMLEncoder}.
1232     */

1233    public class NamedStyle implements Style JavaDoc, Serializable {
1234
1235        /**
1236         * Creates a new named style.
1237         *
1238         * @param name the style name, null for unnamed
1239         * @param parent the parent style, null if none
1240         */

1241        public NamedStyle(String JavaDoc name, Style JavaDoc parent) {
1242            attributes = getEmptySet();
1243            if (name != null) {
1244                setName(name);
1245            }
1246            if (parent != null) {
1247                setResolveParent(parent);
1248            }
1249        }
1250
1251        /**
1252         * Creates a new named style.
1253         *
1254         * @param parent the parent style, null if none
1255         */

1256        public NamedStyle(Style JavaDoc parent) {
1257            this(null, parent);
1258        }
1259
1260        /**
1261         * Creates a new named style, with a null name and parent.
1262         */

1263        public NamedStyle() {
1264            attributes = getEmptySet();
1265        }
1266
1267        /**
1268         * Converts the style to a string.
1269         *
1270         * @return the string
1271         */

1272        public String JavaDoc toString() {
1273            return "NamedStyle:" + getName() + " " + attributes;
1274        }
1275
1276        /**
1277         * Fetches the name of the style. A style is not required to be named,
1278         * so null is returned if there is no name associated with the style.
1279         *
1280         * @return the name
1281         */

1282        public String JavaDoc getName() {
1283            if (isDefined(StyleConstants.NameAttribute)) {
1284                return getAttribute(StyleConstants.NameAttribute).toString();
1285            }
1286            return null;
1287        }
1288
1289        /**
1290         * Changes the name of the style. Does nothing with a null name.
1291         *
1292         * @param name the new name
1293         */

1294        public void setName(String JavaDoc name) {
1295            if (name != null) {
1296                this.addAttribute(StyleConstants.NameAttribute, name);
1297            }
1298        }
1299
1300        /**
1301         * Adds a change listener.
1302         *
1303         * @param l the change listener
1304         */

1305        public void addChangeListener(ChangeListener JavaDoc l) {
1306            listenerList.add(ChangeListener JavaDoc.class, l);
1307        }
1308
1309        /**
1310         * Removes a change listener.
1311         *
1312         * @param l the change listener
1313         */

1314        public void removeChangeListener(ChangeListener JavaDoc l) {
1315            listenerList.remove(ChangeListener JavaDoc.class, l);
1316        }
1317
1318
1319        /**
1320         * Returns an array of all the <code>ChangeListener</code>s added
1321         * to this NamedStyle with addChangeListener().
1322         *
1323         * @return all of the <code>ChangeListener</code>s added or an empty
1324         * array if no listeners have been added
1325         * @since 1.4
1326         */

1327        public ChangeListener JavaDoc[] getChangeListeners() {
1328            return (ChangeListener JavaDoc[])listenerList.getListeners(
1329                    ChangeListener JavaDoc.class);
1330        }
1331
1332
1333        /**
1334         * Notifies all listeners that have registered interest for
1335         * notification on this event type. The event instance
1336         * is lazily created using the parameters passed into
1337         * the fire method.
1338         *
1339         * @see EventListenerList
1340         */

1341        protected void fireStateChanged() {
1342            // Guaranteed to return a non-null array
1343
Object JavaDoc[] listeners = listenerList.getListenerList();
1344            // Process the listeners last to first, notifying
1345
// those that are interested in this event
1346
for (int i = listeners.length-2; i>=0; i-=2) {
1347                if (listeners[i]==ChangeListener JavaDoc.class) {
1348                    // Lazily create the event:
1349
if (changeEvent == null)
1350                        changeEvent = new ChangeEvent JavaDoc(this);
1351                    ((ChangeListener JavaDoc)listeners[i+1]).stateChanged(changeEvent);
1352                }
1353            }
1354        }
1355
1356    /**
1357     * Return an array of all the listeners of the given type that
1358     * were added to this model.
1359     *
1360     * @return all of the objects receiving <em>listenerType</em> notifications
1361     * from this model
1362     *
1363     * @since 1.3
1364     */

1365    public <T extends EventListener> T[] getListeners(Class JavaDoc<T> listenerType) {
1366        return listenerList.getListeners(listenerType);
1367    }
1368        
1369        // --- AttributeSet ----------------------------
1370
// delegated to the immutable field "attributes"
1371

1372        /**
1373         * Gets the number of attributes that are defined.
1374         *
1375         * @return the number of attributes >= 0
1376         * @see AttributeSet#getAttributeCount
1377         */

1378        public int getAttributeCount() {
1379            return attributes.getAttributeCount();
1380        }
1381
1382        /**
1383         * Checks whether a given attribute is defined.
1384         *
1385         * @param attrName the non-null attribute name
1386         * @return true if the attribute is defined
1387         * @see AttributeSet#isDefined
1388         */

1389        public boolean isDefined(Object JavaDoc attrName) {
1390            return attributes.isDefined(attrName);
1391        }
1392
1393        /**
1394         * Checks whether two attribute sets are equal.
1395         *
1396         * @param attr the attribute set to check against
1397         * @return true if the same
1398         * @see AttributeSet#isEqual
1399         */

1400        public boolean isEqual(AttributeSet JavaDoc attr) {
1401            return attributes.isEqual(attr);
1402        }
1403
1404        /**
1405         * Copies a set of attributes.
1406         *
1407         * @return the copy
1408         * @see AttributeSet#copyAttributes
1409         */

1410        public AttributeSet JavaDoc copyAttributes() {
1411            NamedStyle a = new NamedStyle();
1412            a.attributes = attributes.copyAttributes();
1413            return a;
1414        }
1415
1416        /**
1417         * Gets the value of an attribute.
1418         *
1419         * @param attrName the non-null attribute name
1420         * @return the attribute value
1421         * @see AttributeSet#getAttribute
1422         */

1423        public Object JavaDoc getAttribute(Object JavaDoc attrName) {
1424            return attributes.getAttribute(attrName);
1425        }
1426
1427        /**
1428         * Gets the names of all attributes.
1429         *
1430         * @return the attribute names as an enumeration
1431         * @see AttributeSet#getAttributeNames
1432         */

1433        public Enumeration<?> getAttributeNames() {
1434            return attributes.getAttributeNames();
1435        }
1436
1437        /**
1438         * Checks whether a given attribute name/value is defined.
1439         *
1440         * @param name the non-null attribute name
1441         * @param value the attribute value
1442         * @return true if the name/value is defined
1443         * @see AttributeSet#containsAttribute
1444         */

1445        public boolean containsAttribute(Object JavaDoc name, Object JavaDoc value) {
1446            return attributes.containsAttribute(name, value);
1447        }
1448
1449
1450        /**
1451         * Checks whether the element contains all the attributes.
1452         *
1453         * @param attrs the attributes to check
1454         * @return true if the element contains all the attributes
1455         * @see AttributeSet#containsAttributes
1456         */

1457        public boolean containsAttributes(AttributeSet JavaDoc attrs) {
1458            return attributes.containsAttributes(attrs);
1459        }
1460
1461        /**
1462         * Gets attributes from the parent.
1463         * If not overriden, the resolving parent defaults to
1464         * the parent element.
1465         *
1466         * @return the attributes from the parent
1467         * @see AttributeSet#getResolveParent
1468         */

1469        public AttributeSet JavaDoc getResolveParent() {
1470            return attributes.getResolveParent();
1471        }
1472
1473        // --- MutableAttributeSet ----------------------------------
1474
// should fetch a new immutable record for the field
1475
// "attributes".
1476

1477        /**
1478         * Adds an attribute.
1479         *
1480         * @param name the non-null attribute name
1481         * @param value the attribute value
1482         * @see MutableAttributeSet#addAttribute
1483         */

1484        public void addAttribute(Object JavaDoc name, Object JavaDoc value) {
1485            StyleContext JavaDoc context = StyleContext.this;
1486            attributes = context.addAttribute(attributes, name, value);
1487            fireStateChanged();
1488        }
1489
1490        /**
1491         * Adds a set of attributes to the element.
1492         *
1493         * @param attr the attributes to add
1494         * @see MutableAttributeSet#addAttribute
1495         */

1496        public void addAttributes(AttributeSet JavaDoc attr) {
1497            StyleContext JavaDoc context = StyleContext.this;
1498            attributes = context.addAttributes(attributes, attr);
1499            fireStateChanged();
1500        }
1501
1502        /**
1503         * Removes an attribute from the set.
1504         *
1505         * @param name the non-null attribute name
1506         * @see MutableAttributeSet#removeAttribute
1507         */

1508        public void removeAttribute(Object JavaDoc name) {
1509            StyleContext JavaDoc context = StyleContext.this;
1510            attributes = context.removeAttribute(attributes, name);
1511            fireStateChanged();
1512        }
1513
1514        /**
1515         * Removes a set of attributes for the element.
1516         *
1517         * @param names the attribute names
1518         * @see MutableAttributeSet#removeAttributes
1519         */

1520        public void removeAttributes(Enumeration<?> names) {
1521            StyleContext JavaDoc context = StyleContext.this;
1522            attributes = context.removeAttributes(attributes, names);
1523            fireStateChanged();
1524        }
1525
1526        /**
1527         * Removes a set of attributes for the element.
1528         *
1529         * @param attrs the attributes
1530         * @see MutableAttributeSet#removeAttributes
1531         */

1532        public void removeAttributes(AttributeSet JavaDoc attrs) {
1533            StyleContext JavaDoc context = StyleContext.this;
1534            if (attrs == this) {
1535                attributes = context.getEmptySet();
1536            } else {
1537                attributes = context.removeAttributes(attributes, attrs);
1538            }
1539            fireStateChanged();
1540        }
1541
1542        /**
1543         * Sets the resolving parent.
1544         *
1545         * @param parent the parent, null if none
1546         * @see MutableAttributeSet#setResolveParent
1547         */

1548        public void setResolveParent(AttributeSet JavaDoc parent) {
1549            if (parent != null) {
1550                addAttribute(StyleConstants.ResolveAttribute, parent);
1551            } else {
1552                removeAttribute(StyleConstants.ResolveAttribute);
1553            }
1554        }
1555
1556        // --- serialization ---------------------------------------------
1557

1558        private void writeObject(ObjectOutputStream s) throws IOException {
1559            s.defaultWriteObject();
1560            writeAttributeSet(s, attributes);
1561        }
1562
1563        private void readObject(ObjectInputStream s)
1564            throws ClassNotFoundException JavaDoc, IOException
1565        {
1566            s.defaultReadObject();
1567            attributes = SimpleAttributeSet.EMPTY;
1568            readAttributeSet(s, this);
1569        }
1570
1571        // --- member variables -----------------------------------------------
1572

1573        /**
1574         * The change listeners for the model.
1575         */

1576        protected EventListenerList JavaDoc listenerList = new EventListenerList JavaDoc();
1577
1578        /**
1579         * Only one ChangeEvent is needed per model instance since the
1580         * event's only (read-only) state is the source property. The source
1581         * of events generated here is always "this".
1582         */

1583        protected transient ChangeEvent JavaDoc changeEvent = null;
1584
1585        /**
1586         * Inner AttributeSet implementation, which may be an
1587         * immutable unique set being shared.
1588         */

1589        private transient AttributeSet JavaDoc attributes;
1590
1591    }
1592
1593    static {
1594    // initialize the static key registry with the StyleConstants keys
1595
try {
1596        int n = StyleConstants.keys.length;
1597            for (int i = 0; i < n; i++) {
1598                StyleContext.registerStaticAttributeKey(StyleConstants.keys[i]);
1599            }
1600        } catch (Throwable JavaDoc e) {
1601            e.printStackTrace();
1602        }
1603    }
1604
1605
1606}
1607
Popular Tags