/*****************************************************************************
* 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 java.net.MalformedURLException;
import java.net.URL;
import org.apache.batik.css.dom.CSSOMSVGColor;
import org.apache.batik.css.dom.CSSOMSVGPaint;
import org.apache.batik.css.dom.CSSOMSVGStyleDeclaration;
import org.apache.batik.css.dom.CSSOMValue;
import org.apache.batik.css.engine.CSSEngine;
import org.apache.batik.css.engine.CSSStylableElement;
import org.apache.batik.css.engine.SVGCSSEngine;
import org.apache.batik.css.engine.StyleMap;
import org.apache.batik.css.engine.value.Value;
import org.apache.batik.css.engine.value.svg.SVGColorManager;
import org.apache.batik.css.engine.value.svg.SVGPaintManager;
import org.apache.batik.dom.AbstractDocument;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.css.CSSStyleDeclaration;
import org.w3c.dom.css.CSSValue;
import org.w3c.dom.svg.SVGAnimatedString;
/**
* This class provides a common superclass for elements which implement
* SVGStylable.
*
* @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
* @version $Id: SVGStylableElement.java,v 1.8 2003/07/09 02:10:10 deweese Exp $
*/
public abstract class SVGStylableElement
extends SVGOMElement
implements CSSStylableElement {
/**
* The computed style map.
*/
protected StyleMap computedStyleMap;
/**
* Creates a new SVGStylableElement object.
*/
protected SVGStylableElement() {
}
/**
* Creates a new SVGStylableElement object.
* @param prefix The namespace prefix.
* @param owner The owner document.
*/
protected SVGStylableElement(String prefix, AbstractDocument owner) {
super(prefix, owner);
}
// CSSStylableElement //////////////////////////////////////////
/**
* Returns the computed style of this element/pseudo-element.
*/
public StyleMap getComputedStyleMap(String pseudoElement) {
return computedStyleMap;
}
/**
* Sets the computed style of this element/pseudo-element.
*/
public void setComputedStyleMap(String pseudoElement, StyleMap sm) {
computedStyleMap = sm;
}
/**
* Returns the ID of this element.
*/
public String getXMLId() {
return getAttributeNS(null, "id");
}
/**
* Returns the class of this element.
*/
public String getCSSClass() {
return getAttributeNS(null, "class");
}
/**
* Returns the CSS base URL of this element.
*/
public URL getCSSBase() {
try {
String bu = XMLBaseSupport.getCascadedXMLBase(this);
if (bu == null) {
return null;
}
return new URL(bu);
} catch (MalformedURLException e) {
// !!! TODO
e.printStackTrace();
throw new InternalError();
}
}
/**
* Tells whether this element is an instance of the given pseudo
* class.
*/
public boolean isPseudoInstanceOf(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;
}
// SVGStylable support ///////////////////////////////////////////////////
/**
* <b>DOM</b>: Implements {@link org.w3c.dom.svg.SVGStylable#getStyle()}.
*/
public CSSStyleDeclaration getStyle() {
CSSStyleDeclaration result =
(CSSStyleDeclaration)getLiveAttributeValue(null,
SVG_STYLE_ATTRIBUTE);
if (result == null) {
CSSEngine eng = ((SVGOMDocument)getOwnerDocument()).getCSSEngine();
result = new StyleDeclaration(eng);
}
return result;
}
/**
* <b>DOM</b>: Implements {@link
* org.w3c.dom.svg.SVGStylable#getPresentationAttribute(String)}.
*/
public CSSValue getPresentationAttribute(String name) {
CSSValue result = (CSSValue)getLiveAttributeValue(null, name);
if (result == null) {
CSSEngine eng = ((SVGOMDocument)getOwnerDocument()).getCSSEngine();
int idx = eng.getPropertyIndex(name);
if (idx > SVGCSSEngine.WRITING_MODE_INDEX) {
if (eng.getValueManagers()[idx] instanceof SVGColorManager) {
result = new PresentationAttributeColorValue(eng, name);
}
if (eng.getValueManagers()[idx] instanceof SVGPaintManager) {
result = new PresentationAttributePaintValue(eng, name);
}
} else {
switch (idx) {
case -1:
return null;
case SVGCSSEngine.FILL_INDEX:
case SVGCSSEngine.STROKE_INDEX:
result = new PresentationAttributePaintValue(eng, name);
break;
case SVGCSSEngine.FLOOD_COLOR_INDEX:
case SVGCSSEngine.LIGHTING_COLOR_INDEX:
case SVGCSSEngine.STOP_COLOR_INDEX:
result = new PresentationAttributeColorValue(eng, name);
break;
default:
result = new PresentationAttributeValue(eng, name);
}
}
putLiveAttributeValue(null, name, (LiveAttributeValue)result);
}
return result;
}
/**
* <b>DOM</b>: Implements {@link
* org.w3c.dom.svg.SVGStylable#getClassName()}.
*/
public SVGAnimatedString getClassName() {
return getAnimatedStringAttribute(null, SVG_CLASS_ATTRIBUTE);
}
/**
* To manage a presentation attribute value.
*/
public class PresentationAttributeValue
extends CSSOMValue
implements LiveAttributeValue,
CSSOMValue.ValueProvider {
/**
* The CSS engine.
*/
protected CSSEngine cssEngine;
/**
* The property name.
*/
protected String property;
/**
* The value.
*/
protected Value value;
/**
* Whether the mutation comes from this object.
*/
protected boolean mutate;
/**
* Creates a new PresentationAttributeValue.
*/
public PresentationAttributeValue(CSSEngine eng, String prop) {
super(null);
valueProvider = this;
setModificationHandler(new AbstractModificationHandler() {
protected Value getValue() {
return PresentationAttributeValue.this.getValue();
}
public void textChanged(String text) throws DOMException {
value = cssEngine.parsePropertyValue
(SVGStylableElement.this, property, text);
mutate = true;
setAttributeNS(null, property, text);
mutate = false;
}
});
cssEngine = eng;
property = prop;
Attr attr = getAttributeNodeNS(null, prop);
if (attr != null) {
value = cssEngine.parsePropertyValue
(SVGStylableElement.this, prop, attr.getValue());
}
}
// ValueProvider ///////////////////////////////
/**
* Returns the current value associated with this object.
*/
public Value getValue() {
if (value == null) {
throw new DOMException(DOMException.INVALID_STATE_ERR, "");
}
return value;
}
// LiveAttributeValue //////////////////////////////////////
/**
* Called when an Attr node has been added.
*/
public void attrAdded(Attr node, String newv) {
if (!mutate) {
value = cssEngine.parsePropertyValue
(SVGStylableElement.this, property, newv);
}
}
/**
* Called when an Attr node has been modified.
*/
public void attrModified(Attr node, String oldv, String newv) {
if (!mutate) {
value = cssEngine.parsePropertyValue
(SVGStylableElement.this, property, newv);
}
}
/**
* Called when an Attr node has been removed.
*/
public void attrRemoved(Attr node, String oldv) {
if (!mutate) {
value = null;
}
}
}
/**
* To manage a presentation attribute SVGColor value.
*/
public class PresentationAttributeColorValue
extends CSSOMSVGColor
implements LiveAttributeValue,
CSSOMSVGColor.ValueProvider {
/**
* The CSS engine.
*/
protected CSSEngine cssEngine;
/**
* The property name.
*/
protected String property;
/**
* The value.
*/
protected Value value;
/**
* Whether the mutation comes from this object.
*/
protected boolean mutate;
/**
* Creates a new PresentationAttributeColorValue.
*/
public PresentationAttributeColorValue(CSSEngine eng, String prop) {
super(null);
valueProvider = this;
setModificationHandler(new AbstractModificationHandler() {
protected Value getValue() {
return PresentationAttributeColorValue.this.getValue();
}
public void textChanged(String text) throws DOMException {
value = cssEngine.parsePropertyValue
(SVGStylableElement.this, property, text);
mutate = true;
setAttributeNS(null, property, text);
mutate = false;
}
});
cssEngine = eng;
property = prop;
Attr attr = getAttributeNodeNS(null, prop);
if (attr != null) {
value = cssEngine.parsePropertyValue
(SVGStylableElement.this, prop, attr.getValue());
}
}
// ValueProvider ///////////////////////////////
/**
* Returns the current value associated with this object.
*/
public Value getValue() {
if (value == null) {
throw new DOMException(DOMException.INVALID_STATE_ERR, "");
}
return value;
}
// LiveAttributeValue //////////////////////////////////////
/**
* Called when an Attr node has been added.
*/
public void attrAdded(Attr node, String newv) {
if (!mutate) {
value = cssEngine.parsePropertyValue
(SVGStylableElement.this, property, newv);
}
}
/**
* Called when an Attr node has been modified.
*/
public void attrModified(Attr node, String oldv, String newv) {
if (!mutate) {
value = cssEngine.parsePropertyValue
(SVGStylableElement.this, property, newv);
}
}
/**
* Called when an Attr node has been removed.
*/
public void attrRemoved(Attr node, String oldv) {
if (!mutate) {
value = null;
}
}
}
/**
* To manage a presentation attribute SVGPaint value.
*/
public class PresentationAttributePaintValue
extends CSSOMSVGPaint
implements LiveAttributeValue,
CSSOMSVGPaint.ValueProvider {
/**
* The CSS engine.
*/
protected CSSEngine cssEngine;
/**
* The property name.
*/
protected String property;
/**
* The value.
*/
protected Value value;
/**
* Whether the mutation comes from this object.
*/
protected boolean mutate;
/**
* Creates a new PresentationAttributeColorValue.
*/
public PresentationAttributePaintValue(CSSEngine eng, String prop) {
super(null);
valueProvider = this;
setModificationHandler(new AbstractModificationHandler() {
protected Value getValue() {
return PresentationAttributePaintValue.this.getValue();
}
public void textChanged(String text) throws DOMException {
value = cssEngine.parsePropertyValue
(SVGStylableElement.this, property, text);
mutate = true;
setAttributeNS(null, property, text);
mutate = false;
}
});
cssEngine = eng;
property = prop;
Attr attr = getAttributeNodeNS(null, prop);
if (attr != null) {
value = cssEngine.parsePropertyValue
(SVGStylableElement.this, prop, attr.getValue());
}
}
// ValueProvider ///////////////////////////////
/**
* Returns the current value associated with this object.
*/
public Value getValue() {
if (value == null) {
throw new DOMException(DOMException.INVALID_STATE_ERR, "");
}
return value;
}
// LiveAttributeValue //////////////////////////////////////
/**
* Called when an Attr node has been added.
*/
public void attrAdded(Attr node, String newv) {
if (!mutate) {
value = cssEngine.parsePropertyValue
(SVGStylableElement.this, property, newv);
}
}
/**
* Called when an Attr node has been modified.
*/
public void attrModified(Attr node, String oldv, String newv) {
if (!mutate) {
value = cssEngine.parsePropertyValue
(SVGStylableElement.this, property, newv);
}
}
/**
* Called when an Attr node has been removed.
*/
public void attrRemoved(Attr node, String oldv) {
if (!mutate) {
value = null;
}
}
}
/**
* This class represents the 'style' attribute.
*/
public class StyleDeclaration
extends CSSOMSVGStyleDeclaration
implements LiveAttributeValue,
CSSOMSVGStyleDeclaration.ValueProvider,
CSSOMSVGStyleDeclaration.ModificationHandler {
/**
* The associated CSS object.
*/
protected org.apache.batik.css.engine.StyleDeclaration declaration;
/**
* Whether the mutation comes from this object.
*/
protected boolean mutate;
/**
* Creates a new StyleDeclaration.
*/
public StyleDeclaration(CSSEngine eng) {
super(null, null, eng);
valueProvider = this;
setModificationHandler(this);
declaration = cssEngine.parseStyleDeclaration
(getAttributeNS(null, SVG_STYLE_ATTRIBUTE));
}
// ValueProvider ////////////////////////////////////////
/**
* Returns the current value associated with this object.
*/
public Value getValue(String name) {
int idx = cssEngine.getPropertyIndex(name);
for (int i = 0; i < declaration.size(); i++) {
if (idx == declaration.getIndex(i)) {
return declaration.getValue(i);
}
}
return null;
}
/**
* Tells whether the given property is important.
*/
public boolean isImportant(String name) {
int idx = cssEngine.getPropertyIndex(name);
for (int i = 0; i < declaration.size(); i++) {
if (idx == declaration.getIndex(i)) {
return declaration.getPriority(i);
}
}
return false;
}
/**
* Returns the text of the declaration.
*/
public String getText() {
return declaration.toString(cssEngine);
}
/**
* Returns the length of the declaration.
*/
public int getLength() {
return declaration.size();
}
/**
* Returns the value at the given.
*/
public String item(int idx) {
return cssEngine.getPropertyName(declaration.getIndex(idx));
}
// LiveAttributeValue //////////////////////////////////////
/**
* Called when an Attr node has been added.
*/
public void attrAdded(Attr node, String newv) {
if (!mutate) {
declaration = cssEngine.parseStyleDeclaration(newv);
}
}
/**
* Called when an Attr node has been modified.
*/
public void attrModified(Attr node, String oldv, String newv) {
if (!mutate) {
declaration = cssEngine.parseStyleDeclaration(newv);
}
}
/**
* Called when an Attr node has been removed.
*/
public void attrRemoved(Attr node, String oldv) {
if (!mutate) {
declaration =
new org.apache.batik.css.engine.StyleDeclaration();
}
}
// ModificationHandler ////////////////////////////////////
/**
* Called when the value text has changed.
*/
public void textChanged(String text) throws DOMException {
declaration = cssEngine.parseStyleDeclaration(text);
mutate = true;
setAttributeNS(null, SVG_STYLE_ATTRIBUTE, text);
mutate = false;
}
/**
* Called when a property was removed.
*/
public void propertyRemoved(String name) throws DOMException {
int idx = cssEngine.getPropertyIndex(name);
for (int i = 0; i < declaration.size(); i++) {
if (idx == declaration.getIndex(i)) {
declaration.remove(i);
mutate = true;
setAttributeNS(null, SVG_STYLE_ATTRIBUTE,
declaration.toString(cssEngine));
mutate = false;
return;
}
}
}
/**
* Called when a property was changed.
*/
public void propertyChanged(String name, String value, String prio)
throws DOMException {
int idx = cssEngine.getPropertyIndex(name);
for (int i = 0; i < declaration.size(); i++) {
if (idx == declaration.getIndex(i)) {
Value v = cssEngine.parsePropertyValue
(SVGStylableElement.this, name, value);
declaration.put(i, v, idx, prio.length() > 0);
mutate = true;
setAttributeNS(null, SVG_STYLE_ATTRIBUTE,
declaration.toString(cssEngine));
mutate = false;
return;
}
}
Value v = cssEngine.parsePropertyValue
(SVGStylableElement.this, name, value);
declaration.append(v, idx, prio.length() > 0);
mutate = true;
setAttributeNS(null, SVG_STYLE_ATTRIBUTE,
declaration.toString(cssEngine));
mutate = false;
}
}
}