blob: b634b6c2efdf5b7d8ff8f8298bc03c1d1d483d9e [file] [log] [blame]
/*****************************************************************************
* 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.CSSOMReadOnlyStyleDeclaration;
import org.apache.batik.css.ElementWithBaseURI;
import org.apache.batik.css.ElementWithID;
import org.apache.batik.css.ElementWithPseudoClass;
import org.apache.batik.css.HiddenChildElement;
import org.apache.batik.css.HiddenChildElementSupport;
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.Element;
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$
*/
public abstract class AbstractElement
extends org.apache.batik.dom.AbstractElement
implements ElementWithBaseURI,
ElementWithID,
ElementWithPseudoClass,
HiddenChildElement {
/**
* The parent element.
*/
protected transient Element parentElement;
/**
* The live attribute values.
*/
protected transient SoftDoublyIndexedTable liveAttributeValues;
/**
* The cascaded style, if any.
*/
protected transient CSSOMReadOnlyStyleDeclaration styleDeclaration;
/**
* 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();
}
// ElementWithBaseURI ////////////////////////////////////////////
/**
* Returns this element's base URI.
*/
public String getBaseURI() {
return XMLBaseSupport.getCascadedXMLBase(this);
}
// ElementWithID /////////////////////////////////////////////////
/**
* Sets the element ID attribute name.
* @param uri The namespace uri.
* @param s The attribute local name.
*/
public void setIDName(String uri, String s) {
if (uri != null || s == null || !s.equals("id")) {
throw createDOMException
(DOMException.NO_MODIFICATION_ALLOWED_ERR,
"id.name",
new Object[] { s });
}
}
/**
* Returns the ID of this element or the empty string.
*/
public String getID() {
return getAttribute("id");
}
// ElementWithPseudoClass ////////////////////////////////////////
/**
* Whether this element matches the given pseudo-class.
* This methods supports the :first-child pseudo class.
*/
public boolean matchPseudoClass(String pseudoClass) {
if (pseudoClass.equals("first-child")) {
Node n = getPreviousSibling();
while (n != null && n.getNodeType() != ELEMENT_NODE) {
n = n.getPreviousSibling();
}
return n == null;
}
return false;
}
// HiddenChildElement ////////////////////////////////////////////
/**
* The parent element of this element.
*/
public Element getParentElement() {
return parentElement;
}
/**
* Sets the parent element.
*/
public void setParentElement(Element elt) {
parentElement = elt;
}
/**
* Gets the style of this element.
*/
public CSSOMReadOnlyStyleDeclaration getStyleDeclaration() {
return styleDeclaration;
}
/**
* Sets the style of this element.
*/
public void setStyleDeclaration(CSSOMReadOnlyStyleDeclaration sd) {
styleDeclaration = sd;
}
/**
* Implements {@link NodeEventTarget#getParentNodeEventTarget()}.
*/
public NodeEventTarget getParentNodeEventTarget() {
return (NodeEventTarget)
HiddenChildElementSupport.getParentElement(this);
}
// 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());
}
/**
* 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;
}
}
}