/*
* $RCSfile$
*
* Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.perseus.model;
import com.sun.perseus.util.SVGConstants;
import org.w3c.dom.DOMException;
/**
* <code>TimeAttributesNode</code> centralizes functionality common to
* many <code>TimedElementNode</code> subclasses such as trait handling
* for timing attributes.
*/
public class TimeAttributesNode extends TimedElementNode {
/**
* Constructor for TimeAttributesNode.
*
* @param ownerDocument the owner DocumentNode
*/
public TimeAttributesNode(final DocumentNode ownerDocument) {
super(ownerDocument);
// If the document is _not_ loaded (i.e., we are at parse time),
// add this TraitAnimationNode to the document's timedElementNodes
// vector for validation at the end of the loading phase.
if (!ownerDocument.loaded) {
ownerDocument.timedElementNodes.addElement(this);
}
}
/**
* Builds a TimeAttributesNode that belongs to the given
* document. This <code>TimeAttributesNode</code> will belong
* to the <code>DocumentNode</code>'s time container.
*
* @param ownerDocument the document this node belongs to.
* @param localName the element's local name
* @throws IllegalArgumentException if the input ownerDocument is null
*/
public TimeAttributesNode(final DocumentNode ownerDocument,
final String localName) {
super(ownerDocument, localName);
// If the document is _not_ loaded (i.e., we are at parse time),
// add this TraitAnimationNode to the document's timedElementNodes
// vector for validation at the end of the loading phase.
if (!ownerDocument.loaded) {
ownerDocument.timedElementNodes.addElement(this);
}
}
/**
* Used by <code>DocumentNode</code> to create a new instance from
* a prototype <code>TimeAttributesNode</code>.
*
*
* @param doc the <code>DocumentNode</code> for which a new node is
* should be created.
* @return a new <code>TimeAttributesNode</code> for the requested
* document.
*/
public ElementNode newInstance(final DocumentNode doc) {
return new TimeAttributesNode(doc, localName);
}
/**
* TimeAttributesNode supports the begin, end, dur, min, max, restart,
* repeatCount, repeatDur and fill attributes.
*
* @param traitName the name of the trait which the element may support.
* @return true if this element supports the given trait in one of the
* trait accessor methods (such as <code>getTrait</code> or
* <code>setFloatTrait</code>.
*/
boolean supportsTrait(final String traitName) {
if (SVGConstants.SVG_BEGIN_ATTRIBUTE == traitName ||
SVGConstants.SVG_END_ATTRIBUTE == traitName ||
SVGConstants.SVG_DUR_ATTRIBUTE == traitName ||
SVGConstants.SVG_MIN_ATTRIBUTE == traitName ||
SVGConstants.SVG_MAX_ATTRIBUTE == traitName ||
SVGConstants.SVG_RESTART_ATTRIBUTE == traitName ||
SVGConstants.SVG_REPEAT_COUNT_ATTRIBUTE == traitName ||
SVGConstants.SVG_REPEAT_DUR_ATTRIBUTE == traitName ||
SVGConstants.SVG_FILL_ATTRIBUTE == traitName) {
return true;
}
return super.supportsTrait(traitName);
}
/**
* TimeAttributesNode supports the begin, end, dur, min, max, restart,
* repeatCount, repeatDur and fill attributes.
*
* Returns the trait value as String. In SVG Tiny only certain traits can
* be obtained as a String value. Syntax of the returned String matches the
* syntax of the corresponding attribute. This element is exactly
* equivalent to {@link org.w3c.dom.svg.SVGElement#getTraitNS getTraitNS}
* with namespaceURI set to null.
*
* The method is meant to be overridden by derived classes. The
* implementation pattern is that derived classes will override the method
* and call their super class' implementation. If the ElementNode
* implementation is called, it means that the trait is either not
* supported or that it cannot be seen as a String.
*
* @param name the requested trait name.
* @return the trait value.
* @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
* trait is not supported on this element or null.
* @throws DOMException with error code TYPE_MISMATCH_ERR if requested
* trait's computed value cannot be converted to a String (SVG Tiny only).
*/
public String getTraitImpl(final String name) throws DOMException {
if (SVGConstants.SVG_BEGIN_ATTRIBUTE == name) {
if (timedElementSupport.beginConditions.size() == 0) {
return "0s";
}
return TimeCondition.toStringTrait(
timedElementSupport.beginConditions);
} else if (SVGConstants.SVG_END_ATTRIBUTE == name) {
if (timedElementSupport.endConditions.size() == 0) {
return SVGConstants.SVG_INDEFINITE_VALUE;
}
return TimeCondition.toStringTrait(
timedElementSupport.endConditions);
} else if (SVGConstants.SVG_DUR_ATTRIBUTE == name) {
return Time.toStringTrait(timedElementSupport.dur);
} else if (SVGConstants.SVG_MIN_ATTRIBUTE == name) {
return Time.toStringTrait(timedElementSupport.min);
} else if (SVGConstants.SVG_MAX_ATTRIBUTE == name) {
return Time.toStringTrait(timedElementSupport.max);
} else if (SVGConstants.SVG_RESTART_ATTRIBUTE == name) {
switch (timedElementSupport.restart) {
case TimedElementSupport.RESTART_ALWAYS:
return SVGConstants.SVG_ALWAYS_VALUE;
case TimedElementSupport.RESTART_WHEN_NOT_ACTIVE:
return SVGConstants.SVG_WHEN_NOT_ACTIVE_VALUE;
case TimedElementSupport.RESTART_NEVER:
return SVGConstants.SVG_NEVER_VALUE;
default:
throw new IllegalStateException();
}
} else if (SVGConstants.SVG_REPEAT_COUNT_ATTRIBUTE == name) {
if (Float.isNaN(timedElementSupport.repeatCount)) {
return null;
} else if (timedElementSupport.repeatCount == Float.MAX_VALUE) {
return SVGConstants.SVG_INDEFINITE_VALUE;
}
return Float.toString(timedElementSupport.repeatCount);
} else if (SVGConstants.SVG_REPEAT_DUR_ATTRIBUTE == name) {
return Time.toStringTrait(timedElementSupport.repeatDur);
} else if (SVGConstants.SVG_FILL_ATTRIBUTE == name) {
switch (timedElementSupport.fillBehavior) {
case TimedElementSupport.FILL_BEHAVIOR_REMOVE:
return SVGConstants.SVG_REMOVE_VALUE;
case TimedElementSupport.FILL_BEHAVIOR_FREEZE:
return SVGConstants.SVG_FREEZE_VALUE;
default:
throw new IllegalStateException();
}
} else {
return super.getTraitImpl(name);
}
}
/**
* TimeAttributesNode supports the begin, end, dur, min, max, restart,
* repeatCount, repeatDur and fill attributes.
*
* @param name the trait's name.
* @param value the trait's value.
* @throws DOMException with error code NOT_SUPPORTED_ERR if the requested
* trait is not supported on this element or null.
* @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
* trait's value cannot be specified as a String
* @throws DOMException with error code INVALID_ACCESS_ERR if the input
* value is an invalid value for the given trait or null.
* @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
* attempt is made to change readonly trait.
*/
public void setTraitImpl(final String name, final String value) throws DOMException {
if (SVGConstants.SVG_BEGIN_ATTRIBUTE == name) {
checkWriteLoading(name);
timedElementSupport.beginConditions.removeAllElements();
parseTimeConditionsTrait(name, value, true);
} else if (SVGConstants.SVG_END_ATTRIBUTE == name) {
checkWriteLoading(name);
timedElementSupport.endConditions.removeAllElements();
parseTimeConditionsTrait(name, value, false);
} else if (SVGConstants.SVG_DUR_ATTRIBUTE == name) {
checkWriteLoading(name);
if (SVGConstants.SVG_MEDIA_VALUE.equals(value)) {
return;
}
timedElementSupport.setDur(parseClockTrait(name, value));
} else if (SVGConstants.SVG_MIN_ATTRIBUTE == name) {
checkWriteLoading(name);
if (SVGConstants.SVG_MEDIA_VALUE.equals(value)) {
return;
}
timedElementSupport.setMin(parseMinMaxClock(name, value, true));
} else if (SVGConstants.SVG_MAX_ATTRIBUTE == name) {
checkWriteLoading(name);
if (SVGConstants.SVG_MEDIA_VALUE.equals(value)) {
return;
}
timedElementSupport.setMax(parseMinMaxClock(name, value, false));
} else if (SVGConstants.SVG_RESTART_ATTRIBUTE == name) {
checkWriteLoading(name);
if (SVGConstants.SVG_ALWAYS_VALUE.equals(value)) {
timedElementSupport.restart =
TimedElementSupport.RESTART_ALWAYS;
} else if (SVGConstants.SVG_WHEN_NOT_ACTIVE_VALUE.equals(value)) {
timedElementSupport.restart =
TimedElementSupport.RESTART_WHEN_NOT_ACTIVE;
} else if (SVGConstants.SVG_NEVER_VALUE.equals(value)) {
timedElementSupport.restart =
TimedElementSupport.RESTART_NEVER;
} else {
throw illegalTraitValue(name, value);
}
} else if (SVGConstants.SVG_REPEAT_COUNT_ATTRIBUTE == name) {
checkWriteLoading(name);
if (SVGConstants.SVG_INDEFINITE_VALUE.equals(value)) {
timedElementSupport.repeatCount = Float.MAX_VALUE;
} else {
timedElementSupport.repeatCount = parseFloatTrait(name, value);
}
} else if (SVGConstants.SVG_REPEAT_DUR_ATTRIBUTE == name) {
checkWriteLoading(name);
if (SVGConstants.SVG_INDEFINITE_VALUE.equals(value)) {
timedElementSupport.repeatDur = Time.INDEFINITE;
} else {
timedElementSupport.setRepeatDur(parseClockTrait(name, value));
}
} else if (SVGConstants.SVG_FILL_ATTRIBUTE == name) {
checkWriteLoading(name);
if (SVGConstants.SVG_REMOVE_VALUE.equals(value)) {
timedElementSupport.fillBehavior =
TimedElementSupport.FILL_BEHAVIOR_REMOVE;
} else if (SVGConstants.SVG_FREEZE_VALUE.equals(value)) {
timedElementSupport.fillBehavior =
TimedElementSupport.FILL_BEHAVIOR_FREEZE;
} else {
throw illegalTraitValue(name, value);
}
} else {
super.setTraitImpl(name, value);
}
}
/**
* When a TimeAttributesNode is hooked into the document tree, it needs
* to validate (only if the Document is loaded).
*/
final void nodeHookedInDocumentTree() {
super.nodeHookedInDocumentTree();
if (ownerDocument.loaded) {
validate();
}
}
}