blob: 4247e15f0dd5f7cf75109015c912cf3e56133a8e [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package javax.swing.text.html;
26
27import javax.swing.text.*;
28import java.io.Serializable;
29import java.util.*;
30
31/**
32 * An implementation of <code>AttributeSet</code> that can multiplex
33 * across a set of <code>AttributeSet</code>s.
34 *
35 */
36class MuxingAttributeSet implements AttributeSet, Serializable {
37 /**
38 * Creates a <code>MuxingAttributeSet</code> with the passed in
39 * attributes.
40 */
41 public MuxingAttributeSet(AttributeSet[] attrs) {
42 this.attrs = attrs;
43 }
44
45 /**
46 * Creates an empty <code>MuxingAttributeSet</code>. This is intended for
47 * use by subclasses only, and it is also intended that subclasses will
48 * set the constituent <code>AttributeSet</code>s before invoking any
49 * of the <code>AttributeSet</code> methods.
50 */
51 protected MuxingAttributeSet() {
52 }
53
54 /**
55 * Directly sets the <code>AttributeSet</code>s that comprise this
56 * <code>MuxingAttributeSet</code>.
57 */
58 protected synchronized void setAttributes(AttributeSet[] attrs) {
59 this.attrs = attrs;
60 }
61
62 /**
63 * Returns the <code>AttributeSet</code>s multiplexing too. When the
64 * <code>AttributeSet</code>s need to be referenced, this should be called.
65 */
66 protected synchronized AttributeSet[] getAttributes() {
67 return attrs;
68 }
69
70 /**
71 * Inserts <code>as</code> at <code>index</code>. This assumes
72 * the value of <code>index</code> is between 0 and attrs.length,
73 * inclusive.
74 */
75 protected synchronized void insertAttributeSetAt(AttributeSet as,
76 int index) {
77 int numAttrs = attrs.length;
78 AttributeSet newAttrs[] = new AttributeSet[numAttrs + 1];
79 if (index < numAttrs) {
80 if (index > 0) {
81 System.arraycopy(attrs, 0, newAttrs, 0, index);
82 System.arraycopy(attrs, index, newAttrs, index + 1,
83 numAttrs - index);
84 }
85 else {
86 System.arraycopy(attrs, 0, newAttrs, 1, numAttrs);
87 }
88 }
89 else {
90 System.arraycopy(attrs, 0, newAttrs, 0, numAttrs);
91 }
92 newAttrs[index] = as;
93 attrs = newAttrs;
94 }
95
96 /**
97 * Removes the AttributeSet at <code>index</code>. This assumes
98 * the value of <code>index</code> is greater than or equal to 0,
99 * and less than attrs.length.
100 */
101 protected synchronized void removeAttributeSetAt(int index) {
102 int numAttrs = attrs.length;
103 AttributeSet[] newAttrs = new AttributeSet[numAttrs - 1];
104 if (numAttrs > 0) {
105 if (index == 0) {
106 // FIRST
107 System.arraycopy(attrs, 1, newAttrs, 0, numAttrs - 1);
108 }
109 else if (index < (numAttrs - 1)) {
110 // MIDDLE
111 System.arraycopy(attrs, 0, newAttrs, 0, index);
112 System.arraycopy(attrs, index + 1, newAttrs, index,
113 numAttrs - index - 1);
114 }
115 else {
116 // END
117 System.arraycopy(attrs, 0, newAttrs, 0, numAttrs - 1);
118 }
119 }
120 attrs = newAttrs;
121 }
122
123 // --- AttributeSet methods ----------------------------
124
125 /**
126 * Gets the number of attributes that are defined.
127 *
128 * @return the number of attributes
129 * @see AttributeSet#getAttributeCount
130 */
131 public int getAttributeCount() {
132 AttributeSet[] as = getAttributes();
133 int n = 0;
134 for (int i = 0; i < as.length; i++) {
135 n += as[i].getAttributeCount();
136 }
137 return n;
138 }
139
140 /**
141 * Checks whether a given attribute is defined.
142 * This will convert the key over to CSS if the
143 * key is a StyleConstants key that has a CSS
144 * mapping.
145 *
146 * @param key the attribute key
147 * @return true if the attribute is defined
148 * @see AttributeSet#isDefined
149 */
150 public boolean isDefined(Object key) {
151 AttributeSet[] as = getAttributes();
152 for (int i = 0; i < as.length; i++) {
153 if (as[i].isDefined(key)) {
154 return true;
155 }
156 }
157 return false;
158 }
159
160 /**
161 * Checks whether two attribute sets are equal.
162 *
163 * @param attr the attribute set to check against
164 * @return true if the same
165 * @see AttributeSet#isEqual
166 */
167 public boolean isEqual(AttributeSet attr) {
168 return ((getAttributeCount() == attr.getAttributeCount()) &&
169 containsAttributes(attr));
170 }
171
172 /**
173 * Copies a set of attributes.
174 *
175 * @return the copy
176 * @see AttributeSet#copyAttributes
177 */
178 public AttributeSet copyAttributes() {
179 AttributeSet[] as = getAttributes();
180 MutableAttributeSet a = new SimpleAttributeSet();
181 int n = 0;
182 for (int i = as.length - 1; i >= 0; i--) {
183 a.addAttributes(as[i]);
184 }
185 return a;
186 }
187
188 /**
189 * Gets the value of an attribute. If the requested
190 * attribute is a StyleConstants attribute that has
191 * a CSS mapping, the request will be converted.
192 *
193 * @param key the attribute name
194 * @return the attribute value
195 * @see AttributeSet#getAttribute
196 */
197 public Object getAttribute(Object key) {
198 AttributeSet[] as = getAttributes();
199 int n = as.length;
200 for (int i = 0; i < n; i++) {
201 Object o = as[i].getAttribute(key);
202 if (o != null) {
203 return o;
204 }
205 }
206 return null;
207 }
208
209 /**
210 * Gets the names of all attributes.
211 *
212 * @return the attribute names
213 * @see AttributeSet#getAttributeNames
214 */
215 public Enumeration getAttributeNames() {
216 return new MuxingAttributeNameEnumeration();
217 }
218
219 /**
220 * Checks whether a given attribute name/value is defined.
221 *
222 * @param name the attribute name
223 * @param value the attribute value
224 * @return true if the name/value is defined
225 * @see AttributeSet#containsAttribute
226 */
227 public boolean containsAttribute(Object name, Object value) {
228 return value.equals(getAttribute(name));
229 }
230
231 /**
232 * Checks whether the attribute set contains all of
233 * the given attributes.
234 *
235 * @param attrs the attributes to check
236 * @return true if the element contains all the attributes
237 * @see AttributeSet#containsAttributes
238 */
239 public boolean containsAttributes(AttributeSet attrs) {
240 boolean result = true;
241
242 Enumeration names = attrs.getAttributeNames();
243 while (result && names.hasMoreElements()) {
244 Object name = names.nextElement();
245 result = attrs.getAttribute(name).equals(getAttribute(name));
246 }
247
248 return result;
249 }
250
251 /**
252 * Returns null, subclasses may wish to do something more
253 * intelligent with this.
254 */
255 public AttributeSet getResolveParent() {
256 return null;
257 }
258
259 /**
260 * The <code>AttributeSet</code>s that make up the resulting
261 * <code>AttributeSet</code>.
262 */
263 private AttributeSet[] attrs;
264
265
266 /**
267 * An Enumeration of the Attribute names in a MuxingAttributeSet.
268 * This may return the same name more than once.
269 */
270 private class MuxingAttributeNameEnumeration implements Enumeration {
271
272 MuxingAttributeNameEnumeration() {
273 updateEnum();
274 }
275
276 public boolean hasMoreElements() {
277 if (currentEnum == null) {
278 return false;
279 }
280 return currentEnum.hasMoreElements();
281 }
282
283 public Object nextElement() {
284 if (currentEnum == null) {
285 throw new NoSuchElementException("No more names");
286 }
287 Object retObject = currentEnum.nextElement();
288 if (!currentEnum.hasMoreElements()) {
289 updateEnum();
290 }
291 return retObject;
292 }
293
294 void updateEnum() {
295 AttributeSet[] as = getAttributes();
296 currentEnum = null;
297 while (currentEnum == null && attrIndex < as.length) {
298 currentEnum = as[attrIndex++].getAttributeNames();
299 if (!currentEnum.hasMoreElements()) {
300 currentEnum = null;
301 }
302 }
303 }
304
305
306 /** Index into attrs the current Enumeration came from. */
307 private int attrIndex;
308 /** Enumeration from attrs. */
309 private Enumeration currentEnum;
310 }
311}