/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.dom.svg;
import org.apache.batik.css.engine.CSSEngine;
import org.apache.batik.dom.AbstractAttr;
import org.apache.batik.dom.AbstractDocument;
import org.apache.batik.dom.events.NodeEventTarget;
import org.apache.batik.util.SoftDoublyIndexedTable;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.events.MutationEvent;
/**
* This class provides a superclass to implement an SVG element, or
* an element interoperable with the SVG elements.
*
* @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
* @version $Id: AbstractElement.java,v 1.9 2003/04/11 13:56:06 vhardy Exp $
*/
public abstract class AbstractElement
extends org.apache.batik.dom.AbstractElement
implements NodeEventTarget {
/**
* The live attribute values.
*/
protected transient SoftDoublyIndexedTable liveAttributeValues;
/**
* Creates a new Element object.
*/
protected AbstractElement() {
}
/**
* Creates a new Element object.
* @param prefix The namespace prefix.
* @param owner The owner document.
*/
protected AbstractElement(String prefix, AbstractDocument owner) {
ownerDocument = owner;
setPrefix(prefix);
initializeAttributes();
}
// NodeEventTarget ////////////////////////////////////////////////////
/**
* Implements {@link NodeEventTarget#getParentNodeEventTarget()}.
*/
public NodeEventTarget getParentNodeEventTarget() {
return (NodeEventTarget)
CSSEngine.getLogicalParentNode(getParentNode());
}
// Attributes /////////////////////////////////////////////////////////
/**
* Returns the live attribute value associated with given
* attribute, if any.
* @param ns The attribute's namespace.
* @param ln The attribute's local name.
*/
public LiveAttributeValue getLiveAttributeValue(String ns, String ln) {
if (liveAttributeValues == null) {
return null;
}
return (LiveAttributeValue)liveAttributeValues.get(ns, ln);
}
/**
* Associates a live attribute value to this element.
* @param ns The attribute's namespace.
* @param ln The attribute's local name.
* @param val The live value.
*/
public void putLiveAttributeValue(String ns, String ln,
LiveAttributeValue val) {
if (liveAttributeValues == null) {
liveAttributeValues = new SoftDoublyIndexedTable();
}
liveAttributeValues.put(ns, ln, val);
}
/**
* Returns the AttributeInitializer for this element type.
* @return null if this element has no attribute with a default value.
*/
protected AttributeInitializer getAttributeInitializer() {
return null;
}
/**
* Initializes the attributes of this element to their default value.
*/
protected void initializeAttributes() {
AttributeInitializer ai = getAttributeInitializer();
if (ai != null) {
ai.initializeAttributes(this);
}
}
/**
* Resets an attribute to the default value.
* @return true if a default value is known for the given attribute.
*/
protected boolean resetAttribute(String ns, String prefix, String ln) {
AttributeInitializer ai = getAttributeInitializer();
if (ai == null) {
return false;
}
return ai.resetAttribute(this, ns, prefix, ln);
}
/**
* Creates the attribute list.
*/
protected NamedNodeMap createAttributes() {
return new ExtendedNamedNodeHashMap();
}
/**
* Sets an unspecified attribute.
* @param nsURI The attribute namespace URI.
* @param name The attribute's qualified name.
* @param value The attribute's default value.
*/
public void setUnspecifiedAttribute(String nsURI, String name,
String value) {
if (attributes == null) {
attributes = createAttributes();
}
((ExtendedNamedNodeHashMap)attributes).
setUnspecifiedAttribute(nsURI, name, value);
}
/**
* Called when an attribute has been added.
*/
protected void attrAdded(Attr node, String newv) {
LiveAttributeValue lav = getLiveAttributeValue(node);
if (lav != null) {
lav.attrAdded(node, newv);
}
}
/**
* Called when an attribute has been modified.
*/
protected void attrModified(Attr node, String oldv, String newv) {
LiveAttributeValue lav = getLiveAttributeValue(node);
if (lav != null) {
lav.attrModified(node, oldv, newv);
}
}
/**
* Called when an attribute has been removed.
*/
protected void attrRemoved(Attr node, String oldv) {
LiveAttributeValue lav = getLiveAttributeValue(node);
if (lav != null) {
lav.attrRemoved(node, oldv);
}
}
/**
* Gets Returns the live attribute value associated with given
* attribute, if any.
*/
private LiveAttributeValue getLiveAttributeValue(Attr node) {
String ns = node.getNamespaceURI();
return getLiveAttributeValue(ns, (ns == null)
? node.getNodeName()
: node.getLocalName());
}
// Importation ////////////////////////////////////////////////////
/**
* Exports this node to the given document.
*/
protected Node export(Node n, AbstractDocument d) {
super.export(n, d);
((AbstractElement)n).initializeAttributes();
super.export(n, d);
return n;
}
/**
* Deeply exports this node to the given document.
*/
protected Node deepExport(Node n, AbstractDocument d) {
super.export(n, d);
((AbstractElement)n).initializeAttributes();
super.deepExport(n, d);
return n;
}
/**
* An implementation of the {@link NamedNodeMap}.
*/
protected class ExtendedNamedNodeHashMap extends NamedNodeHashMap {
/**
* Creates a new ExtendedNamedNodeHashMap object.
*/
public ExtendedNamedNodeHashMap() {
}
/**
* Adds an unspecified attribute to the map.
* @param nsURI The attribute namespace URI.
* @param name The attribute's qualified name.
* @param value The attribute's default value.
*/
public void setUnspecifiedAttribute(String nsURI, String name,
String value) {
Attr attr = getOwnerDocument().createAttributeNS(nsURI, name);
attr.setValue(value);
((AbstractAttr)attr).setSpecified(false);
setNamedItemNS(attr);
}
/**
* <b>DOM</b>: Implements {@link
* NamedNodeMap#removeNamedItemNS(String,String)}.
*/
public Node removeNamedItemNS(String namespaceURI, String localName)
throws DOMException {
if (isReadonly()) {
throw createDOMException
(DOMException.NO_MODIFICATION_ALLOWED_ERR,
"readonly.node.map",
new Object[] {});
}
if (localName == null) {
throw createDOMException(DOMException.NOT_FOUND_ERR,
"attribute.missing",
new Object[] { "" });
}
AbstractAttr n = (AbstractAttr)remove(namespaceURI, localName);
if (n == null) {
throw createDOMException(DOMException.NOT_FOUND_ERR,
"attribute.missing",
new Object[] { localName });
}
n.setOwnerElement(null);
String prefix = n.getPrefix();
// Reset the attribute to its default value
if (!resetAttribute(namespaceURI, prefix, localName)) {
// Mutation event
fireDOMAttrModifiedEvent(n.getNodeName(), n,
n.getNodeValue(), "",
MutationEvent.REMOVAL);
}
return n;
}
}
}