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 org.apache.batik.css.engine.CSSNavigableNode;
022: import org.apache.batik.dom.AbstractAttr;
023: import org.apache.batik.dom.AbstractDocument;
024: import org.apache.batik.dom.events.NodeEventTarget;
025: import org.apache.batik.dom.util.DoublyIndexedTable;
026:
027: import org.w3c.dom.Attr;
028: import org.w3c.dom.DOMException;
029: import org.w3c.dom.NamedNodeMap;
030: import org.w3c.dom.Node;
031: import org.w3c.dom.events.MutationEvent;
032:
033: /**
034: * This class provides a superclass to implement an SVG element, or
035: * an element interoperable with the SVG elements.
036: *
037: * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
038: * @version $Id: AbstractElement.java 489964 2006-12-24 01:30:23Z cam $
039: */
040: public abstract class AbstractElement extends
041: org.apache.batik.dom.AbstractElement implements
042: NodeEventTarget, CSSNavigableNode {
043:
044: /**
045: * The live attribute values.
046: */
047: protected transient DoublyIndexedTable liveAttributeValues = new DoublyIndexedTable();
048:
049: /**
050: * Creates a new Element object.
051: */
052: protected AbstractElement() {
053: }
054:
055: /**
056: * Creates a new Element object.
057: * @param prefix The namespace prefix.
058: * @param owner The owner document.
059: */
060: protected AbstractElement(String prefix, AbstractDocument owner) {
061: ownerDocument = owner;
062: setPrefix(prefix);
063: initializeAttributes();
064: }
065:
066: // CSSNavigableNode ///////////////////////////////////////////////////
067:
068: /**
069: * Returns the CSS parent node of this node.
070: */
071: public Node getCSSParentNode() {
072: return getXblParentNode();
073: }
074:
075: /**
076: * Returns the CSS previous sibling node of this node.
077: */
078: public Node getCSSPreviousSibling() {
079: return getXblPreviousSibling();
080: }
081:
082: /**
083: * Returns the CSS next sibling node of this node.
084: */
085: public Node getCSSNextSibling() {
086: return getXblNextSibling();
087: }
088:
089: /**
090: * Returns the CSS first child node of this node.
091: */
092: public Node getCSSFirstChild() {
093: return getXblFirstChild();
094: }
095:
096: /**
097: * Returns the CSS last child of this node.
098: */
099: public Node getCSSLastChild() {
100: return getXblLastChild();
101: }
102:
103: /**
104: * Returns whether this node is the root of a (conceptual) hidden tree
105: * that selectors will not work across.
106: */
107: public boolean isHiddenFromSelectors() {
108: return false;
109: }
110:
111: // Attributes /////////////////////////////////////////////////////////
112:
113: /**
114: * Returns the live attribute value associated with given
115: * attribute, if any.
116: * @param ns The attribute's namespace.
117: * @param ln The attribute's local name.
118: */
119: public LiveAttributeValue getLiveAttributeValue(String ns, String ln) {
120: // if (liveAttributeValues == null) {
121: // return null;
122: // }
123: return (LiveAttributeValue) liveAttributeValues.get(ns, ln);
124: }
125:
126: /**
127: * Associates a live attribute value to this element.
128: * @param ns The attribute's namespace.
129: * @param ln The attribute's local name.
130: * @param val The live value.
131: */
132: public void putLiveAttributeValue(String ns, String ln,
133: LiveAttributeValue val) {
134: // if (liveAttributeValues == null) {
135: // liveAttributeValues = new SoftDoublyIndexedTable();
136: // }
137: liveAttributeValues.put(ns, ln, val);
138: }
139:
140: /**
141: * Returns the AttributeInitializer for this element type.
142: * @return null if this element has no attribute with a default value.
143: */
144: protected AttributeInitializer getAttributeInitializer() {
145: return null;
146: }
147:
148: /**
149: * Initializes the attributes of this element to their default value.
150: */
151: protected void initializeAttributes() {
152: AttributeInitializer ai = getAttributeInitializer();
153: if (ai != null) {
154: ai.initializeAttributes(this );
155: }
156: }
157:
158: /**
159: * Resets an attribute to the default value.
160: * @return true if a default value is known for the given attribute.
161: */
162: protected boolean resetAttribute(String ns, String prefix, String ln) {
163: AttributeInitializer ai = getAttributeInitializer();
164: if (ai == null) {
165: return false;
166: }
167: return ai.resetAttribute(this , ns, prefix, ln);
168: }
169:
170: /**
171: * Creates the attribute list.
172: */
173: protected NamedNodeMap createAttributes() {
174: return new ExtendedNamedNodeHashMap();
175: }
176:
177: /**
178: * Sets an unspecified attribute.
179: * @param nsURI The attribute namespace URI.
180: * @param name The attribute's qualified name.
181: * @param value The attribute's default value.
182: */
183: public void setUnspecifiedAttribute(String nsURI, String name,
184: String value) {
185: if (attributes == null) {
186: attributes = createAttributes();
187: }
188: ((ExtendedNamedNodeHashMap) attributes)
189: .setUnspecifiedAttribute(nsURI, name, value);
190: }
191:
192: /**
193: * Called when an attribute has been added.
194: */
195: protected void attrAdded(Attr node, String newv) {
196: LiveAttributeValue lav = getLiveAttributeValue(node);
197: if (lav != null) {
198: lav.attrAdded(node, newv);
199: }
200: }
201:
202: /**
203: * Called when an attribute has been modified.
204: */
205: protected void attrModified(Attr node, String oldv, String newv) {
206: LiveAttributeValue lav = getLiveAttributeValue(node);
207: if (lav != null) {
208: lav.attrModified(node, oldv, newv);
209: }
210: }
211:
212: /**
213: * Called when an attribute has been removed.
214: */
215: protected void attrRemoved(Attr node, String oldv) {
216: LiveAttributeValue lav = getLiveAttributeValue(node);
217: if (lav != null) {
218: lav.attrRemoved(node, oldv);
219: }
220: }
221:
222: /**
223: * Gets Returns the live attribute value associated with given
224: * attribute, if any.
225: */
226: private LiveAttributeValue getLiveAttributeValue(Attr node) {
227: String ns = node.getNamespaceURI();
228: return getLiveAttributeValue(ns, (ns == null) ? node
229: .getNodeName() : node.getLocalName());
230: }
231:
232: // Importation ////////////////////////////////////////////////////
233:
234: /**
235: * Exports this node to the given document.
236: */
237: protected Node export(Node n, AbstractDocument d) {
238: super .export(n, d);
239: ((AbstractElement) n).initializeAttributes();
240:
241: super .export(n, d);
242: return n;
243: }
244:
245: /**
246: * Deeply exports this node to the given document.
247: */
248: protected Node deepExport(Node n, AbstractDocument d) {
249: super .export(n, d);
250: ((AbstractElement) n).initializeAttributes();
251:
252: super .deepExport(n, d);
253: return n;
254: }
255:
256: /**
257: * An implementation of the {@link NamedNodeMap}.
258: */
259: protected class ExtendedNamedNodeHashMap extends NamedNodeHashMap {
260:
261: /**
262: * Creates a new ExtendedNamedNodeHashMap object.
263: */
264: public ExtendedNamedNodeHashMap() {
265: }
266:
267: /**
268: * Adds an unspecified attribute to the map.
269: *
270: * @param nsURI The attribute namespace URI.
271: * @param name The attribute's qualified name.
272: * @param value The attribute's default value.
273: */
274: public void setUnspecifiedAttribute(String nsURI, String name,
275: String value) {
276: Attr attr = getOwnerDocument().createAttributeNS(nsURI,
277: name);
278: attr.setValue(value);
279: ((AbstractAttr) attr).setSpecified(false);
280: setNamedItemNS(attr);
281: }
282:
283: /**
284: * <b>DOM</b>: Implements {@link NamedNodeMap#removeNamedItemNS(String,String)}.
285: */
286: public Node removeNamedItemNS(String namespaceURI,
287: String localName) throws DOMException {
288: if (isReadonly()) {
289: throw createDOMException(
290: DOMException.NO_MODIFICATION_ALLOWED_ERR,
291: "readonly.node.map", new Object[] {});
292: }
293: if (localName == null) {
294: throw createDOMException(DOMException.NOT_FOUND_ERR,
295: "attribute.missing", new Object[] { "" });
296: }
297: AbstractAttr n = (AbstractAttr) remove(namespaceURI,
298: localName);
299: if (n == null) {
300: throw createDOMException(DOMException.NOT_FOUND_ERR,
301: "attribute.missing", new Object[] { localName });
302: }
303: n.setOwnerElement(null);
304: String prefix = n.getPrefix();
305:
306: // Reset the attribute to its default value
307: if (!resetAttribute(namespaceURI, prefix, localName)) {
308: // Mutation event
309: fireDOMAttrModifiedEvent(n.getNodeName(), n, n
310: .getNodeValue(), "", MutationEvent.REMOVAL);
311: }
312: return n;
313: }
314: }
315:
316: }
|