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.anim.timing;
020:
021: import java.util.Iterator;
022: import java.util.LinkedList;
023: import java.util.List;
024:
025: /**
026: * An abstract base class for time container elements.
027: *
028: * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a>
029: * @version $Id: TimeContainer.java 522271 2007-03-25 14:42:45Z dvholten $
030: */
031: public abstract class TimeContainer extends TimedElement {
032:
033: /**
034: * The child {@link TimedElement}s of this time container.
035: */
036: protected List children = new LinkedList();
037:
038: /**
039: * Adds a {@link TimedElement} to this container.
040: */
041: public void addChild(TimedElement e) {
042: if (e == this ) {
043: throw new IllegalArgumentException(
044: "recursive datastructure not allowed here!");
045: }
046: children.add(e);
047: e.parent = this ;
048: setRoot(e, root);
049: root.fireElementAdded(e);
050: root.currentIntervalWillUpdate();
051: }
052:
053: /**
054: * Recursively sets the {@link TimedDocumentRoot} of the given
055: * {@link TimedElement} and any of its descendants.
056: */
057: protected void setRoot(TimedElement e, TimedDocumentRoot root) {
058: e.root = root;
059: if (e instanceof TimeContainer) {
060: TimeContainer c = (TimeContainer) e;
061: for (Iterator it = c.children.iterator(); it.hasNext();) {
062: TimedElement te = (TimedElement) it.next();
063: setRoot(te, root);
064: }
065: }
066: }
067:
068: /**
069: * Removes a {@link TimedElement} from this container.
070: */
071: public void removeChild(TimedElement e) {
072: children.remove(e);
073: e.parent = null;
074: setRoot(e, null);
075: root.fireElementRemoved(e);
076: root.currentIntervalWillUpdate();
077: }
078:
079: /**
080: * Returns an array of the children of this container.
081: */
082: public TimedElement[] getChildren() {
083: return (TimedElement[]) children.toArray(new TimedElement[0]);
084: }
085:
086: /**
087: * Calculates the local simple time. Currently the hyperlinking parameter
088: * is ignored, so DOM timing events are fired during hyperlinking seeks.
089: * If we were following SMIL 2.1 rather than SMIL Animation, then these
090: * events would have to be surpressed.
091: *
092: * @return the number of seconds until this element becomes active again
093: * if it currently is not, {@link Float#POSITIVE_INFINITY} if this
094: * element will become active at some undetermined point in the
095: * future (because of unresolved begin times, for example) or
096: * will never become active again, or <code>0f</code> if the
097: * element is currently active.
098: */
099: protected float sampleAt(float parentSimpleTime,
100: boolean hyperlinking) {
101: super .sampleAt(parentSimpleTime, hyperlinking);
102: // Maybe check the return value of the previous statement.
103: return sampleChildren(parentSimpleTime, hyperlinking);
104: }
105:
106: /**
107: * Samples all the child timed elements.
108: */
109: protected float sampleChildren(float parentSimpleTime,
110: boolean hyperlinking) {
111: float mint = Float.POSITIVE_INFINITY;
112: Iterator i = children.iterator();
113: while (i.hasNext()) {
114: TimedElement e = (TimedElement) i.next();
115: float t = e.sampleAt(parentSimpleTime, hyperlinking);
116: if (t < mint) {
117: mint = t;
118: }
119: }
120: return mint;
121: }
122:
123: /**
124: * Resets this element.
125: */
126: protected void reset(boolean clearCurrentBegin) {
127: super .reset(clearCurrentBegin);
128: Iterator i = children.iterator();
129: while (i.hasNext()) {
130: TimedElement e = (TimedElement) i.next();
131: e.reset(clearCurrentBegin);
132: }
133: }
134:
135: /**
136: * Returns whether this timed element is for a constant animation (i.e., a
137: * 'set' animation.
138: */
139: protected boolean isConstantAnimation() {
140: return false;
141: }
142:
143: /**
144: * Returns the default begin time for the given child
145: * timed element.
146: */
147: public abstract float getDefaultBegin(TimedElement child);
148: }
|