001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.dom.svg;
020:
021: import java.util.ArrayList;
022: import java.util.Iterator;
023:
024: import org.apache.batik.anim.values.AnimatableNumberListValue;
025: import org.apache.batik.anim.values.AnimatableValue;
026: import org.apache.batik.dom.anim.AnimationTarget;
027:
028: import org.apache.batik.parser.ParseException;
029:
030: import org.w3c.dom.Attr;
031: import org.w3c.dom.DOMException;
032: import org.w3c.dom.Element;
033: import org.w3c.dom.svg.SVGAnimatedNumberList;
034: import org.w3c.dom.svg.SVGException;
035: import org.w3c.dom.svg.SVGNumber;
036: import org.w3c.dom.svg.SVGNumberList;
037:
038: /**
039: * This class is the implementation of the {@link SVGAnimatedNumberList}
040: * interface.
041: *
042: * @author <a href="mailto:tonny@kiyut.com">Tonny Kohar</a>
043: * @version $Id: SVGOMAnimatedNumberList.java 498740 2007-01-22 18:35:57Z dvholten $
044: */
045: public class SVGOMAnimatedNumberList extends AbstractSVGAnimatedValue
046: implements SVGAnimatedNumberList {
047:
048: /**
049: * The base value.
050: */
051: protected BaseSVGNumberList baseVal;
052:
053: /**
054: * The animated value.
055: */
056: protected AnimSVGNumberList animVal;
057:
058: /**
059: * Whether the list is changing.
060: */
061: protected boolean changing;
062:
063: /**
064: * Default value for the number list.
065: */
066: protected String defaultValue;
067:
068: /**
069: * Whether empty length lists are allowed.
070: */
071: protected boolean emptyAllowed;
072:
073: /**
074: * Creates a new SVGOMAnimatedNumberList.
075: * @param elt The associated element.
076: * @param ns The attribute's namespace URI.
077: * @param ln The attribute's local name.
078: * @param defaultValue The default value if the attribute is not specified.
079: * @param emptyAllowed Whether an empty number list is allowed.
080: */
081: public SVGOMAnimatedNumberList(AbstractElement elt, String ns,
082: String ln, String defaultValue, boolean emptyAllowed) {
083: super (elt, ns, ln);
084: this .defaultValue = defaultValue;
085: this .emptyAllowed = emptyAllowed;
086: }
087:
088: /**
089: * <b>DOM</b>: Implements {@link SVGAnimatedNumberList#getBaseVal()}.
090: */
091: public SVGNumberList getBaseVal() {
092: if (baseVal == null) {
093: baseVal = new BaseSVGNumberList();
094: }
095: return baseVal;
096: }
097:
098: /**
099: * <b>DOM</b>: Implements {@link SVGAnimatedNumberList#getAnimVal()}.
100: */
101: public SVGNumberList getAnimVal() {
102: if (animVal == null) {
103: animVal = new AnimSVGNumberList();
104: }
105: return animVal;
106: }
107:
108: /**
109: * Returns the base value of the attribute as an {@link AnimatableValue}.
110: */
111: public AnimatableValue getUnderlyingValue(AnimationTarget target) {
112: SVGNumberList nl = getBaseVal();
113: int n = nl.getNumberOfItems();
114: float[] numbers = new float[n];
115: for (int i = 0; i < n; i++) {
116: numbers[i] = nl.getItem(n).getValue();
117: }
118: return new AnimatableNumberListValue(target, numbers);
119: }
120:
121: /**
122: * Updates the animated value with the given {@link AnimatableValue}.
123: */
124: protected void updateAnimatedValue(AnimatableValue val) {
125: if (val == null) {
126: hasAnimVal = false;
127: } else {
128: hasAnimVal = true;
129: AnimatableNumberListValue animNumList = (AnimatableNumberListValue) val;
130: if (animVal == null) {
131: animVal = new AnimSVGNumberList();
132: }
133: animVal.setAnimatedValue(animNumList.getNumbers());
134: }
135: fireAnimatedAttributeListeners();
136: }
137:
138: /**
139: * Called when an Attr node has been added.
140: */
141: public void attrAdded(Attr node, String newv) {
142: if (!changing && baseVal != null) {
143: baseVal.invalidate();
144: }
145: fireBaseAttributeListeners();
146: if (!hasAnimVal) {
147: fireAnimatedAttributeListeners();
148: }
149: }
150:
151: /**
152: * Called when an Attr node has been modified.
153: */
154: public void attrModified(Attr node, String oldv, String newv) {
155: if (!changing && baseVal != null) {
156: baseVal.invalidate();
157: }
158: fireBaseAttributeListeners();
159: if (!hasAnimVal) {
160: fireAnimatedAttributeListeners();
161: }
162: }
163:
164: /**
165: * Called when an Attr node has been removed.
166: */
167: public void attrRemoved(Attr node, String oldv) {
168: if (!changing && baseVal != null) {
169: baseVal.invalidate();
170: }
171: fireBaseAttributeListeners();
172: if (!hasAnimVal) {
173: fireAnimatedAttributeListeners();
174: }
175: }
176:
177: /**
178: * {@link SVGNumberList} implementation for the base number list value.
179: */
180: public class BaseSVGNumberList extends AbstractSVGNumberList {
181:
182: /**
183: * Create a DOMException.
184: */
185: protected DOMException createDOMException(short type,
186: String key, Object[] args) {
187: return element.createDOMException(type, key, args);
188: }
189:
190: /**
191: * Create a SVGException.
192: */
193: protected SVGException createSVGException(short type,
194: String key, Object[] args) {
195:
196: return ((SVGOMElement) element).createSVGException(type,
197: key, args);
198: }
199:
200: /**
201: * Returns the element owning the attribute with which this length
202: * list is associated.
203: */
204: protected Element getElement() {
205: return element;
206: }
207:
208: /**
209: * Returns the value of the DOM attribute containing the number list.
210: */
211: protected String getValueAsString() {
212: Attr attr = element.getAttributeNodeNS(namespaceURI,
213: localName);
214: if (attr == null) {
215: return defaultValue;
216: }
217: return attr.getValue();
218: }
219:
220: /**
221: * Sets the DOM attribute value containing the number list.
222: */
223: protected void setAttributeValue(String value) {
224: try {
225: changing = true;
226: element.setAttributeNS(namespaceURI, localName, value);
227: } finally {
228: changing = false;
229: }
230: }
231:
232: /**
233: * Initializes the list, if needed.
234: */
235: protected void revalidate() {
236: if (valid) {
237: return;
238: }
239:
240: String s = getValueAsString();
241: boolean isEmpty = s != null && s.length() == 0;
242: if (s == null || isEmpty && !emptyAllowed) {
243: throw new LiveAttributeException(element, localName,
244: LiveAttributeException.ERR_ATTRIBUTE_MISSING,
245: null);
246: }
247: if (isEmpty) {
248: itemList = new ArrayList(1);
249: } else {
250: try {
251: ListBuilder builder = new ListBuilder();
252:
253: doParse(s, builder);
254:
255: if (builder.getList() != null) {
256: clear(itemList);
257: }
258: itemList = builder.getList();
259: } catch (ParseException e) {
260: itemList = new ArrayList(1);
261: valid = true;
262: throw new LiveAttributeException(
263: element,
264: localName,
265: LiveAttributeException.ERR_ATTRIBUTE_MALFORMED,
266: s);
267: }
268: }
269: valid = true;
270: }
271: }
272:
273: /**
274: * {@link SVGNumberList} implementation for the animated number list value.
275: */
276: protected class AnimSVGNumberList extends AbstractSVGNumberList {
277:
278: /**
279: * Creates a new AnimSVGNumberList.
280: */
281: public AnimSVGNumberList() {
282: itemList = new ArrayList(1);
283: }
284:
285: /**
286: * Create a DOMException.
287: */
288: protected DOMException createDOMException(short type,
289: String key, Object[] args) {
290: return element.createDOMException(type, key, args);
291: }
292:
293: /**
294: * Create a SVGException.
295: */
296: protected SVGException createSVGException(short type,
297: String key, Object[] args) {
298:
299: return ((SVGOMElement) element).createSVGException(type,
300: key, args);
301: }
302:
303: /**
304: * Returns the element owning this SVGNumberList.
305: */
306: protected Element getElement() {
307: return element;
308: }
309:
310: /**
311: * <b>DOM</b>: Implements {@link SVGNumberList#getNumberOfItems()}.
312: */
313: public int getNumberOfItems() {
314: if (hasAnimVal) {
315: return super .getNumberOfItems();
316: }
317: return getBaseVal().getNumberOfItems();
318: }
319:
320: /**
321: * <b>DOM</b>: Implements {@link SVGNumberList#getItem(int)}.
322: */
323: public SVGNumber getItem(int index) throws DOMException {
324: if (hasAnimVal) {
325: return super .getItem(index);
326: }
327: return getBaseVal().getItem(index);
328: }
329:
330: /**
331: * Returns the value of the DOM attribute containing the point list.
332: */
333: protected String getValueAsString() {
334: if (itemList.size() == 0) {
335: return "";
336: }
337: StringBuffer sb = new StringBuffer(itemList.size() * 8);
338: Iterator i = itemList.iterator();
339: if (i.hasNext()) {
340: sb.append(((SVGItem) i.next()).getValueAsString());
341: }
342: while (i.hasNext()) {
343: sb.append(getItemSeparator());
344: sb.append(((SVGItem) i.next()).getValueAsString());
345: }
346: return sb.toString();
347: }
348:
349: /**
350: * Sets the DOM attribute value containing the point list.
351: */
352: protected void setAttributeValue(String value) {
353: }
354:
355: /**
356: * <b>DOM</b>: Implements {@link SVGNumberList#clear()}.
357: */
358: public void clear() throws DOMException {
359: throw element.createDOMException(
360: DOMException.NO_MODIFICATION_ALLOWED_ERR,
361: "readonly.number.list", null);
362: }
363:
364: /**
365: * <b>DOM</b>: Implements {@link SVGNumberList#initialize(SVGNumber)}.
366: */
367: public SVGNumber initialize(SVGNumber newItem)
368: throws DOMException, SVGException {
369: throw element.createDOMException(
370: DOMException.NO_MODIFICATION_ALLOWED_ERR,
371: "readonly.number.list", null);
372: }
373:
374: /**
375: * <b>DOM</b>: Implements {@link
376: * SVGNumberList#insertItemBefore(SVGNumber, int)}.
377: */
378: public SVGNumber insertItemBefore(SVGNumber newItem, int index)
379: throws DOMException, SVGException {
380: throw element.createDOMException(
381: DOMException.NO_MODIFICATION_ALLOWED_ERR,
382: "readonly.number.list", null);
383: }
384:
385: /**
386: * <b>DOM</b>: Implements {@link
387: * SVGNumberList#replaceItem(SVGNumber, int)}.
388: */
389: public SVGNumber replaceItem(SVGNumber newItem, int index)
390: throws DOMException, SVGException {
391: throw element.createDOMException(
392: DOMException.NO_MODIFICATION_ALLOWED_ERR,
393: "readonly.number.list", null);
394: }
395:
396: /**
397: * <b>DOM</b>: Implements {@link SVGNumberList#removeItem(int)}.
398: */
399: public SVGNumber removeItem(int index) throws DOMException {
400: throw element.createDOMException(
401: DOMException.NO_MODIFICATION_ALLOWED_ERR,
402: "readonly.number.list", null);
403: }
404:
405: /**
406: * <b>DOM</b>: Implements {@link SVGNumberList#appendItem(SVGNumber)}.
407: */
408: public SVGNumber appendItem(SVGNumber newItem)
409: throws DOMException {
410: throw element.createDOMException(
411: DOMException.NO_MODIFICATION_ALLOWED_ERR,
412: "readonly.number.list", null);
413: }
414:
415: /**
416: * Sets the animated value.
417: */
418: protected void setAnimatedValue(float[] values) {
419: int size = itemList.size();
420: int i = 0;
421: while (i < size && i < values.length) {
422: SVGNumberItem n = (SVGNumberItem) itemList.get(i);
423: n.value = values[i];
424: i++;
425: }
426: while (i < values.length) {
427: appendItemImpl(new SVGNumberItem(values[i]));
428: i++;
429: }
430: while (size > values.length) {
431: removeItemImpl(--size);
432: }
433: }
434:
435: /**
436: * Resets the value of the associated attribute. Does nothing, since
437: * there is no attribute for an animated value.
438: */
439: protected void resetAttribute() {
440: }
441:
442: /**
443: * Resets the value of the associated attribute. Does nothing, since
444: * there is no attribute for an animated value.
445: */
446: protected void resetAttribute(SVGItem item) {
447: }
448:
449: /**
450: * Initializes the list, if needed. Does nothing, since there is no
451: * attribute to read the list from.
452: */
453: protected void revalidate() {
454: valid = true;
455: }
456: }
457: }
|