1. /*
  2. * @(#)SimpleAttributeSet.java 1.41 04/05/05
  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. import java.util.Hashtable;
  9. import java.util.Enumeration;
  10. import java.util.NoSuchElementException;
  11. import java.io.IOException;
  12. import java.io.ObjectInputStream;
  13. import java.io.ObjectOutputStream;
  14. import java.io.Serializable;
  15. /**
  16. * A straightforward implementation of MutableAttributeSet using a
  17. * hash table.
  18. * <p>
  19. * <strong>Warning:</strong>
  20. * Serialized objects of this class will not be compatible with
  21. * future Swing releases. The current serialization support is
  22. * appropriate for short term storage or RMI between applications running
  23. * the same version of Swing. As of 1.4, support for long term storage
  24. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  25. * has been added to the <code>java.beans</code> package.
  26. * Please see {@link java.beans.XMLEncoder}.
  27. *
  28. * @version 1.41 05/05/04
  29. * @author Tim Prinzing
  30. */
  31. public class SimpleAttributeSet implements MutableAttributeSet, Serializable, Cloneable
  32. {
  33. /**
  34. * An empty attribute set.
  35. */
  36. public static final AttributeSet EMPTY = new EmptyAttributeSet();
  37. private transient Hashtable table = new Hashtable(3);
  38. private static Enumeration emptyEnumeration;
  39. /**
  40. * Creates a new attribute set.
  41. */
  42. public SimpleAttributeSet() {
  43. }
  44. /**
  45. * Creates a new attribute set based on a supplied set of attributes.
  46. *
  47. * @param source the set of attributes
  48. */
  49. public SimpleAttributeSet(AttributeSet source) {
  50. addAttributes(source);
  51. }
  52. private SimpleAttributeSet(Hashtable table) {
  53. this.table = table;
  54. }
  55. /**
  56. * Checks whether the set of attributes is empty.
  57. *
  58. * @return true if the set is empty else false
  59. */
  60. public boolean isEmpty()
  61. {
  62. return table.isEmpty();
  63. }
  64. /**
  65. * Gets a count of the number of attributes.
  66. *
  67. * @return the count
  68. */
  69. public int getAttributeCount() {
  70. return table.size();
  71. }
  72. /**
  73. * Tells whether a given attribute is defined.
  74. *
  75. * @param attrName the attribute name
  76. * @return true if the attribute is defined
  77. */
  78. public boolean isDefined(Object attrName) {
  79. return table.containsKey(attrName);
  80. }
  81. /**
  82. * Compares two attribute sets.
  83. *
  84. * @param attr the second attribute set
  85. * @return true if the sets are equal, false otherwise
  86. */
  87. public boolean isEqual(AttributeSet attr) {
  88. return ((getAttributeCount() == attr.getAttributeCount()) &&
  89. containsAttributes(attr));
  90. }
  91. /**
  92. * Makes a copy of the attributes.
  93. *
  94. * @return the copy
  95. */
  96. public AttributeSet copyAttributes() {
  97. return (AttributeSet) clone();
  98. }
  99. /**
  100. * Gets the names of the attributes in the set.
  101. *
  102. * @return the names as an <code>Enumeration</code>
  103. */
  104. public Enumeration<?> getAttributeNames() {
  105. return table.keys();
  106. }
  107. /**
  108. * Gets the value of an attribute.
  109. *
  110. * @param name the attribute name
  111. * @return the value
  112. */
  113. public Object getAttribute(Object name) {
  114. Object value = table.get(name);
  115. if (value == null) {
  116. AttributeSet parent = getResolveParent();
  117. if (parent != null) {
  118. value = parent.getAttribute(name);
  119. }
  120. }
  121. return value;
  122. }
  123. /**
  124. * Checks whether the attribute list contains a
  125. * specified attribute name/value pair.
  126. *
  127. * @param name the name
  128. * @param value the value
  129. * @return true if the name/value pair is in the list
  130. */
  131. public boolean containsAttribute(Object name, Object value) {
  132. return value.equals(getAttribute(name));
  133. }
  134. /**
  135. * Checks whether the attribute list contains all the
  136. * specified name/value pairs.
  137. *
  138. * @param attributes the attribute list
  139. * @return true if the list contains all the name/value pairs
  140. */
  141. public boolean containsAttributes(AttributeSet attributes) {
  142. boolean result = true;
  143. Enumeration names = attributes.getAttributeNames();
  144. while (result && names.hasMoreElements()) {
  145. Object name = names.nextElement();
  146. result = attributes.getAttribute(name).equals(getAttribute(name));
  147. }
  148. return result;
  149. }
  150. /**
  151. * Adds an attribute to the list.
  152. *
  153. * @param name the attribute name
  154. * @param value the attribute value
  155. */
  156. public void addAttribute(Object name, Object value) {
  157. table.put(name, value);
  158. }
  159. /**
  160. * Adds a set of attributes to the list.
  161. *
  162. * @param attributes the set of attributes to add
  163. */
  164. public void addAttributes(AttributeSet attributes) {
  165. Enumeration names = attributes.getAttributeNames();
  166. while (names.hasMoreElements()) {
  167. Object name = names.nextElement();
  168. addAttribute(name, attributes.getAttribute(name));
  169. }
  170. }
  171. /**
  172. * Removes an attribute from the list.
  173. *
  174. * @param name the attribute name
  175. */
  176. public void removeAttribute(Object name) {
  177. table.remove(name);
  178. }
  179. /**
  180. * Removes a set of attributes from the list.
  181. *
  182. * @param names the set of names to remove
  183. */
  184. public void removeAttributes(Enumeration<?> names) {
  185. while (names.hasMoreElements())
  186. removeAttribute(names.nextElement());
  187. }
  188. /**
  189. * Removes a set of attributes from the list.
  190. *
  191. * @param attributes the set of attributes to remove
  192. */
  193. public void removeAttributes(AttributeSet attributes) {
  194. if (attributes == this) {
  195. table.clear();
  196. }
  197. else {
  198. Enumeration names = attributes.getAttributeNames();
  199. while (names.hasMoreElements()) {
  200. Object name = names.nextElement();
  201. Object value = attributes.getAttribute(name);
  202. if (value.equals(getAttribute(name)))
  203. removeAttribute(name);
  204. }
  205. }
  206. }
  207. /**
  208. * Gets the resolving parent. This is the set
  209. * of attributes to resolve through if an attribute
  210. * isn't defined locally. This is null if there
  211. * are no other sets of attributes to resolve
  212. * through.
  213. *
  214. * @return the parent
  215. */
  216. public AttributeSet getResolveParent() {
  217. return (AttributeSet) table.get(StyleConstants.ResolveAttribute);
  218. }
  219. /**
  220. * Sets the resolving parent.
  221. *
  222. * @param parent the parent
  223. */
  224. public void setResolveParent(AttributeSet parent) {
  225. addAttribute(StyleConstants.ResolveAttribute, parent);
  226. }
  227. // --- Object methods ---------------------------------
  228. /**
  229. * Clones a set of attributes.
  230. *
  231. * @return the new set of attributes
  232. */
  233. public Object clone() {
  234. SimpleAttributeSet attr;
  235. try {
  236. attr = (SimpleAttributeSet) super.clone();
  237. attr.table = (Hashtable) table.clone();
  238. } catch (CloneNotSupportedException cnse) {
  239. attr = null;
  240. }
  241. return attr;
  242. }
  243. /**
  244. * Returns a hashcode for this set of attributes.
  245. * @return a hashcode value for this set of attributes.
  246. */
  247. public int hashCode() {
  248. return table.hashCode();
  249. }
  250. /**
  251. * Compares this object to the specified object.
  252. * The result is <code>true</code> if the object is an equivalent
  253. * set of attributes.
  254. * @param obj the object to compare this attribute set with
  255. * @return <code>true</code> if the objects are equal;
  256. * <code>false</code> otherwise
  257. */
  258. public boolean equals(Object obj) {
  259. if (this == obj) {
  260. return true;
  261. }
  262. if (obj instanceof AttributeSet) {
  263. AttributeSet attrs = (AttributeSet) obj;
  264. return isEqual(attrs);
  265. }
  266. return false;
  267. }
  268. /**
  269. * Converts the attribute set to a String.
  270. *
  271. * @return the string
  272. */
  273. public String toString() {
  274. String s = "";
  275. Enumeration names = getAttributeNames();
  276. while (names.hasMoreElements()) {
  277. Object key = names.nextElement();
  278. Object value = getAttribute(key);
  279. if (value instanceof AttributeSet) {
  280. // don't go recursive
  281. s = s + key + "=**AttributeSet** ";
  282. } else {
  283. s = s + key + "=" + value + " ";
  284. }
  285. }
  286. return s;
  287. }
  288. private void writeObject(java.io.ObjectOutputStream s) throws IOException {
  289. s.defaultWriteObject();
  290. StyleContext.writeAttributeSet(s, this);
  291. }
  292. private void readObject(ObjectInputStream s)
  293. throws ClassNotFoundException, IOException {
  294. s.defaultReadObject();
  295. table = new Hashtable(3);
  296. StyleContext.readAttributeSet(s, this);
  297. }
  298. /**
  299. * An AttributeSet this is always empty.
  300. */
  301. static class EmptyAttributeSet implements AttributeSet, Serializable {
  302. public int getAttributeCount() {
  303. return 0;
  304. }
  305. public boolean isDefined(Object attrName) {
  306. return false;
  307. }
  308. public boolean isEqual(AttributeSet attr) {
  309. return (attr.getAttributeCount() == 0);
  310. }
  311. public AttributeSet copyAttributes() {
  312. return this;
  313. }
  314. public Object getAttribute(Object key) {
  315. return null;
  316. }
  317. public Enumeration getAttributeNames() {
  318. return getEmptyEnumeration();
  319. }
  320. public boolean containsAttribute(Object name, Object value) {
  321. return false;
  322. }
  323. public boolean containsAttributes(AttributeSet attributes) {
  324. return (attributes.getAttributeCount() == 0);
  325. }
  326. public AttributeSet getResolveParent() {
  327. return null;
  328. }
  329. public boolean equals(Object obj) {
  330. if (this == obj) {
  331. return true;
  332. }
  333. return ((obj instanceof AttributeSet) &&
  334. (((AttributeSet)obj).getAttributeCount() == 0));
  335. }
  336. public int hashCode() {
  337. return 0;
  338. }
  339. };
  340. private static Enumeration getEmptyEnumeration() {
  341. if (emptyEnumeration == null) {
  342. emptyEnumeration = new Enumeration() {
  343. public boolean hasMoreElements() {
  344. return false;
  345. }
  346. public Object nextElement() {
  347. throw new NoSuchElementException("No more elements");
  348. }
  349. };
  350. }
  351. return emptyEnumeration;
  352. }
  353. }