40 /**
41 * A pool of styles and their associated resources. This class determines
42 * the lifetime of a group of resources by being a container that holds
43 * caches for various resources such as font and color that get reused
44 * by the various style definitions. This can be shared by multiple
45 * documents if desired to maximize the sharing of related resources.
46 * <p>
47 * This class also provides efficient support for small sets of attributes
48 * and compresses them by sharing across uses and taking advantage of
49 * their immutable nature. Since many styles are replicated, the potential
50 * for sharing is significant, and copies can be extremely cheap.
51 * Larger sets reduce the possibility of sharing, and therefore revert
52 * automatically to a less space-efficient implementation.
53 * <p>
54 * <strong>Warning:</strong>
55 * Serialized objects of this class will not be compatible with
56 * future Swing releases. The current serialization support is
57 * appropriate for short term storage or RMI between applications running
58 * the same version of Swing. As of 1.4, support for long term storage
59 * of all JavaBeans™
60 * has been added to the <code>java.beans</code> package.
61 * Please see {@link java.beans.XMLEncoder}.
62 *
63 * @author Timothy Prinzing
64 */
65 @SuppressWarnings("serial") // Same-version serialization only
66 public class StyleContext implements Serializable, AbstractDocument.AttributeContext {
67
68 /**
69 * Returns default AttributeContext shared by all documents that
70 * don't bother to define/supply their own context.
71 *
72 * @return the context
73 */
74 public static final StyleContext getDefaultStyleContext() {
75 if (defaultContext == null) {
76 defaultContext = new StyleContext();
77 }
78 return defaultContext;
79 }
80
145 * Adds a listener to track when styles are added
146 * or removed.
147 *
148 * @param l the change listener
149 */
150 public void addChangeListener(ChangeListener l) {
151 styles.addChangeListener(l);
152 }
153
154 /**
155 * Removes a listener that was tracking styles being
156 * added or removed.
157 *
158 * @param l the change listener
159 */
160 public void removeChangeListener(ChangeListener l) {
161 styles.removeChangeListener(l);
162 }
163
164 /**
165 * Returns an array of all the <code>ChangeListener</code>s added
166 * to this StyleContext with addChangeListener().
167 *
168 * @return all of the <code>ChangeListener</code>s added or an empty
169 * array if no listeners have been added
170 * @since 1.4
171 */
172 public ChangeListener[] getChangeListeners() {
173 return ((NamedStyle)styles).getChangeListeners();
174 }
175
176 /**
177 * Gets the font from an attribute set. This is
178 * implemented to try and fetch a cached font
179 * for the given AttributeSet, and if that fails
180 * the font features are resolved and the
181 * font is fetched from the low-level font cache.
182 *
183 * @param attr the attribute set
184 * @return the font
185 */
186 public Font getFont(AttributeSet attr) {
187 // PENDING(prinz) add cache behavior
188 int style = Font.PLAIN;
572 /**
573 * Context-specific handling of reading in attributes
574 * @param in the object stream to read the attribute data from.
575 * @param a the attribute set to place the attribute
576 * definitions in.
577 * @exception ClassNotFoundException passed upward if encountered
578 * when reading the object stream.
579 * @exception IOException passed upward if encountered when
580 * reading the object stream.
581 */
582 public void readAttributes(ObjectInputStream in,
583 MutableAttributeSet a) throws ClassNotFoundException, IOException {
584 readAttributeSet(in, a);
585 }
586
587 /**
588 * Writes a set of attributes to the given object stream
589 * for the purpose of serialization. This will take
590 * special care to deal with static attribute keys that
591 * have been registered wit the
592 * <code>registerStaticAttributeKey</code> method.
593 * Any attribute key not registered as a static key
594 * will be serialized directly. All values are expected
595 * to be serializable.
596 *
597 * @param out the output stream
598 * @param a the attribute set
599 * @exception IOException on any I/O error
600 */
601 public static void writeAttributeSet(ObjectOutputStream out,
602 AttributeSet a) throws IOException {
603 int n = a.getAttributeCount();
604 out.writeInt(n);
605 Enumeration<?> keys = a.getAttributeNames();
606 while (keys.hasMoreElements()) {
607 Object key = keys.nextElement();
608 if (key instanceof Serializable) {
609 out.writeObject(key);
610 } else {
611 Object ioFmt = freezeKeyMap.get(key);
612 if (ioFmt == null) {
615 }
616 out.writeObject(ioFmt);
617 }
618 Object value = a.getAttribute(key);
619 Object ioFmt = freezeKeyMap.get(value);
620 if (value instanceof Serializable) {
621 out.writeObject((ioFmt != null) ? ioFmt : value);
622 } else {
623 if (ioFmt == null) {
624 throw new NotSerializableException(value.getClass().
625 getName() + " is not serializable as a value in an AttributeSet");
626 }
627 out.writeObject(ioFmt);
628 }
629 }
630 }
631
632 /**
633 * Reads a set of attributes from the given object input
634 * stream that have been previously written out with
635 * <code>writeAttributeSet</code>. This will try to restore
636 * keys that were static objects to the static objects in
637 * the current virtual machine considering only those keys
638 * that have been registered with the
639 * <code>registerStaticAttributeKey</code> method.
640 * The attributes retrieved from the stream will be placed
641 * into the given mutable set.
642 *
643 * @param in the object stream to read the attribute data from.
644 * @param a the attribute set to place the attribute
645 * definitions in.
646 * @exception ClassNotFoundException passed upward if encountered
647 * when reading the object stream.
648 * @exception IOException passed upward if encountered when
649 * reading the object stream.
650 */
651 public static void readAttributeSet(ObjectInputStream in,
652 MutableAttributeSet a) throws ClassNotFoundException, IOException {
653
654 int n = in.readInt();
655 for (int i = 0; i < n; i++) {
656 Object key = in.readObject();
657 Object value = in.readObject();
658 if (thawKeyMap != null) {
659 Object staticKey = thawKeyMap.get(key);
660 if (staticKey != null) {
661 key = staticKey;
662 }
663 Object staticValue = thawKeyMap.get(value);
664 if (staticValue != null) {
665 value = staticValue;
666 }
667 }
668 a.addAttribute(key, value);
669 }
670 }
671
672 /**
673 * Registers an object as a static object that is being
674 * used as a key in attribute sets. This allows the key
675 * to be treated specially for serialization.
676 * <p>
677 * For operation under a 1.1 virtual machine, this
678 * uses the value returned by <code>toString</code>
679 * concatenated to the classname. The value returned
680 * by toString should not have the class reference
681 * in it (ie it should be reimplemented from the
682 * definition in Object) in order to be the same when
683 * recomputed later.
684 *
685 * @param key the non-null object key
686 */
687 public static void registerStaticAttributeKey(Object key) {
688 String ioFmt = key.getClass().getName() + "." + key.toString();
689 if (freezeKeyMap == null) {
690 freezeKeyMap = new Hashtable<Object, String>();
691 thawKeyMap = new Hashtable<String, Object>();
692 }
693 freezeKeyMap.put(key, ioFmt);
694 thawKeyMap.put(ioFmt, key);
695 }
696
697 /**
698 * Returns the object previously registered with
699 * <code>registerStaticAttributeKey</code>.
700 * @param key the object key
701 * @return Returns the object previously registered with
702 * {@code registerStaticAttributeKey}
703 */
704 public static Object getStaticAttribute(Object key) {
705 if (thawKeyMap == null || key == null) {
706 return null;
707 }
708 return thawKeyMap.get(key);
709 }
710
711 /**
712 * Returns the String that <code>key</code> will be registered with.
713 * @see #getStaticAttribute
714 * @see #registerStaticAttributeKey
715 * @param key the object key
716 * @return the String that {@code key} will be registered with
717 */
718 public static Object getStaticAttributeKey(Object key) {
719 return key.getClass().getName() + "." + key.toString();
720 }
721
722 private void writeObject(java.io.ObjectOutputStream s)
723 throws IOException
724 {
725 // clean out unused sets before saving
726 removeUnusedSets();
727
728 s.defaultWriteObject();
729 }
730
731 private void readObject(ObjectInputStream s)
732 throws ClassNotFoundException, IOException
859 }
860 s = s + "}";
861 return s;
862 }
863
864 /**
865 * Returns a hashcode for this set of attributes.
866 * @return a hashcode value for this set of attributes.
867 */
868 public int hashCode() {
869 int code = 0;
870 Object[] tbl = attributes;
871 for (int i = 1; i < tbl.length; i += 2) {
872 code ^= tbl[i].hashCode();
873 }
874 return code;
875 }
876
877 /**
878 * Compares this object to the specified object.
879 * The result is <code>true</code> if the object is an equivalent
880 * set of attributes.
881 * @param obj the object to compare with.
882 * @return <code>true</code> if the objects are equal;
883 * <code>false</code> otherwise.
884 */
885 public boolean equals(Object obj) {
886 if (obj instanceof AttributeSet) {
887 AttributeSet attrs = (AttributeSet) obj;
888 return ((getAttributeCount() == attrs.getAttributeCount()) &&
889 containsAttributes(attrs));
890 }
891 return false;
892 }
893
894 /**
895 * Clones a set of attributes. Since the set is immutable, a
896 * clone is basically the same set.
897 *
898 * @return the set of attributes
899 */
900 public Object clone() {
901 return this;
902 }
903
1029 // --- variables -----------------------------------------
1030
1031 Object[] attributes;
1032 // This is also stored in attributes
1033 AttributeSet resolveParent;
1034 }
1035
1036 /**
1037 * An enumeration of the keys in a SmallAttributeSet.
1038 */
1039 class KeyEnumeration implements Enumeration<Object> {
1040
1041 KeyEnumeration(Object[] attr) {
1042 this.attr = attr;
1043 i = 0;
1044 }
1045
1046 /**
1047 * Tests if this enumeration contains more elements.
1048 *
1049 * @return <code>true</code> if this enumeration contains more elements;
1050 * <code>false</code> otherwise.
1051 * @since 1.0
1052 */
1053 public boolean hasMoreElements() {
1054 return i < attr.length;
1055 }
1056
1057 /**
1058 * Returns the next element of this enumeration.
1059 *
1060 * @return the next element of this enumeration.
1061 * @exception NoSuchElementException if no more elements exist.
1062 * @since 1.0
1063 */
1064 public Object nextElement() {
1065 if (i < attr.length) {
1066 Object o = attr[i];
1067 i += 2;
1068 return o;
1069 }
1070 throw new NoSuchElementException();
1229 setValue(family, style, size);
1230 }
1231
1232 public void setValue(String family, int style, int size) {
1233 this.family = (family != null) ? family.intern() : null;
1234 this.style = style;
1235 this.size = size;
1236 }
1237
1238 /**
1239 * Returns a hashcode for this font.
1240 * @return a hashcode value for this font.
1241 */
1242 public int hashCode() {
1243 int fhash = (family != null) ? family.hashCode() : 0;
1244 return fhash ^ style ^ size;
1245 }
1246
1247 /**
1248 * Compares this object to the specified object.
1249 * The result is <code>true</code> if and only if the argument is not
1250 * <code>null</code> and is a <code>Font</code> object with the same
1251 * name, style, and point size as this font.
1252 * @param obj the object to compare this font with.
1253 * @return <code>true</code> if the objects are equal;
1254 * <code>false</code> otherwise.
1255 */
1256 public boolean equals(Object obj) {
1257 if (obj instanceof FontKey) {
1258 FontKey font = (FontKey)obj;
1259 return (size == font.size) && (style == font.style) && (family == font.family);
1260 }
1261 return false;
1262 }
1263
1264 }
1265
1266 /**
1267 * A collection of attributes, typically used to represent
1268 * character and paragraph styles. This is an implementation
1269 * of MutableAttributeSet that can be observed if desired.
1270 * These styles will take advantage of immutability while
1271 * the sets are small enough, and may be substantially more
1272 * efficient than something like SimpleAttributeSet.
1273 * <p>
1274 * <strong>Warning:</strong>
1275 * Serialized objects of this class will not be compatible with
1276 * future Swing releases. The current serialization support is
1277 * appropriate for short term storage or RMI between applications running
1278 * the same version of Swing. As of 1.4, support for long term storage
1279 * of all JavaBeans™
1280 * has been added to the <code>java.beans</code> package.
1281 * Please see {@link java.beans.XMLEncoder}.
1282 */
1283 @SuppressWarnings("serial") // Same-version serialization only
1284 public class NamedStyle implements Style, Serializable {
1285
1286 /**
1287 * Creates a new named style.
1288 *
1289 * @param name the style name, null for unnamed
1290 * @param parent the parent style, null if none
1291 * @since 1.4
1292 */
1293 public NamedStyle(String name, Style parent) {
1294 attributes = getEmptySet();
1295 if (name != null) {
1296 setName(name);
1297 }
1298 if (parent != null) {
1299 setResolveParent(parent);
1300 }
1353 /**
1354 * Adds a change listener.
1355 *
1356 * @param l the change listener
1357 */
1358 public void addChangeListener(ChangeListener l) {
1359 listenerList.add(ChangeListener.class, l);
1360 }
1361
1362 /**
1363 * Removes a change listener.
1364 *
1365 * @param l the change listener
1366 */
1367 public void removeChangeListener(ChangeListener l) {
1368 listenerList.remove(ChangeListener.class, l);
1369 }
1370
1371
1372 /**
1373 * Returns an array of all the <code>ChangeListener</code>s added
1374 * to this NamedStyle with addChangeListener().
1375 *
1376 * @return all of the <code>ChangeListener</code>s added or an empty
1377 * array if no listeners have been added
1378 * @since 1.4
1379 */
1380 public ChangeListener[] getChangeListeners() {
1381 return listenerList.getListeners(ChangeListener.class);
1382 }
1383
1384
1385 /**
1386 * Notifies all listeners that have registered interest for
1387 * notification on this event type. The event instance
1388 * is lazily created using the parameters passed into
1389 * the fire method.
1390 *
1391 * @see EventListenerList
1392 */
1393 protected void fireStateChanged() {
1394 // Guaranteed to return a non-null array
1395 Object[] listeners = listenerList.getListenerList();
1396 // Process the listeners last to first, notifying
|
40 /**
41 * A pool of styles and their associated resources. This class determines
42 * the lifetime of a group of resources by being a container that holds
43 * caches for various resources such as font and color that get reused
44 * by the various style definitions. This can be shared by multiple
45 * documents if desired to maximize the sharing of related resources.
46 * <p>
47 * This class also provides efficient support for small sets of attributes
48 * and compresses them by sharing across uses and taking advantage of
49 * their immutable nature. Since many styles are replicated, the potential
50 * for sharing is significant, and copies can be extremely cheap.
51 * Larger sets reduce the possibility of sharing, and therefore revert
52 * automatically to a less space-efficient implementation.
53 * <p>
54 * <strong>Warning:</strong>
55 * Serialized objects of this class will not be compatible with
56 * future Swing releases. The current serialization support is
57 * appropriate for short term storage or RMI between applications running
58 * the same version of Swing. As of 1.4, support for long term storage
59 * of all JavaBeans™
60 * has been added to the {@code java.beans} package.
61 * Please see {@link java.beans.XMLEncoder}.
62 *
63 * @author Timothy Prinzing
64 */
65 @SuppressWarnings("serial") // Same-version serialization only
66 public class StyleContext implements Serializable, AbstractDocument.AttributeContext {
67
68 /**
69 * Returns default AttributeContext shared by all documents that
70 * don't bother to define/supply their own context.
71 *
72 * @return the context
73 */
74 public static final StyleContext getDefaultStyleContext() {
75 if (defaultContext == null) {
76 defaultContext = new StyleContext();
77 }
78 return defaultContext;
79 }
80
145 * Adds a listener to track when styles are added
146 * or removed.
147 *
148 * @param l the change listener
149 */
150 public void addChangeListener(ChangeListener l) {
151 styles.addChangeListener(l);
152 }
153
154 /**
155 * Removes a listener that was tracking styles being
156 * added or removed.
157 *
158 * @param l the change listener
159 */
160 public void removeChangeListener(ChangeListener l) {
161 styles.removeChangeListener(l);
162 }
163
164 /**
165 * Returns an array of all the {@code ChangeListener}s added
166 * to this StyleContext with addChangeListener().
167 *
168 * @return all of the {@code ChangeListener}s added or an empty
169 * array if no listeners have been added
170 * @since 1.4
171 */
172 public ChangeListener[] getChangeListeners() {
173 return ((NamedStyle)styles).getChangeListeners();
174 }
175
176 /**
177 * Gets the font from an attribute set. This is
178 * implemented to try and fetch a cached font
179 * for the given AttributeSet, and if that fails
180 * the font features are resolved and the
181 * font is fetched from the low-level font cache.
182 *
183 * @param attr the attribute set
184 * @return the font
185 */
186 public Font getFont(AttributeSet attr) {
187 // PENDING(prinz) add cache behavior
188 int style = Font.PLAIN;
572 /**
573 * Context-specific handling of reading in attributes
574 * @param in the object stream to read the attribute data from.
575 * @param a the attribute set to place the attribute
576 * definitions in.
577 * @exception ClassNotFoundException passed upward if encountered
578 * when reading the object stream.
579 * @exception IOException passed upward if encountered when
580 * reading the object stream.
581 */
582 public void readAttributes(ObjectInputStream in,
583 MutableAttributeSet a) throws ClassNotFoundException, IOException {
584 readAttributeSet(in, a);
585 }
586
587 /**
588 * Writes a set of attributes to the given object stream
589 * for the purpose of serialization. This will take
590 * special care to deal with static attribute keys that
591 * have been registered wit the
592 * {@code registerStaticAttributeKey} method.
593 * Any attribute key not registered as a static key
594 * will be serialized directly. All values are expected
595 * to be serializable.
596 *
597 * @param out the output stream
598 * @param a the attribute set
599 * @exception IOException on any I/O error
600 */
601 public static void writeAttributeSet(ObjectOutputStream out,
602 AttributeSet a) throws IOException {
603 int n = a.getAttributeCount();
604 out.writeInt(n);
605 Enumeration<?> keys = a.getAttributeNames();
606 while (keys.hasMoreElements()) {
607 Object key = keys.nextElement();
608 if (key instanceof Serializable) {
609 out.writeObject(key);
610 } else {
611 Object ioFmt = freezeKeyMap.get(key);
612 if (ioFmt == null) {
615 }
616 out.writeObject(ioFmt);
617 }
618 Object value = a.getAttribute(key);
619 Object ioFmt = freezeKeyMap.get(value);
620 if (value instanceof Serializable) {
621 out.writeObject((ioFmt != null) ? ioFmt : value);
622 } else {
623 if (ioFmt == null) {
624 throw new NotSerializableException(value.getClass().
625 getName() + " is not serializable as a value in an AttributeSet");
626 }
627 out.writeObject(ioFmt);
628 }
629 }
630 }
631
632 /**
633 * Reads a set of attributes from the given object input
634 * stream that have been previously written out with
635 * {@code writeAttributeSet}. This will try to restore
636 * keys that were static objects to the static objects in
637 * the current virtual machine considering only those keys
638 * that have been registered with the
639 * {@code registerStaticAttributeKey} method.
640 * The attributes retrieved from the stream will be placed
641 * into the given mutable set.
642 *
643 * @param in the object stream to read the attribute data from.
644 * @param a the attribute set to place the attribute
645 * definitions in.
646 * @exception ClassNotFoundException passed upward if encountered
647 * when reading the object stream.
648 * @exception IOException passed upward if encountered when
649 * reading the object stream.
650 */
651 public static void readAttributeSet(ObjectInputStream in,
652 MutableAttributeSet a) throws ClassNotFoundException, IOException {
653
654 int n = in.readInt();
655 for (int i = 0; i < n; i++) {
656 Object key = in.readObject();
657 Object value = in.readObject();
658 if (thawKeyMap != null) {
659 Object staticKey = thawKeyMap.get(key);
660 if (staticKey != null) {
661 key = staticKey;
662 }
663 Object staticValue = thawKeyMap.get(value);
664 if (staticValue != null) {
665 value = staticValue;
666 }
667 }
668 a.addAttribute(key, value);
669 }
670 }
671
672 /**
673 * Registers an object as a static object that is being
674 * used as a key in attribute sets. This allows the key
675 * to be treated specially for serialization.
676 * <p>
677 * For operation under a 1.1 virtual machine, this
678 * uses the value returned by {@code toString}
679 * concatenated to the classname. The value returned
680 * by toString should not have the class reference
681 * in it (ie it should be reimplemented from the
682 * definition in Object) in order to be the same when
683 * recomputed later.
684 *
685 * @param key the non-null object key
686 */
687 public static void registerStaticAttributeKey(Object key) {
688 String ioFmt = key.getClass().getName() + "." + key.toString();
689 if (freezeKeyMap == null) {
690 freezeKeyMap = new Hashtable<Object, String>();
691 thawKeyMap = new Hashtable<String, Object>();
692 }
693 freezeKeyMap.put(key, ioFmt);
694 thawKeyMap.put(ioFmt, key);
695 }
696
697 /**
698 * Returns the object previously registered with
699 * {@code registerStaticAttributeKey}.
700 * @param key the object key
701 * @return Returns the object previously registered with
702 * {@code registerStaticAttributeKey}
703 */
704 public static Object getStaticAttribute(Object key) {
705 if (thawKeyMap == null || key == null) {
706 return null;
707 }
708 return thawKeyMap.get(key);
709 }
710
711 /**
712 * Returns the String that {@code key} will be registered with.
713 * @see #getStaticAttribute
714 * @see #registerStaticAttributeKey
715 * @param key the object key
716 * @return the String that {@code key} will be registered with
717 */
718 public static Object getStaticAttributeKey(Object key) {
719 return key.getClass().getName() + "." + key.toString();
720 }
721
722 private void writeObject(java.io.ObjectOutputStream s)
723 throws IOException
724 {
725 // clean out unused sets before saving
726 removeUnusedSets();
727
728 s.defaultWriteObject();
729 }
730
731 private void readObject(ObjectInputStream s)
732 throws ClassNotFoundException, IOException
859 }
860 s = s + "}";
861 return s;
862 }
863
864 /**
865 * Returns a hashcode for this set of attributes.
866 * @return a hashcode value for this set of attributes.
867 */
868 public int hashCode() {
869 int code = 0;
870 Object[] tbl = attributes;
871 for (int i = 1; i < tbl.length; i += 2) {
872 code ^= tbl[i].hashCode();
873 }
874 return code;
875 }
876
877 /**
878 * Compares this object to the specified object.
879 * The result is {@code true} if the object is an equivalent
880 * set of attributes.
881 * @param obj the object to compare with.
882 * @return {@code true} if the objects are equal;
883 * {@code false} otherwise.
884 */
885 public boolean equals(Object obj) {
886 if (obj instanceof AttributeSet) {
887 AttributeSet attrs = (AttributeSet) obj;
888 return ((getAttributeCount() == attrs.getAttributeCount()) &&
889 containsAttributes(attrs));
890 }
891 return false;
892 }
893
894 /**
895 * Clones a set of attributes. Since the set is immutable, a
896 * clone is basically the same set.
897 *
898 * @return the set of attributes
899 */
900 public Object clone() {
901 return this;
902 }
903
1029 // --- variables -----------------------------------------
1030
1031 Object[] attributes;
1032 // This is also stored in attributes
1033 AttributeSet resolveParent;
1034 }
1035
1036 /**
1037 * An enumeration of the keys in a SmallAttributeSet.
1038 */
1039 class KeyEnumeration implements Enumeration<Object> {
1040
1041 KeyEnumeration(Object[] attr) {
1042 this.attr = attr;
1043 i = 0;
1044 }
1045
1046 /**
1047 * Tests if this enumeration contains more elements.
1048 *
1049 * @return {@code true} if this enumeration contains more elements;
1050 * {@code false} otherwise.
1051 * @since 1.0
1052 */
1053 public boolean hasMoreElements() {
1054 return i < attr.length;
1055 }
1056
1057 /**
1058 * Returns the next element of this enumeration.
1059 *
1060 * @return the next element of this enumeration.
1061 * @exception NoSuchElementException if no more elements exist.
1062 * @since 1.0
1063 */
1064 public Object nextElement() {
1065 if (i < attr.length) {
1066 Object o = attr[i];
1067 i += 2;
1068 return o;
1069 }
1070 throw new NoSuchElementException();
1229 setValue(family, style, size);
1230 }
1231
1232 public void setValue(String family, int style, int size) {
1233 this.family = (family != null) ? family.intern() : null;
1234 this.style = style;
1235 this.size = size;
1236 }
1237
1238 /**
1239 * Returns a hashcode for this font.
1240 * @return a hashcode value for this font.
1241 */
1242 public int hashCode() {
1243 int fhash = (family != null) ? family.hashCode() : 0;
1244 return fhash ^ style ^ size;
1245 }
1246
1247 /**
1248 * Compares this object to the specified object.
1249 * The result is {@code true} if and only if the argument is not
1250 * {@code null} and is a {@code Font} object with the same
1251 * name, style, and point size as this font.
1252 * @param obj the object to compare this font with.
1253 * @return {@code true} if the objects are equal;
1254 * {@code false} otherwise.
1255 */
1256 public boolean equals(Object obj) {
1257 if (obj instanceof FontKey) {
1258 FontKey font = (FontKey)obj;
1259 return (size == font.size) && (style == font.style) && (family == font.family);
1260 }
1261 return false;
1262 }
1263
1264 }
1265
1266 /**
1267 * A collection of attributes, typically used to represent
1268 * character and paragraph styles. This is an implementation
1269 * of MutableAttributeSet that can be observed if desired.
1270 * These styles will take advantage of immutability while
1271 * the sets are small enough, and may be substantially more
1272 * efficient than something like SimpleAttributeSet.
1273 * <p>
1274 * <strong>Warning:</strong>
1275 * Serialized objects of this class will not be compatible with
1276 * future Swing releases. The current serialization support is
1277 * appropriate for short term storage or RMI between applications running
1278 * the same version of Swing. As of 1.4, support for long term storage
1279 * of all JavaBeans™
1280 * has been added to the {@code java.beans} package.
1281 * Please see {@link java.beans.XMLEncoder}.
1282 */
1283 @SuppressWarnings("serial") // Same-version serialization only
1284 public class NamedStyle implements Style, Serializable {
1285
1286 /**
1287 * Creates a new named style.
1288 *
1289 * @param name the style name, null for unnamed
1290 * @param parent the parent style, null if none
1291 * @since 1.4
1292 */
1293 public NamedStyle(String name, Style parent) {
1294 attributes = getEmptySet();
1295 if (name != null) {
1296 setName(name);
1297 }
1298 if (parent != null) {
1299 setResolveParent(parent);
1300 }
1353 /**
1354 * Adds a change listener.
1355 *
1356 * @param l the change listener
1357 */
1358 public void addChangeListener(ChangeListener l) {
1359 listenerList.add(ChangeListener.class, l);
1360 }
1361
1362 /**
1363 * Removes a change listener.
1364 *
1365 * @param l the change listener
1366 */
1367 public void removeChangeListener(ChangeListener l) {
1368 listenerList.remove(ChangeListener.class, l);
1369 }
1370
1371
1372 /**
1373 * Returns an array of all the {@code ChangeListener}s added
1374 * to this NamedStyle with addChangeListener().
1375 *
1376 * @return all of the {@code ChangeListener}s added or an empty
1377 * array if no listeners have been added
1378 * @since 1.4
1379 */
1380 public ChangeListener[] getChangeListeners() {
1381 return listenerList.getListeners(ChangeListener.class);
1382 }
1383
1384
1385 /**
1386 * Notifies all listeners that have registered interest for
1387 * notification on this event type. The event instance
1388 * is lazily created using the parameters passed into
1389 * the fire method.
1390 *
1391 * @see EventListenerList
1392 */
1393 protected void fireStateChanged() {
1394 // Guaranteed to return a non-null array
1395 Object[] listeners = listenerList.getListenerList();
1396 // Process the listeners last to first, notifying
|