1. /*
  2. * @(#)MuxingAttributeSet.java 1.4 03/12/19
  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.html;
  8. import javax.swing.text.*;
  9. import java.io.Serializable;
  10. import java.util.*;
  11. /**
  12. * An implementation of <code>AttributeSet</code> that can multiplex
  13. * across a set of <code>AttributeSet</code>s.
  14. *
  15. * @version 1.4 12/19/03
  16. */
  17. class MuxingAttributeSet implements AttributeSet, Serializable {
  18. /**
  19. * Creates a <code>MuxingAttributeSet</code> with the passed in
  20. * attributes.
  21. */
  22. public MuxingAttributeSet(AttributeSet[] attrs) {
  23. this.attrs = attrs;
  24. }
  25. /**
  26. * Creates an empty <code>MuxingAttributeSet</code>. This is intended for
  27. * use by subclasses only, and it is also intended that subclasses will
  28. * set the constituent <code>AttributeSet</code>s before invoking any
  29. * of the <code>AttributeSet</code> methods.
  30. */
  31. protected MuxingAttributeSet() {
  32. }
  33. /**
  34. * Directly sets the <code>AttributeSet</code>s that comprise this
  35. * <code>MuxingAttributeSet</code>.
  36. */
  37. protected synchronized void setAttributes(AttributeSet[] attrs) {
  38. this.attrs = attrs;
  39. }
  40. /**
  41. * Returns the <code>AttributeSet</code>s multiplexing too. When the
  42. * <code>AttributeSet</code>s need to be referenced, this should be called.
  43. */
  44. protected synchronized AttributeSet[] getAttributes() {
  45. return attrs;
  46. }
  47. /**
  48. * Inserts <code>as</code> at <code>index</code>. This assumes
  49. * the value of <code>index</code> is between 0 and attrs.length,
  50. * inclusive.
  51. */
  52. protected synchronized void insertAttributeSetAt(AttributeSet as,
  53. int index) {
  54. int numAttrs = attrs.length;
  55. AttributeSet newAttrs[] = new AttributeSet[numAttrs + 1];
  56. if (index < numAttrs) {
  57. if (index > 0) {
  58. System.arraycopy(attrs, 0, newAttrs, 0, index);
  59. System.arraycopy(attrs, index, newAttrs, index + 1,
  60. numAttrs - index);
  61. }
  62. else {
  63. System.arraycopy(attrs, 0, newAttrs, 1, numAttrs);
  64. }
  65. }
  66. else {
  67. System.arraycopy(attrs, 0, newAttrs, 0, numAttrs);
  68. }
  69. newAttrs[index] = as;
  70. attrs = newAttrs;
  71. }
  72. /**
  73. * Removes the AttributeSet at <code>index</code>. This assumes
  74. * the value of <code>index</code> is greater than or equal to 0,
  75. * and less than attrs.length.
  76. */
  77. protected synchronized void removeAttributeSetAt(int index) {
  78. int numAttrs = attrs.length;
  79. AttributeSet[] newAttrs = new AttributeSet[numAttrs - 1];
  80. if (numAttrs > 0) {
  81. if (index == 0) {
  82. // FIRST
  83. System.arraycopy(attrs, 1, newAttrs, 0, numAttrs - 1);
  84. }
  85. else if (index < (numAttrs - 1)) {
  86. // MIDDLE
  87. System.arraycopy(attrs, 0, newAttrs, 0, index);
  88. System.arraycopy(attrs, index + 1, newAttrs, index,
  89. numAttrs - index - 1);
  90. }
  91. else {
  92. // END
  93. System.arraycopy(attrs, 0, newAttrs, 0, numAttrs - 1);
  94. }
  95. }
  96. attrs = newAttrs;
  97. }
  98. // --- AttributeSet methods ----------------------------
  99. /**
  100. * Gets the number of attributes that are defined.
  101. *
  102. * @return the number of attributes
  103. * @see AttributeSet#getAttributeCount
  104. */
  105. public int getAttributeCount() {
  106. AttributeSet[] as = getAttributes();
  107. int n = 0;
  108. for (int i = 0; i < as.length; i++) {
  109. n += as[i].getAttributeCount();
  110. }
  111. return n;
  112. }
  113. /**
  114. * Checks whether a given attribute is defined.
  115. * This will convert the key over to CSS if the
  116. * key is a StyleConstants key that has a CSS
  117. * mapping.
  118. *
  119. * @param key the attribute key
  120. * @return true if the attribute is defined
  121. * @see AttributeSet#isDefined
  122. */
  123. public boolean isDefined(Object key) {
  124. AttributeSet[] as = getAttributes();
  125. for (int i = 0; i < as.length; i++) {
  126. if (as[i].isDefined(key)) {
  127. return true;
  128. }
  129. }
  130. return false;
  131. }
  132. /**
  133. * Checks whether two attribute sets are equal.
  134. *
  135. * @param attr the attribute set to check against
  136. * @return true if the same
  137. * @see AttributeSet#isEqual
  138. */
  139. public boolean isEqual(AttributeSet attr) {
  140. return ((getAttributeCount() == attr.getAttributeCount()) &&
  141. containsAttributes(attr));
  142. }
  143. /**
  144. * Copies a set of attributes.
  145. *
  146. * @return the copy
  147. * @see AttributeSet#copyAttributes
  148. */
  149. public AttributeSet copyAttributes() {
  150. AttributeSet[] as = getAttributes();
  151. MutableAttributeSet a = new SimpleAttributeSet();
  152. int n = 0;
  153. for (int i = as.length - 1; i >= 0; i--) {
  154. a.addAttributes(as[i]);
  155. }
  156. return a;
  157. }
  158. /**
  159. * Gets the value of an attribute. If the requested
  160. * attribute is a StyleConstants attribute that has
  161. * a CSS mapping, the request will be converted.
  162. *
  163. * @param key the attribute name
  164. * @return the attribute value
  165. * @see AttributeSet#getAttribute
  166. */
  167. public Object getAttribute(Object key) {
  168. AttributeSet[] as = getAttributes();
  169. int n = as.length;
  170. for (int i = 0; i < n; i++) {
  171. Object o = as[i].getAttribute(key);
  172. if (o != null) {
  173. return o;
  174. }
  175. }
  176. return null;
  177. }
  178. /**
  179. * Gets the names of all attributes.
  180. *
  181. * @return the attribute names
  182. * @see AttributeSet#getAttributeNames
  183. */
  184. public Enumeration getAttributeNames() {
  185. return new MuxingAttributeNameEnumeration();
  186. }
  187. /**
  188. * Checks whether a given attribute name/value is defined.
  189. *
  190. * @param name the attribute name
  191. * @param value the attribute value
  192. * @return true if the name/value is defined
  193. * @see AttributeSet#containsAttribute
  194. */
  195. public boolean containsAttribute(Object name, Object value) {
  196. return value.equals(getAttribute(name));
  197. }
  198. /**
  199. * Checks whether the attribute set contains all of
  200. * the given attributes.
  201. *
  202. * @param attrs the attributes to check
  203. * @return true if the element contains all the attributes
  204. * @see AttributeSet#containsAttributes
  205. */
  206. public boolean containsAttributes(AttributeSet attrs) {
  207. boolean result = true;
  208. Enumeration names = attrs.getAttributeNames();
  209. while (result && names.hasMoreElements()) {
  210. Object name = names.nextElement();
  211. result = attrs.getAttribute(name).equals(getAttribute(name));
  212. }
  213. return result;
  214. }
  215. /**
  216. * Returns null, subclasses may wish to do something more
  217. * intelligent with this.
  218. */
  219. public AttributeSet getResolveParent() {
  220. return null;
  221. }
  222. /**
  223. * The <code>AttributeSet</code>s that make up the resulting
  224. * <code>AttributeSet</code>.
  225. */
  226. private AttributeSet[] attrs;
  227. /**
  228. * An Enumeration of the Attribute names in a MuxingAttributeSet.
  229. * This may return the same name more than once.
  230. */
  231. private class MuxingAttributeNameEnumeration implements Enumeration {
  232. MuxingAttributeNameEnumeration() {
  233. updateEnum();
  234. }
  235. public boolean hasMoreElements() {
  236. if (currentEnum == null) {
  237. return false;
  238. }
  239. return currentEnum.hasMoreElements();
  240. }
  241. public Object nextElement() {
  242. if (currentEnum == null) {
  243. throw new NoSuchElementException("No more names");
  244. }
  245. Object retObject = currentEnum.nextElement();
  246. if (!currentEnum.hasMoreElements()) {
  247. updateEnum();
  248. }
  249. return retObject;
  250. }
  251. void updateEnum() {
  252. AttributeSet[] as = getAttributes();
  253. currentEnum = null;
  254. while (currentEnum == null && attrIndex < as.length) {
  255. currentEnum = as[attrIndex++].getAttributeNames();
  256. if (!currentEnum.hasMoreElements()) {
  257. currentEnum = null;
  258. }
  259. }
  260. }
  261. /** Index into attrs the current Enumeration came from. */
  262. private int attrIndex;
  263. /** Enumeration from attrs. */
  264. private Enumeration currentEnum;
  265. }
  266. }