Index: 3rdParty_sources/versions.txt =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/versions.txt,v diff -u -r1.8 -r1.9 --- 3rdParty_sources/versions.txt 15 Mar 2013 09:55:56 -0000 1.8 +++ 3rdParty_sources/versions.txt 8 Apr 2013 10:55:58 -0000 1.9 @@ -7,6 +7,8 @@ aspirin 0.8.03.201003071132 +batik 1.7.0 + CKEditor 3.6.2 Commons HttpClient 3.0 Index: 3rdParty_sources/batik/org/apache/batik/Version.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/Version.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/Version.java 8 Apr 2013 10:55:58 -0000 1.1 @@ -0,0 +1,103 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik; + +/** + * This class defines the Batik version number. + * + * @author Vincent Hardy + * @version $Id: Version.java,v 1.1 2013/04/08 10:55:58 marcin Exp $ + */ +public final class Version { + + /** + * Returns the Batik version. + *

+ * This is based on the Implementation-Version attribute in the + * batik-util.jar (which is where this Version class lives) and + * the 'HeadURL' SVN keyword. The keyword be substituted with + * the URL of this file, which is then inspected to determine if this + * file was compiled from the trunk, a tag (a release version), or a + * branch. The format of the returned string will be one of the + * following: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
SourceVersion string
Release versionversion
Trunkversion+rrevision
Branchversion+rrevision; branch-name
Unknowndevelopment version
+ *

+ * Prior to release 1.7, the version string would + * be the straight tag (e.g. "batik-1_6") or the + * string "development.version". revision is the + * Subversion working copy's revision number. + *

+ */ + public static String getVersion() { + Package pkg = Version.class.getPackage(); + String version = null; + if (pkg != null) { + version = pkg.getImplementationVersion(); + } + String headURL = "$HeadURL: http://svn.apache.org/repos/asf/xmlgraphics/batik/tags/batik-1_7/sources/org/apache/batik/Version.java $"; + String prefix = "$HeadURL: "; + String suffix = "/sources/org/apache/batik/Version.java $"; + if (headURL.startsWith(prefix) && headURL.endsWith(suffix)) { + headURL = headURL.substring + (prefix.length(), headURL.length() - suffix.length()); + if (!headURL.endsWith("/trunk")) { + int index1 = headURL.lastIndexOf('/'); + int index2 = headURL.lastIndexOf('/', index1 - 1); + String name = headURL.substring(index1 + 1); + String type = headURL.substring(index2 + 1, index1); + String tagPrefix = "batik-"; + if (type.equals("tags") && name.startsWith(tagPrefix)) { + // Release, just use the tag name + version = name.substring(tagPrefix.length()) + .replace('_', '.'); + } else if (type.equals("branches")) { + // SVN branch + version += "; " + name; + } + } + } + if (version == null) { + version = "development version"; + } + + return version; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/AbstractAnimation.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/AbstractAnimation.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/AbstractAnimation.java 8 Apr 2013 10:55:58 -0000 1.1 @@ -0,0 +1,210 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim; + +import org.apache.batik.anim.timing.TimedElement; +import org.apache.batik.anim.values.AnimatableValue; +import org.apache.batik.dom.anim.AnimatableElement; + +// import org.apache.batik.anim.timing.Trace; + +/** + * An abstract base class for the different types of animation. + * + * @author Cameron McCormack + * @version $Id: AbstractAnimation.java,v 1.1 2013/04/08 10:55:58 marcin Exp $ + */ +public abstract class AbstractAnimation { + + // Constants for calcMode. + public static final short CALC_MODE_DISCRETE = 0; + public static final short CALC_MODE_LINEAR = 1; + public static final short CALC_MODE_PACED = 2; + public static final short CALC_MODE_SPLINE = 3; + + /** + * The TimedElement that controls the timing of this animation. + */ + protected TimedElement timedElement; + + /** + * The AnimatableElement that gives access to underlying values in the + * document. + */ + protected AnimatableElement animatableElement; + + /** + * The animation that is lower in the sandwich. + */ + protected AbstractAnimation lowerAnimation; + + /** + * The animation that is higher in the sandwich. + */ + protected AbstractAnimation higherAnimation; + + /** + * Whether this animation needs recomputing. + */ + protected boolean isDirty; + + /** + * Whether this animation is active. + */ + protected boolean isActive; + + /** + * Whether this animation is frozen. + */ + protected boolean isFrozen; + + /** + * The time at which this animation became active. Used for ensuring the + * sandwich order is correct when multiple animations become active + * simultaneously. + */ + protected float beginTime; + + /** + * The value of this animation. + */ + protected AnimatableValue value; + + /** + * The value of this animation composed with any others. + */ + protected AnimatableValue composedValue; + + /** + * Whether this animation depends on the underlying value. + */ + protected boolean usesUnderlyingValue; + + /** + * Whether this animation is a 'to-animation'. + */ + protected boolean toAnimation; + + /** + * Creates a new Animation. + */ + protected AbstractAnimation(TimedElement timedElement, + AnimatableElement animatableElement) { + this.timedElement = timedElement; + this.animatableElement = animatableElement; + } + + /** + * Returns the TimedElement for this animation. + */ + public TimedElement getTimedElement() { + return timedElement; + } + + /** + * Returns the value of this animation, or null if it isn't active. + */ + public AnimatableValue getValue() { + if (!isActive && !isFrozen) { + return null; + } + return value; + } + + /** + * Returns the composed value of this animation, or null if it isn't active. + */ + public AnimatableValue getComposedValue() { + // Trace.enter(this, "getComposedValue", null); try { + // Trace.print("isActive == " + isActive + ", isFrozen == " + isFrozen + ", isDirty == " + isDirty); + if (!isActive && !isFrozen) { + return null; + } + if (isDirty) { + // Trace.print("willReplace() == " + willReplace()); + // Trace.print("value == " + value); + AnimatableValue lowerValue = null; + if (!willReplace()) { + // Trace.print("lowerAnimation == " + lowerAnimation); + if (lowerAnimation == null) { + lowerValue = animatableElement.getUnderlyingValue(); + usesUnderlyingValue = true; + } else { + lowerValue = lowerAnimation.getComposedValue(); + usesUnderlyingValue = false; + } + // Trace.print("lowerValue == " + lowerValue); + } + composedValue = + value.interpolate(composedValue, null, 0f, lowerValue, 1); + // Trace.print("composedValue == " + composedValue); + isDirty = false; + } + return composedValue; + // } finally { Trace.exit(); } + } + + /** + * Returns a string representation of this animation. + */ + public String toString() { + return timedElement.toString(); + } + + /** + * Returns whether this animation depends on the underlying value. + */ + public boolean usesUnderlyingValue() { + return usesUnderlyingValue || toAnimation; + } + + /** + * Returns whether this animation will replace values on animations + * lower in the sandwich. + */ + protected boolean willReplace() { + return true; + } + + /** + * Marks this animation and any animation that depends on it + * as dirty. + */ + protected void markDirty() { + isDirty = true; + if (higherAnimation != null + && !higherAnimation.willReplace() + && !higherAnimation.isDirty) { + higherAnimation.markDirty(); + } + } + + /** + * Called when the element is sampled for its "last" value. + */ + protected void sampledLastValue(int repeatIteration) { + } + + /** + * Called when the element is sampled at the given time. This updates + * the {@link #value} of the animation if active. + */ + protected abstract void sampledAt(float simpleTime, float simpleDur, + int repeatIteration); +} Index: 3rdParty_sources/batik/org/apache/batik/anim/AnimationEngine.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/AnimationEngine.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/AnimationEngine.java 8 Apr 2013 10:55:58 -0000 1.1 @@ -0,0 +1,698 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim; + +import java.util.Calendar; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.batik.anim.timing.TimedDocumentRoot; +import org.apache.batik.anim.timing.TimedElement; +import org.apache.batik.anim.timing.TimegraphListener; +import org.apache.batik.anim.values.AnimatableValue; +import org.apache.batik.dom.anim.AnimationTarget; +import org.apache.batik.dom.anim.AnimationTargetListener; +import org.apache.batik.util.DoublyIndexedTable; + +import org.w3c.dom.Document; + +/** + * An abstract base class for managing animation in a document. + * + * @author Cameron McCormack + * @version $Id: AnimationEngine.java,v 1.1 2013/04/08 10:55:58 marcin Exp $ + */ +public abstract class AnimationEngine { + + // Constants to identify the type of animation. + public static final short ANIM_TYPE_XML = 0; + public static final short ANIM_TYPE_CSS = 1; + public static final short ANIM_TYPE_OTHER = 2; + + /** + * The document this AnimationEngine is managing animation for. + */ + protected Document document; + + /** + * The root time container for the document. + */ + protected TimedDocumentRoot timedDocumentRoot; + + /** + * The time at which the document was paused, or 0 if the document is not + * paused. + */ + protected long pauseTime; + + /** + * Map of AnimationTargets to TargetInfo objects. + */ + protected HashMap targets = new HashMap(); + + /** + * Map of AbstractAnimations to AnimationInfo objects. + */ + protected HashMap animations = new HashMap(); + + /** + * The listener object for animation target base value changes. + */ + protected Listener targetListener = new Listener(); + + /** + * Creates a new AnimationEngine for the given document. + */ + public AnimationEngine(Document doc) { + this.document = doc; + timedDocumentRoot = createDocumentRoot(); + } + + /** + * Disposes this animation engine. + */ + public void dispose() { + // Remove any target listeners that are registered. + Iterator i = targets.entrySet().iterator(); + while (i.hasNext()) { + Map.Entry e = (Map.Entry) i.next(); + AnimationTarget target = (AnimationTarget) e.getKey(); + TargetInfo info = (TargetInfo) e.getValue(); + + Iterator j = info.xmlAnimations.iterator(); + while (j.hasNext()) { + DoublyIndexedTable.Entry e2 = + (DoublyIndexedTable.Entry) j.next(); + String namespaceURI = (String) e2.getKey1(); + String localName = (String) e2.getKey2(); + Sandwich sandwich = (Sandwich) e2.getValue(); + if (sandwich.listenerRegistered) { + target.removeTargetListener(namespaceURI, localName, false, + targetListener); + } + } + + j = info.cssAnimations.entrySet().iterator(); + while (j.hasNext()) { + Map.Entry e2 = (Map.Entry) j.next(); + String propertyName = (String) e2.getKey(); + Sandwich sandwich = (Sandwich) e2.getValue(); + if (sandwich.listenerRegistered) { + target.removeTargetListener(null, propertyName, true, + targetListener); + } + } + } + } + + /** + * Pauses the animations. + */ + public void pause() { + if (pauseTime == 0) { + pauseTime = System.currentTimeMillis(); + } + } + + /** + * Unpauses the animations. + */ + public void unpause() { + if (pauseTime != 0) { + Calendar begin = timedDocumentRoot.getDocumentBeginTime(); + int dt = (int) (System.currentTimeMillis() - pauseTime); + begin.add(Calendar.MILLISECOND, dt); + pauseTime = 0; + } + } + + /** + * Returns whether animations are currently paused. + */ + public boolean isPaused() { + return pauseTime != 0; + } + + /** + * Returns the current document time. + */ + public float getCurrentTime() { + return timedDocumentRoot.getCurrentTime(); + } + + /** + * Sets the current document time. + */ + public float setCurrentTime(float t) { + boolean p = pauseTime != 0; + unpause(); + Calendar begin = timedDocumentRoot.getDocumentBeginTime(); + float now = + timedDocumentRoot.convertEpochTime(System.currentTimeMillis()); + begin.add(Calendar.MILLISECOND, (int) ((now - t) * 1000)); + if (p) { + pause(); + } + return tick(t, true); + } + + /** + * Adds an animation to the document. + * @param target the target element of the animation + * @param type the type of animation (must be one of the + * ANIM_TYPE_* constants defined in this class + * @param ns the namespace URI of the attribute being animated, if + * type == {@link #ANIM_TYPE_XML} + * @param an the attribute name if type == {@link + * #ANIM_TYPE_XML}, the property name if type == + * {@link #ANIM_TYPE_CSS}, and the animation type otherwise + * @param anim the animation + */ + public void addAnimation(AnimationTarget target, short type, String ns, + String an, AbstractAnimation anim) { + // org.apache.batik.anim.timing.Trace.enter(this, "addAnimation", new Object[] { target, new Short[type], ns, an, anim } ); try { + timedDocumentRoot.addChild(anim.getTimedElement()); + + AnimationInfo animInfo = getAnimationInfo(anim); + animInfo.type = type; + animInfo.attributeNamespaceURI = ns; + animInfo.attributeLocalName = an; + animInfo.target = target; + animations.put(anim, animInfo); + + Sandwich sandwich = getSandwich(target, type, ns, an); + if (sandwich.animation == null) { + anim.lowerAnimation = null; + anim.higherAnimation = null; + } else { + sandwich.animation.higherAnimation = anim; + anim.lowerAnimation = sandwich.animation; + anim.higherAnimation = null; + } + sandwich.animation = anim; + if (anim.lowerAnimation == null) { + sandwich.lowestAnimation = anim; + } + // } finally { org.apache.batik.anim.timing.Trace.exit(); } + } + + /** + * Removes an animation from the document. + */ + public void removeAnimation(AbstractAnimation anim) { + // org.apache.batik.anim.timing.Trace.enter(this, "removeAnimation", new Object[] { anim } ); try { + timedDocumentRoot.removeChild(anim.getTimedElement()); + AbstractAnimation nextHigher = anim.higherAnimation; + if (nextHigher != null) { + nextHigher.markDirty(); + } + moveToBottom(anim); + if (anim.higherAnimation != null) { + anim.higherAnimation.lowerAnimation = null; + } + AnimationInfo animInfo = getAnimationInfo(anim); + Sandwich sandwich = getSandwich(animInfo.target, animInfo.type, + animInfo.attributeNamespaceURI, + animInfo.attributeLocalName); + if (sandwich.animation == anim) { + sandwich.animation = null; + sandwich.lowestAnimation = null; + sandwich.shouldUpdate = true; + } + // } finally { org.apache.batik.anim.timing.Trace.exit(); } + } + + /** + * Returns the Sandwich for the given animation type/attribute. + */ + protected Sandwich getSandwich(AnimationTarget target, short type, + String ns, String an) { + TargetInfo info = getTargetInfo(target); + Sandwich sandwich; + if (type == ANIM_TYPE_XML) { + sandwich = (Sandwich) info.xmlAnimations.get(ns, an); + if (sandwich == null) { + sandwich = new Sandwich(); + info.xmlAnimations.put(ns, an, sandwich); + } + } else if (type == ANIM_TYPE_CSS) { + sandwich = (Sandwich) info.cssAnimations.get(an); + if (sandwich == null) { + sandwich = new Sandwich(); + info.cssAnimations.put(an, sandwich); + } + } else { + sandwich = (Sandwich) info.otherAnimations.get(an); + if (sandwich == null) { + sandwich = new Sandwich(); + info.otherAnimations.put(an, sandwich); + } + } + return sandwich; + } + + /** + * Returns the TargetInfo for the given AnimationTarget. + */ + protected TargetInfo getTargetInfo(AnimationTarget target) { + TargetInfo info = (TargetInfo) targets.get(target); + if (info == null) { + info = new TargetInfo(); + targets.put(target, info); + } + return info; + } + + /** + * Returns the AnimationInfo for the given AbstractAnimation. + */ + protected AnimationInfo getAnimationInfo(AbstractAnimation anim) { + AnimationInfo info = (AnimationInfo) animations.get(anim); + if (info == null) { + info = new AnimationInfo(); + animations.put(anim, info); + } + return info; + } + + protected static final Map.Entry[] MAP_ENTRY_ARRAY = new Map.Entry[0]; + + /** + * Updates the animations in the document to the given document time. + * @param time the document time to sample at + * @param hyperlinking whether the document should be seeked to the given + * time, as with hyperlinking + */ + protected float tick(float time, boolean hyperlinking) { + float waitTime = timedDocumentRoot.seekTo(time, hyperlinking); + Map.Entry[] targetEntries = + (Map.Entry[]) targets.entrySet().toArray(MAP_ENTRY_ARRAY); + for (int i = 0; i < targetEntries.length; i++) { + Map.Entry e = targetEntries[i]; + AnimationTarget target = (AnimationTarget) e.getKey(); + TargetInfo info = (TargetInfo) e.getValue(); + + // Update the XML animations. + Iterator j = info.xmlAnimations.iterator(); + while (j.hasNext()) { + DoublyIndexedTable.Entry e2 = + (DoublyIndexedTable.Entry) j.next(); + String namespaceURI = (String) e2.getKey1(); + String localName = (String) e2.getKey2(); + Sandwich sandwich = (Sandwich) e2.getValue(); + if (sandwich.shouldUpdate || + sandwich.animation != null + && sandwich.animation.isDirty) { + AnimatableValue av = null; + boolean usesUnderlying = false; + AbstractAnimation anim = sandwich.animation; + if (anim != null) { + av = anim.getComposedValue(); + usesUnderlying = + sandwich.lowestAnimation.usesUnderlyingValue(); + anim.isDirty = false; + } + if (usesUnderlying && !sandwich.listenerRegistered) { + target.addTargetListener(namespaceURI, localName, false, + targetListener); + sandwich.listenerRegistered = true; + } else if (!usesUnderlying && sandwich.listenerRegistered) { + target.removeTargetListener(namespaceURI, localName, + false, targetListener); + sandwich.listenerRegistered = false; + } + target.updateAttributeValue(namespaceURI, localName, av); + sandwich.shouldUpdate = false; + } + } + + // Update the CSS animations. + j = info.cssAnimations.entrySet().iterator(); + while (j.hasNext()) { + Map.Entry e2 = (Map.Entry) j.next(); + String propertyName = (String) e2.getKey(); + Sandwich sandwich = (Sandwich) e2.getValue(); + if (sandwich.shouldUpdate || + sandwich.animation != null + && sandwich.animation.isDirty) { + AnimatableValue av = null; + boolean usesUnderlying = false; + AbstractAnimation anim = sandwich.animation; + if (anim != null) { + av = anim.getComposedValue(); + usesUnderlying = + sandwich.lowestAnimation.usesUnderlyingValue(); + anim.isDirty = false; + } + if (usesUnderlying && !sandwich.listenerRegistered) { + target.addTargetListener(null, propertyName, true, + targetListener); + sandwich.listenerRegistered = true; + } else if (!usesUnderlying && sandwich.listenerRegistered) { + target.removeTargetListener(null, propertyName, true, + targetListener); + sandwich.listenerRegistered = false; + } + if (usesUnderlying) { + target.updatePropertyValue(propertyName, null); + } + if (!(usesUnderlying && av == null)) { + target.updatePropertyValue(propertyName, av); + } + sandwich.shouldUpdate = false; + } + } + + // Update the other animations. + j = info.otherAnimations.entrySet().iterator(); + while (j.hasNext()) { + Map.Entry e2 = (Map.Entry) j.next(); + String type = (String) e2.getKey(); + Sandwich sandwich = (Sandwich) e2.getValue(); + if (sandwich.shouldUpdate || sandwich.animation.isDirty) { + AnimatableValue av = null; + AbstractAnimation anim = sandwich.animation; + if (anim != null) { + av = sandwich.animation.getComposedValue(); + anim.isDirty = false; + } + target.updateOtherValue(type, av); + sandwich.shouldUpdate = false; + } + } + } + return waitTime; + } + + /** + * Invoked to indicate an animation became active at the specified time. + * + * @param anim the animation + * @param begin the time the element became active, in document simple time + */ + public void toActive(AbstractAnimation anim, float begin) { + moveToTop(anim); + anim.isActive = true; + anim.beginTime = begin; + anim.isFrozen = false; + // Move the animation down, in case it began at the same time as another + // animation in the sandwich and it's earlier in document order. + pushDown(anim); + anim.markDirty(); + } + + /** + * Moves the animation down the sandwich such that it is in the right + * position according to begin time and document order. + */ + protected void pushDown(AbstractAnimation anim) { + TimedElement e = anim.getTimedElement(); + AbstractAnimation top = null; + boolean moved = false; + while (anim.lowerAnimation != null + && (anim.lowerAnimation.isActive + || anim.lowerAnimation.isFrozen) + && (anim.lowerAnimation.beginTime > anim.beginTime + || anim.lowerAnimation.beginTime == anim.beginTime + && e.isBefore(anim.lowerAnimation.getTimedElement()))) { + AbstractAnimation higher = anim.higherAnimation; + AbstractAnimation lower = anim.lowerAnimation; + AbstractAnimation lowerLower = lower.lowerAnimation; + if (higher != null) { + higher.lowerAnimation = lower; + } + if (lowerLower != null) { + lowerLower.higherAnimation = anim; + } + lower.lowerAnimation = anim; + lower.higherAnimation = higher; + anim.lowerAnimation = lowerLower; + anim.higherAnimation = lower; + if (!moved) { + top = lower; + moved = true; + } + } + if (moved) { + AnimationInfo animInfo = getAnimationInfo(anim); + Sandwich sandwich = getSandwich(animInfo.target, animInfo.type, + animInfo.attributeNamespaceURI, + animInfo.attributeLocalName); + if (sandwich.animation == anim) { + sandwich.animation = top; + } + if (anim.lowerAnimation == null) { + sandwich.lowestAnimation = anim; + } + } + } + + /** + * Invoked to indicate that this timed element became inactive. + * + * @param anim the animation + * @param isFrozen whether the element is frozen or not + */ + public void toInactive(AbstractAnimation anim, boolean isFrozen) { + anim.isActive = false; + anim.isFrozen = isFrozen; + anim.beginTime = Float.NEGATIVE_INFINITY; + anim.markDirty(); + if (!isFrozen) { + anim.value = null; + moveToBottom(anim); + } else { + pushDown(anim); + } + } + + /** + * Invoked to indicate that this timed element has had its fill removed. + */ + public void removeFill(AbstractAnimation anim) { + anim.isActive = false; + anim.isFrozen = false; + anim.value = null; + anim.markDirty(); + moveToBottom(anim); + } + + /** + * Moves the given animation to the top of the sandwich. + */ + protected void moveToTop(AbstractAnimation anim) { + AnimationInfo animInfo = getAnimationInfo(anim); + Sandwich sandwich = getSandwich(animInfo.target, animInfo.type, + animInfo.attributeNamespaceURI, + animInfo.attributeLocalName); + sandwich.shouldUpdate = true; + if (anim.higherAnimation == null) { + return; + } + if (anim.lowerAnimation == null) { + sandwich.lowestAnimation = anim.higherAnimation; + } else { + anim.lowerAnimation.higherAnimation = anim.higherAnimation; + } + anim.higherAnimation.lowerAnimation = anim.lowerAnimation; + if (sandwich.animation != null) { + sandwich.animation.higherAnimation = anim; + } + anim.lowerAnimation = sandwich.animation; + anim.higherAnimation = null; + sandwich.animation = anim; + } + + /** + * Moves the given animation to the bottom of the sandwich. + */ + protected void moveToBottom(AbstractAnimation anim) { + if (anim.lowerAnimation == null) { + return; + } + AnimationInfo animInfo = getAnimationInfo(anim); + Sandwich sandwich = getSandwich(animInfo.target, animInfo.type, + animInfo.attributeNamespaceURI, + animInfo.attributeLocalName); + AbstractAnimation nextLower = anim.lowerAnimation; + nextLower.markDirty(); + anim.lowerAnimation.higherAnimation = anim.higherAnimation; + if (anim.higherAnimation != null) { + anim.higherAnimation.lowerAnimation = anim.lowerAnimation; + } else { + sandwich.animation = nextLower; + sandwich.shouldUpdate = true; + } + sandwich.lowestAnimation.lowerAnimation = anim; + anim.higherAnimation = sandwich.lowestAnimation; + anim.lowerAnimation = null; + sandwich.lowestAnimation = anim; + if (sandwich.animation.isDirty) { + sandwich.shouldUpdate = true; + } + } + + /** + * Adds a {@link TimegraphListener} to the document. + */ + public void addTimegraphListener(TimegraphListener l) { + timedDocumentRoot.addTimegraphListener(l); + } + + /** + * Removes a {@link TimegraphListener} from the document. + */ + public void removeTimegraphListener(TimegraphListener l) { + timedDocumentRoot.removeTimegraphListener(l); + } + + /** + * Invoked to indicate that this timed element has been sampled at the given + * time. + * + * @param anim the animation + * @param simpleTime the sample time in local simple time + * @param simpleDur the simple duration of the element + * @param repeatIteration the repeat iteration during which the element was + * sampled + */ + public void sampledAt(AbstractAnimation anim, float simpleTime, + float simpleDur, int repeatIteration) { + anim.sampledAt(simpleTime, simpleDur, repeatIteration); + } + + /** + * Invoked to indicate that this timed element has been sampled at the end + * of its active time, at an integer multiple of the simple duration. This + * is the "last" value that will be used for filling, which cannot be + * sampled normally. + */ + public void sampledLastValue(AbstractAnimation anim, int repeatIteration) { + anim.sampledLastValue(repeatIteration); + } + + /** + * Creates a new returns a new TimedDocumentRoot object for the document. + */ + protected abstract TimedDocumentRoot createDocumentRoot(); + + /** + * Listener class for changes to base values on a target element. + */ + protected class Listener implements AnimationTargetListener { + + /** + * Invoked to indicate that base value of the specified attribute + * or property has changed. + */ + public void baseValueChanged(AnimationTarget t, String ns, String ln, + boolean isCSS) { + short type = isCSS ? ANIM_TYPE_CSS : ANIM_TYPE_XML; + Sandwich sandwich = getSandwich(t, type, ns, ln); + sandwich.shouldUpdate = true; + AbstractAnimation anim = sandwich.animation; + while (anim.lowerAnimation != null) { + anim = anim.lowerAnimation; + } + anim.markDirty(); + } + } + + /** + * Class to hold XML and CSS animations for a target element. + */ + protected static class TargetInfo { + + /** + * Map of XML attribute names to the corresponding {@link Sandwich} + * objects. + */ + public DoublyIndexedTable xmlAnimations = new DoublyIndexedTable(); + + /** + * Map of CSS attribute names to the corresponding {@link Sandwich} + * objects. + */ + public HashMap cssAnimations = new HashMap(); + + /** + * Map of other animation types to the corresponding {@link Sandwich} + * objects. + */ + public HashMap otherAnimations = new HashMap(); + } + + /** + * Class to hold an animation sandwich for a particular attribute. + */ + protected static class Sandwich { + + /** + * The top-most animation in the sandwich. + */ + public AbstractAnimation animation; + + /** + * The bottom-most animation in the sandwich. + */ + public AbstractAnimation lowestAnimation; + + /** + * Whether the animation needs to have its value copied into the + * document. + */ + public boolean shouldUpdate; + + /** + * Whether an {@link AnimationTargetListener} has been registered to + * listen for changes to the base value. + */ + public boolean listenerRegistered; + } + + /** + * Class to hold target information of an animation. + */ + protected static class AnimationInfo { + + /** + * The target of the animation. + */ + public AnimationTarget target; + + /** + * The type of animation. Must be one of the ANIM_TYPE_* + * constants defined in {@link AnimationEngine}. + */ + public short type; + + /** + * The namespace URI of the attribute to animate, if this is an XML + * attribute animation. + */ + public String attributeNamespaceURI; + + /** + * The local name of the attribute or the name of the CSS property to + * animate. + */ + public String attributeLocalName; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/AnimationException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/AnimationException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/AnimationException.java 8 Apr 2013 10:55:58 -0000 1.1 @@ -0,0 +1,90 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim; + +import org.apache.batik.anim.timing.TimedElement; + +/** + * An exception class for SMIL animation exceptions. + * + * @author Cameron McCormack + * @version $Id: AnimationException.java,v 1.1 2013/04/08 10:55:58 marcin Exp $ + */ +public class AnimationException extends RuntimeException { + + /** + * The timed element on which the error occurred. + */ + protected TimedElement e; + + /** + * The error code. + */ + protected String code; + + /** + * The parameters to use for the error message. + */ + protected Object[] params; + + /** + * The message. + */ + protected String message; + + /** + * Creates a new AnimationException. + * @param e the animation element on which the error occurred + * @param code the error code + * @param params the parameters to use for the error message + */ + public AnimationException(TimedElement e, String code, Object[] params) { + this.e = e; + this.code = code; + this.params = params; + } + + /** + * Returns the timed element that caused this animation exception. + */ + public TimedElement getElement() { + return e; + } + + /** + * Returns the error code. + */ + public String getCode() { + return code; + } + + /** + * Returns the error message parameters. + */ + public Object[] getParams() { + return params; + } + + /** + * Returns the error message according to the error code and parameters. + */ + public String getMessage() { + return TimedElement.formatMessage(code, params); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/ColorAnimation.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/ColorAnimation.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/ColorAnimation.java 8 Apr 2013 10:55:58 -0000 1.1 @@ -0,0 +1,50 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim; + +import org.apache.batik.anim.timing.TimedElement; +import org.apache.batik.anim.values.AnimatableValue; +import org.apache.batik.dom.anim.AnimatableElement; + +/** + * An animation class for 'animateColor' animations. + * + * @author Cameron McCormack + * @version $Id: ColorAnimation.java,v 1.1 2013/04/08 10:55:58 marcin Exp $ + */ +public class ColorAnimation extends SimpleAnimation { + + /** + * Creates a new ColorAnimation. + */ + public ColorAnimation(TimedElement timedElement, + AnimatableElement animatableElement, + int calcMode, + float[] keyTimes, + float[] keySplines, + boolean additive, + boolean cumulative, + AnimatableValue[] values, + AnimatableValue from, + AnimatableValue to, + AnimatableValue by) { + super(timedElement, animatableElement, calcMode, keyTimes, keySplines, + additive, cumulative, values, from, to, by); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/InterpolatingAnimation.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/InterpolatingAnimation.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/InterpolatingAnimation.java 8 Apr 2013 10:55:58 -0000 1.1 @@ -0,0 +1,167 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim; + +import org.apache.batik.anim.timing.TimedElement; +import org.apache.batik.dom.anim.AnimatableElement; +import org.apache.batik.ext.awt.geom.Cubic; +import org.apache.batik.util.SMILConstants; + +/** + * An abstract animation class for those animations that interpolate + * values. Specifically, this is for animations that have the 'calcMode', + * 'keyTimes', 'keySplines', 'additive' and 'cumulative' attributes. + * + * @author Cameron McCormack + * @version $Id: InterpolatingAnimation.java,v 1.1 2013/04/08 10:55:58 marcin Exp $ + */ +public abstract class InterpolatingAnimation extends AbstractAnimation { + + /** + * The interpolation mode of this animator. This should take one + * of the CALC_MODE_* constants defined in {@link AbstractAnimation}. + */ + protected int calcMode; + + /** + * Time values to control the pacing of the animation. + */ + protected float[] keyTimes; + + /** + * Bezier control points that control the pacing of the animation. + */ + protected float[] keySplines; + + /** + * Cubics built from the bezier control points in {@link #keySplines}. + */ + protected Cubic[] keySplineCubics; + + /** + * Whether this animation adds to ones below it in the animation sandwich + * or replaces them. + */ + protected boolean additive; + + /** + * Whether this animation accumulates from previous iterations. + */ + protected boolean cumulative; + + /** + * Creates a new InterpolatingAnimation. + */ + public InterpolatingAnimation(TimedElement timedElement, + AnimatableElement animatableElement, + int calcMode, + float[] keyTimes, + float[] keySplines, + boolean additive, + boolean cumulative) { + super(timedElement, animatableElement); + this.calcMode = calcMode; + this.keyTimes = keyTimes; + this.keySplines = keySplines; + this.additive = additive; + this.cumulative = cumulative; + + if (calcMode == CALC_MODE_SPLINE) { + if (keySplines == null || keySplines.length % 4 != 0) { + throw timedElement.createException + ("attribute.malformed", + new Object[] { null, + SMILConstants.SMIL_KEY_SPLINES_ATTRIBUTE }); + } + keySplineCubics = new Cubic[keySplines.length / 4]; + for (int i = 0; i < keySplines.length / 4; i++) { + keySplineCubics[i] = new Cubic(0, 0, + keySplines[i * 4], + keySplines[i * 4 + 1], + keySplines[i * 4 + 2], + keySplines[i * 4 + 3], + 1, 1); + } + } + + if (keyTimes != null) { + boolean invalidKeyTimes = false; + if ((calcMode == CALC_MODE_LINEAR || calcMode == CALC_MODE_SPLINE + || calcMode == CALC_MODE_PACED) + && (keyTimes.length < 2 + || keyTimes[0] != 0 + || keyTimes[keyTimes.length - 1] != 1) + || calcMode == CALC_MODE_DISCRETE + && (keyTimes.length == 0 || keyTimes[0] != 0)) { + invalidKeyTimes = true; + } + if (!invalidKeyTimes) { + for (int i = 1; i < keyTimes.length; i++) { + if (keyTimes[i] < 0 || keyTimes[1] > 1 + || keyTimes[i] < keyTimes[i - 1]) { + invalidKeyTimes = true; + break; + } + } + } + if (invalidKeyTimes) { + throw timedElement.createException + ("attribute.malformed", + new Object[] { null, + SMILConstants.SMIL_KEY_TIMES_ATTRIBUTE }); + } + } + } + + /** + * Returns whether this animation will replace values on animations + * lower in the sandwich. + */ + protected boolean willReplace() { + return !additive; + } + + /** + * Called when the element is sampled for its "last" value. + */ + protected void sampledLastValue(int repeatIteration) { + sampledAtUnitTime(1f, repeatIteration); + } + + /** + * Called when the element is sampled at the given time. + */ + protected void sampledAt(float simpleTime, float simpleDur, + int repeatIteration) { + float unitTime; + if (simpleDur == TimedElement.INDEFINITE) { + unitTime = 0; + } else { + unitTime = simpleTime / simpleDur; + } + sampledAtUnitTime(unitTime, repeatIteration); + } + + /** + * Called when the element is sampled at the given unit time. This updates + * the {@link #value} of the animation if active. + */ + protected abstract void sampledAtUnitTime(float unitTime, + int repeatIteration); +} Index: 3rdParty_sources/batik/org/apache/batik/anim/MotionAnimation.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/MotionAnimation.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/MotionAnimation.java 8 Apr 2013 10:55:58 -0000 1.1 @@ -0,0 +1,331 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim; + +import java.awt.geom.Point2D; + +import org.apache.batik.anim.timing.TimedElement; +import org.apache.batik.anim.values.AnimatableAngleValue; +import org.apache.batik.anim.values.AnimatableMotionPointValue; +import org.apache.batik.anim.values.AnimatableValue; +import org.apache.batik.dom.anim.AnimatableElement; +import org.apache.batik.ext.awt.geom.Cubic; +import org.apache.batik.ext.awt.geom.ExtendedGeneralPath; +import org.apache.batik.ext.awt.geom.ExtendedPathIterator; +import org.apache.batik.ext.awt.geom.PathLength; +import org.apache.batik.util.SMILConstants; + +/** + * An animation class for 'animateMotion' animations. + * + * @author Cameron McCormack + * @version $Id: MotionAnimation.java,v 1.1 2013/04/08 10:55:58 marcin Exp $ + */ +public class MotionAnimation extends InterpolatingAnimation { + + /** + * The path that describes the motion. + */ + protected ExtendedGeneralPath path; + + /** + * The path length calculation object. + */ + protected PathLength pathLength; + + /** + * The points defining the distance along the path that the + * keyTimes apply. + */ + protected float[] keyPoints; + + /** + * Whether automatic rotation should be performed. + */ + protected boolean rotateAuto; + + /** + * Whether the automatic rotation should be reversed. + */ + protected boolean rotateAutoReverse; + + /** + * The angle of rotation (in radians) to use when automatic rotation is + * not being used. + */ + protected float rotateAngle; + + /** + * Creates a new MotionAnimation. + */ + public MotionAnimation(TimedElement timedElement, + AnimatableElement animatableElement, + int calcMode, + float[] keyTimes, + float[] keySplines, + boolean additive, + boolean cumulative, + AnimatableValue[] values, + AnimatableValue from, + AnimatableValue to, + AnimatableValue by, + ExtendedGeneralPath path, + float[] keyPoints, + boolean rotateAuto, + boolean rotateAutoReverse, + float rotateAngle, + short rotateAngleUnit) { + super(timedElement, animatableElement, calcMode, keyTimes, keySplines, + additive, cumulative); + this.rotateAuto = rotateAuto; + this.rotateAutoReverse = rotateAutoReverse; + this.rotateAngle = AnimatableAngleValue.rad(rotateAngle, rotateAngleUnit); + + if (path == null) { + path = new ExtendedGeneralPath(); + if (values == null || values.length == 0) { + if (from != null) { + AnimatableMotionPointValue fromPt = (AnimatableMotionPointValue) from; + float x = fromPt.getX(); + float y = fromPt.getY(); + path.moveTo(x, y); + if (to != null) { + AnimatableMotionPointValue toPt = (AnimatableMotionPointValue) to; + path.lineTo(toPt.getX(), toPt.getY()); + } else if (by != null) { + AnimatableMotionPointValue byPt = (AnimatableMotionPointValue) by; + path.lineTo(x + byPt.getX(), y + byPt.getY()); + } else { + throw timedElement.createException + ("values.to.by.path.missing", + new Object[] { null }); + } + } else { + if (to != null) { + AnimatableMotionPointValue unPt = (AnimatableMotionPointValue) + animatableElement.getUnderlyingValue(); + AnimatableMotionPointValue toPt = (AnimatableMotionPointValue) to; + path.moveTo(unPt.getX(), unPt.getY()); + path.lineTo(toPt.getX(), toPt.getY()); + this.cumulative = false; + } else if (by != null) { + AnimatableMotionPointValue byPt = (AnimatableMotionPointValue) by; + path.moveTo(0, 0); + path.lineTo(byPt.getX(), byPt.getY()); + this.additive = true; + } else { + throw timedElement.createException + ("values.to.by.path.missing", + new Object[] { null }); + } + } + } else { + AnimatableMotionPointValue pt = (AnimatableMotionPointValue) values[0]; + path.moveTo(pt.getX(), pt.getY()); + for (int i = 1; i < values.length; i++) { + pt = (AnimatableMotionPointValue) values[i]; + path.lineTo(pt.getX(), pt.getY()); + } + } + } + this.path = path; + pathLength = new PathLength(path); + int segments = 0; + ExtendedPathIterator epi = path.getExtendedPathIterator(); + while (!epi.isDone()) { + int type = epi.currentSegment(); + if (type != ExtendedPathIterator.SEG_MOVETO) { + segments++; + } + epi.next(); + } + + int count = keyPoints == null ? segments + 1 : keyPoints.length; + float totalLength = pathLength.lengthOfPath(); + if (this.keyTimes != null && calcMode != CALC_MODE_PACED) { + if (this.keyTimes.length != count) { + throw timedElement.createException + ("attribute.malformed", + new Object[] { null, + SMILConstants.SMIL_KEY_TIMES_ATTRIBUTE }); + } + } else { + if (calcMode == CALC_MODE_LINEAR || calcMode == CALC_MODE_SPLINE) { + this.keyTimes = new float[count]; + for (int i = 0; i < count; i++) { + this.keyTimes[i] = (float) i / (count - 1); + } + } else if (calcMode == CALC_MODE_DISCRETE) { + this.keyTimes = new float[count]; + for (int i = 0; i < count; i++) { + this.keyTimes[i] = (float) i / count; + } + } else { // CALC_MODE_PACED + // This corrects the keyTimes to be paced, so from now on + // it can be considered the same as CALC_MODE_LINEAR. + epi = path.getExtendedPathIterator(); + this.keyTimes = new float[count]; + int j = 0; + for (int i = 0; i < count - 1; i++) { + while (epi.currentSegment() == + ExtendedPathIterator.SEG_MOVETO) { + j++; + epi.next(); + } + this.keyTimes[i] = + pathLength.getLengthAtSegment(j) / totalLength; + j++; + epi.next(); + } + this.keyTimes[count - 1] = 1f; + } + } + + if (keyPoints != null) { + if (keyPoints.length != this.keyTimes.length) { + throw timedElement.createException + ("attribute.malformed", + new Object[] { null, + SMILConstants.SMIL_KEY_POINTS_ATTRIBUTE }); + } + } else { + epi = path.getExtendedPathIterator(); + keyPoints = new float[count]; + int j = 0; + for (int i = 0; i < count - 1; i++) { + while (epi.currentSegment() == + ExtendedPathIterator.SEG_MOVETO) { + j++; + epi.next(); + } + keyPoints[i] = pathLength.getLengthAtSegment(j) / totalLength; + j++; + epi.next(); + } + keyPoints[count - 1] = 1f; + } + this.keyPoints = keyPoints; + } + + /** + * Called when the element is sampled at the given unit time. This updates + * the {@link #value} of the animation if active. + */ + protected void sampledAtUnitTime(float unitTime, int repeatIteration) { + AnimatableValue value, accumulation; + float interpolation = 0; + if (unitTime != 1) { + int keyTimeIndex = 0; + while (keyTimeIndex < keyTimes.length - 1 + && unitTime >= keyTimes[keyTimeIndex + 1]) { + keyTimeIndex++; + } + if (keyTimeIndex == keyTimes.length - 1 && calcMode == CALC_MODE_DISCRETE) { + keyTimeIndex = keyTimes.length - 2; + interpolation = 1; + } else { + if (calcMode == CALC_MODE_LINEAR || calcMode == CALC_MODE_PACED + || calcMode == CALC_MODE_SPLINE) { + if (unitTime == 0) { + interpolation = 0; + } else { + interpolation = (unitTime - keyTimes[keyTimeIndex]) + / (keyTimes[keyTimeIndex + 1] - keyTimes[keyTimeIndex]); + } + if (calcMode == CALC_MODE_SPLINE && unitTime != 0) { + // XXX This could be done better, e.g. with + // Newton-Raphson. + Cubic c = keySplineCubics[keyTimeIndex]; + float tolerance = 0.001f; + float min = 0; + float max = 1; + Point2D.Double p; + for (;;) { + float t = (min + max) / 2; + p = c.eval(t); + double x = p.getX(); + if (Math.abs(x - interpolation) < tolerance) { + break; + } + if (x < interpolation) { + min = t; + } else { + max = t; + } + } + interpolation = (float) p.getY(); + } + } + } + float point = keyPoints[keyTimeIndex]; + if (interpolation != 0) { + point += interpolation * + (keyPoints[keyTimeIndex + 1] - keyPoints[keyTimeIndex]); + } + point *= pathLength.lengthOfPath(); + Point2D p = pathLength.pointAtLength(point); + float ang; + if (rotateAuto) { + ang = pathLength.angleAtLength(point); + if (rotateAutoReverse) { + ang += Math.PI; + } + } else { + ang = rotateAngle; + } + value = new AnimatableMotionPointValue(null, (float) p.getX(), + (float) p.getY(), ang); + } else { + Point2D p = pathLength.pointAtLength(pathLength.lengthOfPath()); + float ang; + if (rotateAuto) { + ang = pathLength.angleAtLength(pathLength.lengthOfPath()); + if (rotateAutoReverse) { + ang += Math.PI; + } + } else { + ang = rotateAngle; + } + value = new AnimatableMotionPointValue(null, (float) p.getX(), + (float) p.getY(), ang); + } + if (cumulative) { + Point2D p = pathLength.pointAtLength(pathLength.lengthOfPath()); + float ang; + if (rotateAuto) { + ang = pathLength.angleAtLength(pathLength.lengthOfPath()); + if (rotateAutoReverse) { + ang += Math.PI; + } + } else { + ang = rotateAngle; + } + accumulation = new AnimatableMotionPointValue(null, (float) p.getX(), + (float) p.getY(), ang); + } else { + accumulation = null; + } + + this.value = value.interpolate(this.value, null, interpolation, + accumulation, repeatIteration); + if (this.value.hasChanged()) { + markDirty(); + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/SetAnimation.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/SetAnimation.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/SetAnimation.java 8 Apr 2013 10:55:58 -0000 1.1 @@ -0,0 +1,68 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim; + +import org.apache.batik.anim.values.AnimatableValue; +import org.apache.batik.anim.timing.TimedElement; +import org.apache.batik.dom.anim.AnimatableElement; + +/** + * An animation class for 'set' animations. + * + * @author Cameron McCormack + * @version $Id: SetAnimation.java,v 1.1 2013/04/08 10:55:58 marcin Exp $ + */ +public class SetAnimation extends AbstractAnimation { + + /** + * The set animation value. + */ + protected AnimatableValue to; + + /** + * Creates a new SetAnimation. + */ + public SetAnimation(TimedElement timedElement, + AnimatableElement animatableElement, + AnimatableValue to) { + super(timedElement, animatableElement); + this.to = to; + } + + /** + * Called when the element is sampled at the given time. + */ + protected void sampledAt(float simpleTime, float simpleDur, + int repeatIteration) { + if (value == null) { + value = to; + markDirty(); + } + } + + /** + * Called when the element is sampled for its "last" value. + */ + protected void sampledLastValue(int repeatIteration) { + if (value == null) { + value = to; + markDirty(); + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/SimpleAnimation.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/SimpleAnimation.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/SimpleAnimation.java 8 Apr 2013 10:55:58 -0000 1.1 @@ -0,0 +1,221 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim; + +import java.awt.geom.Point2D; + +import org.apache.batik.anim.timing.TimedElement; +import org.apache.batik.anim.values.AnimatableValue; +import org.apache.batik.dom.anim.AnimatableElement; +import org.apache.batik.ext.awt.geom.Cubic; +import org.apache.batik.util.SMILConstants; + +/** + * An animation class for 'animate' animations. + * + * @author Cameron McCormack + * @version $Id: SimpleAnimation.java,v 1.1 2013/04/08 10:55:58 marcin Exp $ + */ +public class SimpleAnimation extends InterpolatingAnimation { + + /** + * Values between which to interpolate. + */ + protected AnimatableValue[] values; + + /** + * Starting value of the animation. + */ + protected AnimatableValue from; + + /** + * Ending value of the animation. + */ + protected AnimatableValue to; + + /** + * Relative offset value for the animation. + */ + protected AnimatableValue by; + + /** + * Creates a new SimpleAnimation. + */ + public SimpleAnimation(TimedElement timedElement, + AnimatableElement animatableElement, + int calcMode, + float[] keyTimes, + float[] keySplines, + boolean additive, + boolean cumulative, + AnimatableValue[] values, + AnimatableValue from, + AnimatableValue to, + AnimatableValue by) { + super(timedElement, animatableElement, calcMode, keyTimes, keySplines, + additive, cumulative); + this.from = from; + this.to = to; + this.by = by; + + if (values == null) { + if (from != null) { + values = new AnimatableValue[2]; + values[0] = from; + if (to != null) { + values[1] = to; + } else if (by != null) { + values[1] = from.interpolate(null, null, 0f, by, 1); + } else { + throw timedElement.createException + ("values.to.by.missing", new Object[] { null }); + } + } else { + if (to != null) { + values = new AnimatableValue[2]; + values[0] = animatableElement.getUnderlyingValue(); + values[1] = to; + this.cumulative = false; + toAnimation = true; + } else if (by != null) { + this.additive = true; + values = new AnimatableValue[2]; + values[0] = by.getZeroValue(); + values[1] = by; + } else { + throw timedElement.createException + ("values.to.by.missing", new Object[] { null }); + } + } + } + this.values = values; + + if (this.keyTimes != null && calcMode != CALC_MODE_PACED) { + if (this.keyTimes.length != values.length) { + throw timedElement.createException + ("attribute.malformed", + new Object[] { null, + SMILConstants.SMIL_KEY_TIMES_ATTRIBUTE }); + } + } else { + if (calcMode == CALC_MODE_LINEAR || calcMode == CALC_MODE_SPLINE + || calcMode == CALC_MODE_PACED && !values[0].canPace()) { + int count = values.length == 1 ? 2 : values.length; + this.keyTimes = new float[count]; + for (int i = 0; i < count; i++) { + this.keyTimes[i] = (float) i / (count - 1); + } + } else if (calcMode == CALC_MODE_DISCRETE) { + int count = values.length; + this.keyTimes = new float[count]; + for (int i = 0; i < count; i++) { + this.keyTimes[i] = (float) i / count; + } + } else { // CALC_MODE_PACED + // This corrects the keyTimes to be paced, so from now on + // it can be considered the same as CALC_MODE_LINEAR. + int count = values.length; + float[] cumulativeDistances = new float[count]; + cumulativeDistances[0] = 0; + for (int i = 1; i < count; i++) { + cumulativeDistances[i] = cumulativeDistances[i - 1] + + values[i - 1].distanceTo(values[i]); + } + float totalLength = cumulativeDistances[count - 1]; + this.keyTimes = new float[count]; + this.keyTimes[0] = 0; + for (int i = 1; i < count - 1; i++) { + this.keyTimes[i] = cumulativeDistances[i] / totalLength; + } + this.keyTimes[count - 1] = 1; + } + } + + if (calcMode == CALC_MODE_SPLINE + && keySplines.length != (this.keyTimes.length - 1) * 4) { + throw timedElement.createException + ("attribute.malformed", + new Object[] { null, + SMILConstants.SMIL_KEY_SPLINES_ATTRIBUTE }); + } + } + + /** + * Called when the element is sampled at the given unit time. This updates + * the {@link #value} of the animation if active. + */ + protected void sampledAtUnitTime(float unitTime, int repeatIteration) { + AnimatableValue value, accumulation, nextValue; + float interpolation = 0; + if (unitTime != 1) { + int keyTimeIndex = 0; + while (keyTimeIndex < keyTimes.length - 1 + && unitTime >= keyTimes[keyTimeIndex + 1]) { + keyTimeIndex++; + } + value = values[keyTimeIndex]; + if (calcMode == CALC_MODE_LINEAR + || calcMode == CALC_MODE_PACED + || calcMode == CALC_MODE_SPLINE) { + nextValue = values[keyTimeIndex + 1]; + interpolation = (unitTime - keyTimes[keyTimeIndex]) + / (keyTimes[keyTimeIndex + 1] - keyTimes[keyTimeIndex]); + if (calcMode == CALC_MODE_SPLINE && unitTime != 0) { + // XXX This could be done better, e.g. with + // Newton-Raphson. + Cubic c = keySplineCubics[keyTimeIndex]; + float tolerance = 0.001f; + float min = 0; + float max = 1; + Point2D.Double p; + for (;;) { + float t = (min + max) / 2; + p = c.eval(t); + double x = p.getX(); + if (Math.abs(x - interpolation) < tolerance) { + break; + } + if (x < interpolation) { + min = t; + } else { + max = t; + } + } + interpolation = (float) p.getY(); + } + } else { + nextValue = null; + } + } else { + value = values[values.length - 1]; + nextValue = null; + } + if (cumulative) { + accumulation = values[values.length - 1]; + } else { + accumulation = null; + } + + this.value = value.interpolate(this.value, nextValue, interpolation, + accumulation, repeatIteration); + if (this.value.hasChanged()) { + markDirty(); + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/TransformAnimation.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/TransformAnimation.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/TransformAnimation.java 8 Apr 2013 10:55:58 -0000 1.1 @@ -0,0 +1,251 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim; + +import org.apache.batik.anim.timing.TimedElement; +import org.apache.batik.anim.values.AnimatableValue; +import org.apache.batik.anim.values.AnimatableTransformListValue; +import org.apache.batik.dom.anim.AnimatableElement; + +import org.w3c.dom.svg.SVGTransform; + +/** + * An animation class for 'animateTransform' animations. + * + * @author Cameron McCormack + * @version $Id: TransformAnimation.java,v 1.1 2013/04/08 10:55:58 marcin Exp $ + */ +public class TransformAnimation extends SimpleAnimation { + + /** + * The transform type. This should take one of the constants defined + * in {@link org.w3c.dom.svg.SVGTransform}. + */ + protected short type; + + /** + * Time values to control the pacing of the second component of the + * animation. + */ + protected float[] keyTimes2; + + /** + * Time values to control the pacing of the third component of the + * animation. + */ + protected float[] keyTimes3; + + /** + * Creates a new TransformAnimation. + */ + public TransformAnimation(TimedElement timedElement, + AnimatableElement animatableElement, + int calcMode, + float[] keyTimes, + float[] keySplines, + boolean additive, + boolean cumulative, + AnimatableValue[] values, + AnimatableValue from, + AnimatableValue to, + AnimatableValue by, + short type) { + // pretend we didn't get a calcMode="paced", since we need specialised + // behaviour in sampledAtUnitTime. + super(timedElement, animatableElement, + calcMode == CALC_MODE_PACED ? CALC_MODE_LINEAR : calcMode, + calcMode == CALC_MODE_PACED ? null : keyTimes, + keySplines, additive, cumulative, values, from, to, by); + this.calcMode = calcMode; + this.type = type; + + if (calcMode != CALC_MODE_PACED) { + return; + } + + // Determine the equivalent keyTimes for the individual components + // of the transforms for CALC_MODE_PACED. + int count = this.values.length; + float[] cumulativeDistances1; + float[] cumulativeDistances2 = null; + float[] cumulativeDistances3 = null; + switch (type) { + case SVGTransform.SVG_TRANSFORM_ROTATE: + cumulativeDistances3 = new float[count]; + cumulativeDistances3[0] = 0f; + // fall through + case SVGTransform.SVG_TRANSFORM_SCALE: + case SVGTransform.SVG_TRANSFORM_TRANSLATE: + cumulativeDistances2 = new float[count]; + cumulativeDistances2[0] = 0f; + // fall through + default: + cumulativeDistances1 = new float[count]; + cumulativeDistances1[0] = 0f; + } + + for (int i = 1; i < this.values.length; i++) { + switch (type) { + case SVGTransform.SVG_TRANSFORM_ROTATE: + cumulativeDistances3[i] = + cumulativeDistances3[i - 1] + + ((AnimatableTransformListValue) + this.values[i - 1]).distanceTo3(this.values[i]); + // fall through + case SVGTransform.SVG_TRANSFORM_SCALE: + case SVGTransform.SVG_TRANSFORM_TRANSLATE: + cumulativeDistances2[i] = + cumulativeDistances2[i - 1] + + ((AnimatableTransformListValue) + this.values[i - 1]).distanceTo2(this.values[i]); + // fall through + default: + cumulativeDistances1[i] = + cumulativeDistances1[i - 1] + + ((AnimatableTransformListValue) + this.values[i - 1]).distanceTo1(this.values[i]); + } + } + + switch (type) { + case SVGTransform.SVG_TRANSFORM_ROTATE: + float totalLength = cumulativeDistances3[count - 1]; + keyTimes3 = new float[count]; + keyTimes3[0] = 0f; + for (int i = 1; i < count - 1; i++) { + keyTimes3[i] = cumulativeDistances3[i] / totalLength; + } + keyTimes3[count - 1] = 1f; + // fall through + case SVGTransform.SVG_TRANSFORM_SCALE: + case SVGTransform.SVG_TRANSFORM_TRANSLATE: + totalLength = cumulativeDistances2[count - 1]; + keyTimes2 = new float[count]; + keyTimes2[0] = 0f; + for (int i = 1; i < count - 1; i++) { + keyTimes2[i] = cumulativeDistances2[i] / totalLength; + } + keyTimes2[count - 1] = 1f; + // fall through + default: + totalLength = cumulativeDistances1[count - 1]; + this.keyTimes = new float[count]; + this.keyTimes[0] = 0f; + for (int i = 1; i < count - 1; i++) { + this.keyTimes[i] = cumulativeDistances1[i] / totalLength; + } + this.keyTimes[count - 1] = 1f; + } + } + + /** + * Called when the element is sampled at the given unit time. This updates + * the {@link #value} of the animation if active. + */ + protected void sampledAtUnitTime(float unitTime, int repeatIteration) { + // Note that skews are handled by SimpleAnimation and not here, since + // they need just the one component of interpolation. + if (calcMode != CALC_MODE_PACED + || type == SVGTransform.SVG_TRANSFORM_SKEWX + || type == SVGTransform.SVG_TRANSFORM_SKEWY) { + super.sampledAtUnitTime(unitTime, repeatIteration); + return; + } + + AnimatableTransformListValue + value1, value2, value3 = null, nextValue1, nextValue2, + nextValue3 = null, accumulation; + float interpolation1 = 0f, interpolation2 = 0f, interpolation3 = 0f; + if (unitTime != 1) { + switch (type) { + case SVGTransform.SVG_TRANSFORM_ROTATE: + int keyTimeIndex = 0; + while (keyTimeIndex < keyTimes3.length - 1 + && unitTime >= keyTimes3[keyTimeIndex + 1]) { + keyTimeIndex++; + } + value3 = (AnimatableTransformListValue) + this.values[keyTimeIndex]; + nextValue3 = (AnimatableTransformListValue) + this.values[keyTimeIndex + 1]; + interpolation3 = (unitTime - keyTimes3[keyTimeIndex]) + / (keyTimes3[keyTimeIndex + 1] - + keyTimes3[keyTimeIndex]); + // fall through + default: + keyTimeIndex = 0; + while (keyTimeIndex < keyTimes2.length - 1 + && unitTime >= keyTimes2[keyTimeIndex + 1]) { + keyTimeIndex++; + } + value2 = (AnimatableTransformListValue) + this.values[keyTimeIndex]; + nextValue2 = (AnimatableTransformListValue) + this.values[keyTimeIndex + 1]; + interpolation2 = (unitTime - keyTimes2[keyTimeIndex]) + / (keyTimes2[keyTimeIndex + 1] - + keyTimes2[keyTimeIndex]); + + keyTimeIndex = 0; + while (keyTimeIndex < keyTimes.length - 1 + && unitTime >= keyTimes[keyTimeIndex + 1]) { + keyTimeIndex++; + } + value1 = (AnimatableTransformListValue) + this.values[keyTimeIndex]; + nextValue1 = (AnimatableTransformListValue) + this.values[keyTimeIndex + 1]; + interpolation1 = (unitTime - keyTimes[keyTimeIndex]) + / (keyTimes[keyTimeIndex + 1] - + keyTimes[keyTimeIndex]); + } + } else { + value1 = value2 = value3 = (AnimatableTransformListValue) + this.values[this.values.length - 1]; + nextValue1 = nextValue2 = nextValue3 = null; + interpolation1 = interpolation2 = interpolation3 = 1f; + } + if (cumulative) { + accumulation = (AnimatableTransformListValue) + this.values[this.values.length - 1]; + } else { + accumulation = null; + } + + switch (type) { + case SVGTransform.SVG_TRANSFORM_ROTATE: + this.value = AnimatableTransformListValue.interpolate + ((AnimatableTransformListValue) this.value, value1, value2, + value3, nextValue1, nextValue2, nextValue3, interpolation1, + interpolation2, interpolation3, accumulation, + repeatIteration); + break; + default: + this.value = AnimatableTransformListValue.interpolate + ((AnimatableTransformListValue) this.value, value1, value2, + nextValue1, nextValue2, interpolation1, interpolation2, + accumulation, repeatIteration); + break; + } + + if (this.value.hasChanged()) { + markDirty(); + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/AccesskeyTimingSpecifier.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/AccesskeyTimingSpecifier.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/AccesskeyTimingSpecifier.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,149 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +import org.apache.batik.dom.events.DOMKeyEvent; +import org.apache.batik.dom.events.NodeEventTarget; +import org.apache.batik.util.XMLConstants; + +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.KeyboardEvent; + +/** + * A class to handle SMIL access key timing specifiers. + * + * @author Cameron McCormack + * @version $Id: AccesskeyTimingSpecifier.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class AccesskeyTimingSpecifier + extends EventLikeTimingSpecifier + implements EventListener { + + /** + * The accesskey. + */ + protected char accesskey; + + /** + * Whether this access key specifier uses SVG 1.2 syntax. + */ + protected boolean isSVG12AccessKey; + + /** + * The DOM 3 key name for SVG 1.2 access key specifiers. + */ + protected String keyName; + + /** + * Creates a new AccesskeyTimingSpecifier object using SVG 1.1 + * or SMIL syntax. + */ + public AccesskeyTimingSpecifier(TimedElement owner, boolean isBegin, + float offset, char accesskey) { + super(owner, isBegin, offset); + this.accesskey = accesskey; + } + + /** + * Creates a new AccesskeyTimingSpecifier object using SVG 1.2 syntax. + */ + public AccesskeyTimingSpecifier(TimedElement owner, boolean isBegin, + float offset, String keyName) { + super(owner, isBegin, offset); + this.isSVG12AccessKey = true; + this.keyName = keyName; + } + + /** + * Returns a string representation of this timing specifier. + */ + public String toString() { + if (isSVG12AccessKey) { + return "accessKey(" + keyName + ")" + + (offset != 0 ? super.toString() : ""); + } + return "accesskey(" + accesskey + ")" + + (offset != 0 ? super.toString() : ""); + } + + /** + * Initializes this timing specifier by adding the initial instance time + * to the owner's instance time list or setting up any event listeners. + */ + public void initialize() { + if (isSVG12AccessKey) { + NodeEventTarget eventTarget = + (NodeEventTarget) owner.getRootEventTarget(); + eventTarget.addEventListenerNS + (XMLConstants.XML_EVENTS_NAMESPACE_URI, "keydown", + this, false, null); + } else { + EventTarget eventTarget = owner.getRootEventTarget(); + eventTarget.addEventListener("keypress", this, false); + } + } + + /** + * Deinitializes this timing specifier by removing any event listeners. + */ + public void deinitialize() { + if (isSVG12AccessKey) { + NodeEventTarget eventTarget = + (NodeEventTarget) owner.getRootEventTarget(); + eventTarget.removeEventListenerNS + (XMLConstants.XML_EVENTS_NAMESPACE_URI, "keydown", + this, false); + } else { + EventTarget eventTarget = owner.getRootEventTarget(); + eventTarget.removeEventListener("keypress", this, false); + } + } + + // EventListener ///////////////////////////////////////////////////////// + + /** + * Handles key events fired by the eventbase element. + */ + public void handleEvent(Event e) { + boolean matched; + if (e.getType().charAt(3) == 'p') { + // DOM 2 key draft keypress + DOMKeyEvent evt = (DOMKeyEvent) e; + matched = evt.getCharCode() == accesskey; + } else { + // DOM 3 keydown + KeyboardEvent evt = (KeyboardEvent) e; + matched = evt.getKeyIdentifier().equals(keyName); + } + if (matched) { + owner.eventOccurred(this, e); + } + } + + /** + * Invoked to resolve an event-like timing specifier into an instance time. + */ + public void resolve(Event e) { + float time = owner.getRoot().convertEpochTime(e.getTimeStamp()); + InstanceTime instance = new InstanceTime(this, time + offset, true); + owner.addInstanceTime(instance, isBegin); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/EventLikeTimingSpecifier.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/EventLikeTimingSpecifier.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/EventLikeTimingSpecifier.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,51 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +import org.w3c.dom.events.Event; + +/** + * Abstract class from which all event-like timing specifier classes derive. + * + * @author Cameron McCormack + * @version $Id: EventLikeTimingSpecifier.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public abstract class EventLikeTimingSpecifier extends OffsetTimingSpecifier { + + /** + * Creates a new EventLikeTimingSpecifier object. + */ + public EventLikeTimingSpecifier(TimedElement owner, boolean isBegin, + float offset) { + super(owner, isBegin, offset); + } + + /** + * Returns whether this timing specifier is event-like (i.e., if it is + * an eventbase, accesskey or a repeat timing specifier). + */ + public boolean isEventCondition() { + return true; + } + + /** + * Invoked to resolve an event-like timing specifier into an instance time. + */ + public abstract void resolve(Event e); +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/EventbaseTimingSpecifier.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/EventbaseTimingSpecifier.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/EventbaseTimingSpecifier.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,128 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +import org.apache.batik.dom.events.NodeEventTarget; + +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.EventTarget; + +/** + * A class to handle eventbase SMIL timing specifiers. + * + * @author Cameron McCormack + * @version $Id: EventbaseTimingSpecifier.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class EventbaseTimingSpecifier + extends EventLikeTimingSpecifier + implements EventListener { + + /** + * The ID of the eventbase element. + */ + protected String eventbaseID; + + /** + * The eventbase element. + */ + protected TimedElement eventbase; + + /** + * The eventbase element as an {@link EventTarget}. + */ + protected EventTarget eventTarget; + + /** + * The namespace URI of the event to sync to. + */ + protected String eventNamespaceURI; + + /** + * The type of the event to sync to. + */ + protected String eventType; + + /** + * The animation name of the event to sync to. + */ + protected String eventName; + + /** + * Creates a new EventbaseTimingSpecifier object. + */ + public EventbaseTimingSpecifier(TimedElement owner, boolean isBegin, + float offset, String eventbaseID, + String eventName) { + super(owner, isBegin, offset); + this.eventbaseID = eventbaseID; + this.eventName = eventName; + TimedDocumentRoot root = owner.getRoot(); + this.eventNamespaceURI = root.getEventNamespaceURI(eventName); + this.eventType = root.getEventType(eventName); + if (eventbaseID == null) { + this.eventTarget = owner.getAnimationEventTarget(); + } else { + this.eventTarget = owner.getEventTargetById(eventbaseID); + } + } + + /** + * Returns a string representation of this timing specifier. + */ + public String toString() { + return (eventbaseID == null ? "" : eventbaseID + ".") + eventName + + (offset != 0 ? super.toString() : ""); + } + + /** + * Initializes this timing specifier by adding the initial instance time + * to the owner's instance time list or setting up any event listeners. + */ + public void initialize() { + ((NodeEventTarget) eventTarget).addEventListenerNS + (eventNamespaceURI, eventType, this, false, null); + } + + /** + * Deinitializes this timing specifier by removing any event listeners. + */ + public void deinitialize() { + ((NodeEventTarget) eventTarget).removeEventListenerNS + (eventNamespaceURI, eventType, this, false); + } + + // EventListener ///////////////////////////////////////////////////////// + + /** + * Handles an event fired on the eventbase element. + */ + public void handleEvent(Event e) { + owner.eventOccurred(this, e); + } + + /** + * Invoked to resolve an event-like timing specifier into an instance time. + */ + public void resolve(Event e) { + float time = owner.getRoot().convertEpochTime(e.getTimeStamp()); + InstanceTime instance = new InstanceTime(this, time + offset, true); + owner.addInstanceTime(instance, isBegin); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/IndefiniteTimingSpecifier.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/IndefiniteTimingSpecifier.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/IndefiniteTimingSpecifier.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,64 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +/** + * A class to handle the 'indefinite' SMIL timing specifier. + * + * @author Cameron McCormack + * @version $Id: IndefiniteTimingSpecifier.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class IndefiniteTimingSpecifier extends TimingSpecifier { + + /** + * Creates a new IndefiniteTimingSpecifier object. + */ + public IndefiniteTimingSpecifier(TimedElement owner, boolean isBegin) { + super(owner, isBegin); + } + + /** + * Returns a string representation of this timing specifier. + */ + public String toString() { + return "indefinite"; + } + + /** + * Initializes this timing specifier by adding the initial instance time + * to the owner's instance time list or setting up any event listeners. + */ + public void initialize() { + if (!isBegin) { + // Only end instance lists get an 'indefinite' instance time from + // an indefinite timing specifier. + InstanceTime instance = + new InstanceTime(this, TimedElement.INDEFINITE, false); + owner.addInstanceTime(instance, isBegin); + } + } + + /** + * Returns whether this timing specifier is event-like (i.e., if it is + * an eventbase, accesskey or a repeat timing specifier). + */ + public boolean isEventCondition() { + return false; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/InstanceTime.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/InstanceTime.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/InstanceTime.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,117 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +/** + * A class that represents an instance time created from a timing + * specification. + * + * @author Cameron McCormack + * @version $Id: InstanceTime.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class InstanceTime implements Comparable { + + /** + * The time. + */ + protected float time; + + /** + * The {@link TimingSpecifier} that created this InstanceTime. + */ + protected TimingSpecifier creator; + + /** + * Whether this InstanceTime should be removed from an element's + * begin or end instance time lists upon reset. + */ + protected boolean clearOnReset; + + /** + * Creates a new InstanceTime. + * @param creator the TimingSpecifier that created this InstanceTime + * @param time the new time, in parent simple time + * @param clearOnReset whether this InstanceTime should be removed from + * an instance time list upon element reset + */ + public InstanceTime(TimingSpecifier creator, + float time, + boolean clearOnReset) { + // Trace.enter(this, null, new Object[] { creator, new Float(time), timebase, new Boolean(clearOnReset) } ); try { + this.creator = creator; + // XXX Convert time from the creator's syncbase's + // time system into this time system. Not + // strictly necessary in SVG. + this.time = time; + this.clearOnReset = clearOnReset; + // } finally { Trace.exit(); } + } + + /** + * Returns whether the InstanceTime should be removed from the + * element's begin or end instance time list when it is reset. + */ + public boolean getClearOnReset() { + return clearOnReset; + } + + /** + * Returns the time of this instance time. + */ + public float getTime() { + return time; + } + + /** + * Called by the dependent Interval to indicate that its time + * has changed. + * @param newTime the new time, in parent simple time + */ + float dependentUpdate(float newTime) { + // Trace.enter(this, "dependentUpdate", new Object[] { new Float(newTime) } ); try { + // XXX Convert time from the creator's syncbase's + // time system into this time system. Not + // strictly necessary in SVG. + time = newTime; + if (creator != null) { + return creator.handleTimebaseUpdate(this, time); + } + return Float.POSITIVE_INFINITY; + // } finally { Trace.exit(); } + } + + /** + * Returns a string representation of this InstanceTime. + */ + public String toString() { + return Float.toString(time); + } + + // Comparable //////////////////////////////////////////////////////////// + + /** + * Compares this InstanceTime with another. + */ + public int compareTo(Object o) { + InstanceTime it = (InstanceTime)o; + if (time == it.time) return 0; + if (time > it.time) return 1; + return -1; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/Interval.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/Interval.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/Interval.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,184 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +import java.util.Iterator; +import java.util.LinkedList; + +/** + * A class that represents an interval for a timed element. + * + * @author Cameron McCormack + * @version $Id: Interval.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class Interval { + + /** + * The begin time for the interval. + */ + protected float begin; + + /** + * The end time for the interval. + */ + protected float end; + + /** + * The InstanceTime that defined the begin time of the current interval. + */ + protected InstanceTime beginInstanceTime; + + /** + * The InstanceTime that defined the end time of the current interval. + */ + protected InstanceTime endInstanceTime; + + /** + * The list of {@link InstanceTime} objects that are dependent + * on the begin time of this Interval. + */ + protected LinkedList beginDependents = new LinkedList(); + + /** + * The list of {@link InstanceTime} objects that are dependent + * on the end time of this Interval. + */ + protected LinkedList endDependents = new LinkedList(); + + /** + * Creates a new Interval. + * @param begin the begin time of the Interval + * @param end the end time of the Interval + * @param beginInstanceTime the {@link InstanceTime} object that defined + * the begin time of the Interval + * @param endInstanceTime the {@link InstanceTime} object that defined + * the end time of the Interval + */ + public Interval(float begin, float end, InstanceTime beginInstanceTime, + InstanceTime endInstanceTime) { + // Trace.enter(this, null, new Object[] { new Float(begin), new Float(end), beginInstanceTime, endInstanceTime } ); try { + this.begin = begin; + this.end = end; + this.beginInstanceTime = beginInstanceTime; + this.endInstanceTime = endInstanceTime; + // } finally { Trace.exit(); } + } + + /** + * Returns a string representation of this Interval. + */ + public String toString() { + return TimedElement.toString(begin) + ".." + TimedElement.toString(end); + } + + /** + * Returns the begin time of this interval. + */ + public float getBegin() { + return begin; + } + + /** + * Returns the end time of this interval. + */ + public float getEnd() { + return end; + } + + /** + * Returns the {@link InstanceTime} that defined the begin time of this + * interval. + */ + public InstanceTime getBeginInstanceTime() { + return beginInstanceTime; + } + + /** + * Returns the {@link InstanceTime} that defined the end time of this + * interval. + */ + public InstanceTime getEndInstanceTime() { + return endInstanceTime; + } + + /** + * Adds a dependent InstanceTime for this Interval. + */ + void addDependent(InstanceTime dependent, boolean forBegin) { + // Trace.enter(this, "addDependent", new Object[] { dependent, new Boolean(forBegin) } ); try { + if (forBegin) { + beginDependents.add(dependent); + } else { + endDependents.add(dependent); + } + // } finally { Trace.exit(); } + } + + /** + * Removes a dependent InstanceTime for this Interval. + */ + void removeDependent(InstanceTime dependent, boolean forBegin) { + // Trace.enter(this, "removeDependent", new Object[] { dependent, new Boolean(forBegin) } ); try { + if (forBegin) { + beginDependents.remove(dependent); + } else { + endDependents.remove(dependent); + } + // } finally { Trace.exit(); } + } + + /** + * Updates the begin time for this interval. + */ + float setBegin(float begin) { + // Trace.enter(this, "setBegin", new Object[] { new Float(begin) } ); try { + float minTime = Float.POSITIVE_INFINITY; + this.begin = begin; + Iterator i = beginDependents.iterator(); + while (i.hasNext()) { + InstanceTime it = (InstanceTime) i.next(); + float t = it.dependentUpdate(begin); + if (t < minTime) { + minTime = t; + } + } + return minTime; + // } finally { Trace.exit(); } + } + + /** + * Updates the end time for this interval. + */ + float setEnd(float end, InstanceTime endInstanceTime) { + // Trace.enter(this, "setEnd", new Object[] { new Float(end) } ); try { + float minTime = Float.POSITIVE_INFINITY; + this.end = end; + this.endInstanceTime = endInstanceTime; + Iterator i = endDependents.iterator(); + while (i.hasNext()) { + InstanceTime it = (InstanceTime) i.next(); + float t = it.dependentUpdate(end); + if (t < minTime) { + minTime = t; + } + } + return minTime; + // } finally { Trace.exit(); } + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/MediaMarkerTimingSpecifier.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/MediaMarkerTimingSpecifier.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/MediaMarkerTimingSpecifier.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,75 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +/** + * A class to handle media marker SMIL timing specifiers. This class + * of timing specifier is currently unused. + * + * @author Cameron McCormack + * @version $Id: MediaMarkerTimingSpecifier.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class MediaMarkerTimingSpecifier extends TimingSpecifier { + + /** + * The ID of the media element. + */ + protected String syncbaseID; + + /** + * The media element. + */ + protected TimedElement mediaElement; + + /** + * The media marker name. + */ + protected String markerName; + + /** + * The instance time. + */ + protected InstanceTime instance; + + /** + * Creates a new MediaMarkerTimingSpecifier object. + */ + public MediaMarkerTimingSpecifier(TimedElement owner, boolean isBegin, + String syncbaseID, String markerName) { + super(owner, isBegin); + this.syncbaseID = syncbaseID; + this.markerName = markerName; + this.mediaElement = owner.getTimedElementById(syncbaseID); + } + + /** + * Returns a string representation of this timing specifier. + */ + public String toString() { + return syncbaseID + ".marker(" + markerName + ")"; + } + + /** + * Returns whether this timing specifier is event-like (i.e., if it is + * an eventbase, accesskey or a repeat timing specifier). + */ + public boolean isEventCondition() { + return false; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/OffsetTimingSpecifier.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/OffsetTimingSpecifier.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/OffsetTimingSpecifier.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,66 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +/** + * A class to handle offset SMIL timing specifiers. + * + * @author Cameron McCormack + * @version $Id: OffsetTimingSpecifier.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class OffsetTimingSpecifier extends TimingSpecifier { + + /** + * The offset value. + */ + protected float offset; + + /** + * Creates a new OffsetTimingSpecifier object. + */ + public OffsetTimingSpecifier(TimedElement owner, boolean isBegin, + float offset) { + super(owner, isBegin); + this.offset = offset; + } + + /** + * Returns a string representation of this timing specifier. + */ + public String toString() { + return (offset >= 0 ? "+" : "") + offset; + } + + /** + * Initializes this timing specifier by adding the initial instance time + * to the owner's instance time list or setting up any event listeners. + */ + public void initialize() { + InstanceTime instance = new InstanceTime(this, offset, false); + owner.addInstanceTime(instance, isBegin); + } + + /** + * Returns whether this timing specifier is event-like (i.e., if it is + * an eventbase, accesskey or a repeat timing specifier). + */ + public boolean isEventCondition() { + return false; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/RepeatTimingSpecifier.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/RepeatTimingSpecifier.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/RepeatTimingSpecifier.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,83 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +import org.w3c.dom.events.Event; +import org.w3c.dom.smil.TimeEvent; + +/** + * A class to handle repeat event SMIL timing specifiers. + * + * @author Cameron McCormack + * @version $Id: RepeatTimingSpecifier.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class RepeatTimingSpecifier extends EventbaseTimingSpecifier { + + /** + * The repeat iteration. + */ + protected int repeatIteration; + + /** + * Whether a repeat iteration was specified. + */ + protected boolean repeatIterationSpecified; + + /** + * Creates a new RepeatTimingSpecifier object without a repeat iteration. + */ + public RepeatTimingSpecifier(TimedElement owner, boolean isBegin, + float offset, String syncbaseID) { + super(owner, isBegin, offset, syncbaseID, + owner.getRoot().getRepeatEventName()); + } + + /** + * Creates a new RepeatTimingSpecifier object with a repeat iteration. + */ + public RepeatTimingSpecifier(TimedElement owner, boolean isBegin, + float offset, String syncbaseID, + int repeatIteration) { + super(owner, isBegin, offset, syncbaseID, + owner.getRoot().getRepeatEventName()); + this.repeatIteration = repeatIteration; + this.repeatIterationSpecified = true; + } + + /** + * Returns a string representation of this timing specifier. + */ + public String toString() { + return (eventbaseID == null ? "" : eventbaseID + ".") + "repeat" + + (repeatIterationSpecified ? "(" + repeatIteration + ")" : "") + + (offset != 0 ? super.toString() : ""); + } + + // EventListener ///////////////////////////////////////////////////////// + + /** + * Handles an event fired on the eventbase element. + */ + public void handleEvent(Event e) { + TimeEvent evt = (TimeEvent) e; + if (!repeatIterationSpecified || evt.getDetail() == repeatIteration) { + super.handleEvent(e); + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/SyncbaseTimingSpecifier.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/SyncbaseTimingSpecifier.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/SyncbaseTimingSpecifier.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,136 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +import java.lang.ref.WeakReference; +import java.util.HashMap; + +/** + * A class to handle syncbase SMIL timing specifiers. + * + * @author Cameron McCormack + * @version $Id: SyncbaseTimingSpecifier.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class SyncbaseTimingSpecifier extends OffsetTimingSpecifier { + + /** + * The ID of the syncbase element. + */ + protected String syncbaseID; + + /** + * The syncbase element. + */ + protected TimedElement syncbaseElement; + + /** + * Whether this specifier specifies a sync to the begin or the end + * of the syncbase element. + */ + protected boolean syncBegin; + + /** + * Map of {@link Interval}s to an + * {@link InstanceTime}. + */ + protected HashMap instances = new HashMap(); + + /** + * Creates a new SyncbaseTimingSpecifier object. + */ + public SyncbaseTimingSpecifier(TimedElement owner, boolean isBegin, + float offset, String syncbaseID, + boolean syncBegin) { + super(owner, isBegin, offset); + // Trace.enter(this, null, new Object[] { owner, new Boolean(isBegin), new Float(offset), syncbaseID, new Boolean(syncBegin) } ); try { + this.syncbaseID = syncbaseID; + this.syncBegin = syncBegin; + this.syncbaseElement = owner.getTimedElementById(syncbaseID); + syncbaseElement.addDependent(this, syncBegin); + // } finally { Trace.exit(); } + } + + /** + * Returns a string representation of this timing specifier. + */ + public String toString() { + return syncbaseID + "." + (syncBegin ? "begin" : "end") + + (offset != 0 ? super.toString() : ""); + } + + /** + * Initializes this timing specifier by adding the initial instance time + * to the owner's instance time list or setting up any event listeners. + */ + public void initialize() { + } + + /** + * Returns whether this timing specifier is event-like (i.e., if it is + * an eventbase, accesskey or a repeat timing specifier). + */ + public boolean isEventCondition() { + return false; + } + + /** + * Called by the timebase element when it creates a new Interval. + */ + float newInterval(Interval interval) { + // Trace.enter(this, "newInterval", new Object[] { interval } ); try { + if (owner.hasPropagated) { + return Float.POSITIVE_INFINITY; + } + InstanceTime instance = + new InstanceTime(this, (syncBegin ? interval.getBegin() + : interval.getEnd()) + offset, + true); + instances.put(interval, instance); + interval.addDependent(instance, syncBegin); + return owner.addInstanceTime(instance, isBegin); + // } finally { Trace.exit(); } + } + + /** + * Called by the timebase element when it deletes an Interval. + */ + float removeInterval(Interval interval) { + // Trace.enter(this, "removeInterval", new Object[] { interval } ); try { + if (owner.hasPropagated) { + return Float.POSITIVE_INFINITY; + } + InstanceTime instance = (InstanceTime) instances.get(interval); + interval.removeDependent(instance, syncBegin); + return owner.removeInstanceTime(instance, isBegin); + // } finally { Trace.exit(); } + } + + /** + * Called by an {@link InstanceTime} created by this TimingSpecifier + * to indicate that its value has changed. + */ + float handleTimebaseUpdate(InstanceTime instanceTime, float newTime) { + // Trace.enter(this, "handleTimebaseUpdate", new Object[] { instanceTime, new Float(newTime) } ); try { + if (owner.hasPropagated) { + return Float.POSITIVE_INFINITY; + } + return owner.instanceTimeChanged(instanceTime, isBegin); + // } finally { Trace.exit(); } + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/TimeContainer.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/TimeContainer.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/TimeContainer.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,147 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +/** + * An abstract base class for time container elements. + * + * @author Cameron McCormack + * @version $Id: TimeContainer.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public abstract class TimeContainer extends TimedElement { + + /** + * The child {@link TimedElement}s of this time container. + */ + protected List children = new LinkedList(); + + /** + * Adds a {@link TimedElement} to this container. + */ + public void addChild(TimedElement e) { + if (e == this) { + throw new IllegalArgumentException("recursive datastructure not allowed here!"); + } + children.add(e); + e.parent = this; + setRoot(e, root); + root.fireElementAdded(e); + root.currentIntervalWillUpdate(); + } + + /** + * Recursively sets the {@link TimedDocumentRoot} of the given + * {@link TimedElement} and any of its descendants. + */ + protected void setRoot(TimedElement e, TimedDocumentRoot root) { + e.root = root; + if (e instanceof TimeContainer) { + TimeContainer c = (TimeContainer) e; + Iterator it = c.children.iterator(); + while (it.hasNext()) { + TimedElement te = (TimedElement)it.next(); + setRoot(te, root); + } + } + } + + /** + * Removes a {@link TimedElement} from this container. + */ + public void removeChild(TimedElement e) { + children.remove(e); + e.parent = null; + setRoot(e, null); + root.fireElementRemoved(e); + root.currentIntervalWillUpdate(); + } + + /** + * Returns an array of the children of this container. + */ + public TimedElement[] getChildren() { + return (TimedElement[]) children.toArray(new TimedElement[0]); + } + + /** + * Calculates the local simple time. Currently the hyperlinking parameter + * is ignored, so DOM timing events are fired during hyperlinking seeks. + * If we were following SMIL 2.1 rather than SMIL Animation, then these + * events would have to be surpressed. + * + * @return the number of seconds until this element becomes active again + * if it currently is not, {@link Float#POSITIVE_INFINITY} if this + * element will become active at some undetermined point in the + * future (because of unresolved begin times, for example) or + * will never become active again, or 0f if the + * element is currently active. + */ + protected float sampleAt(float parentSimpleTime, boolean hyperlinking) { + super.sampleAt(parentSimpleTime, hyperlinking); + // Maybe check the return value of the previous statement. + return sampleChildren(parentSimpleTime, hyperlinking); + } + + /** + * Samples all the child timed elements. + */ + protected float sampleChildren(float parentSimpleTime, + boolean hyperlinking) { + float mint = Float.POSITIVE_INFINITY; + Iterator i = children.iterator(); + while (i.hasNext()) { + TimedElement e = (TimedElement) i.next(); + float t = e.sampleAt(parentSimpleTime, hyperlinking); + if (t < mint) { + mint = t; + } + } + return mint; + } + + /** + * Resets this element. + */ + protected void reset(boolean clearCurrentBegin) { + super.reset(clearCurrentBegin); + Iterator i = children.iterator(); + while (i.hasNext()) { + TimedElement e = (TimedElement) i.next(); + e.reset(clearCurrentBegin); + } + } + + /** + * Returns whether this timed element is for a constant animation (i.e., a + * 'set' animation. + */ + protected boolean isConstantAnimation() { + return false; + } + + /** + * Returns the default begin time for the given child + * timed element. + */ + public abstract float getDefaultBegin(TimedElement child); +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/TimedDocumentRoot.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/TimedDocumentRoot.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/TimedDocumentRoot.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,288 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +import java.util.Calendar; +import java.util.Iterator; +import java.util.LinkedList; + +import org.apache.batik.util.DoublyIndexedSet; + +/** + * An abstract base class for the root time container element + * for a document. + * + * @author Cameron McCormack + * @version $Id: TimedDocumentRoot.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public abstract class TimedDocumentRoot extends TimeContainer { + + /** + * The wallclock time that the document began. + */ + protected Calendar documentBeginTime; + + /** + * Allows the use of accessKey() timing specifiers with a single + * character, as specified in SVG 1.1. + */ + protected boolean useSVG11AccessKeys; + + /** + * Allows the use of accessKey() timing specifiers with a DOM 3 + * key name, as specified in SVG 1.2. + */ + protected boolean useSVG12AccessKeys; + + /** + * A set to determine when propagation of new Instance times should + * be stopped. + */ + protected DoublyIndexedSet propagationFlags = new DoublyIndexedSet(); + + /** + * List of {link TimegraphListener}s to be notified of changes to the + * timed elements in this document. + */ + protected LinkedList listeners = new LinkedList(); + + /** + * Whether the document is currently being sampled. + */ + protected boolean isSampling; + + /** + * Whether the document is currently being sampled for a hyperlink. + */ + protected boolean isHyperlinking; + + /** + * Creates a new TimedDocumentRoot. + * @param useSVG11AccessKeys allows the use of accessKey() timing + * specifiers with a single character + * @param useSVG12AccessKeys allows the use of accessKey() with a + * DOM 3 key name + */ + public TimedDocumentRoot(boolean useSVG11AccessKeys, + boolean useSVG12AccessKeys) { + root = this; + this.useSVG11AccessKeys = useSVG11AccessKeys; + this.useSVG12AccessKeys = useSVG12AccessKeys; + } + + /** + * Returns the implicit duration of the element. The document root + * has an {@link #INDEFINITE} implicit duration. + */ + protected float getImplicitDur() { + return INDEFINITE; + } + + /** + * Returns the default begin time for the given child + * timed element. In SVG, this is always 0, since the + * only time container is the root SVG element, which acts + * like a 'par'. + */ + public float getDefaultBegin(TimedElement child) { + return 0.0f; + } + + /** + * Returns the last sampled document time. + */ + public float getCurrentTime() { + return lastSampleTime; + } + + /** + * Returns whether the document is currently being sampled. + */ + public boolean isSampling() { + return isSampling; + } + + /** + * Returns whether the document is currently being sampled for a hyperlink. + */ + public boolean isHyperlinking() { + return isHyperlinking; + } + + /** + * Samples the entire timegraph at the given time. + */ + public float seekTo(float time, boolean hyperlinking) { + // Trace.enter(this, "seekTo", new Object[] { new Float(time) } ); try { + isSampling = true; + lastSampleTime = time; + isHyperlinking = hyperlinking; + propagationFlags.clear(); + // No time containers in SVG, so we don't have to worry + // about a partial ordering of timed elements to sample. + float mint = Float.POSITIVE_INFINITY; + TimedElement[] es = getChildren(); + for (int i = 0; i < es.length; i++) { + float t = es[i].sampleAt(time, hyperlinking); + if (t < mint) { + mint = t; + } + } + boolean needsUpdates; + do { + needsUpdates = false; + for (int i = 0; i < es.length; i++) { + if (es[i].shouldUpdateCurrentInterval) { + needsUpdates = true; + // System.err.print("{" + ((Test.AnimateElement) es[i]).id + "} "); + float t = es[i].sampleAt(time, hyperlinking); + if (t < mint) { + mint = t; + } + } + } + } while (needsUpdates); + isSampling = false; + if (hyperlinking) { + root.currentIntervalWillUpdate(); + } + return mint; + // } finally { Trace.exit(); } + } + + /** + * Resets the entire timegraph. + */ + public void resetDocument(Calendar documentBeginTime) { + if (documentBeginTime == null) { + this.documentBeginTime = Calendar.getInstance(); + } else { + this.documentBeginTime = documentBeginTime; + } + reset(true); + } + + /** + * Returns the wallclock time that the document began. + */ + public Calendar getDocumentBeginTime() { + return documentBeginTime; + } + + /** + * Converts an epoch time to document time. + */ + public float convertEpochTime(long t) { + long begin = documentBeginTime.getTime().getTime(); + return (t - begin) / 1000f; + } + + /** + * Converts a wallclock time to document time. + */ + public float convertWallclockTime(Calendar time) { + long begin = documentBeginTime.getTime().getTime(); + long t = time.getTime().getTime(); + return (t - begin) / 1000f; + } + + /** + * Adds a {@link TimegraphListener} to the document. + */ + public void addTimegraphListener(TimegraphListener l) { + listeners.add(l); + } + + /** + * Removes a {@link TimegraphListener} from the document. + */ + public void removeTimegraphListener(TimegraphListener l) { + listeners.remove(l); + } + + /** + * Fires an {@link TimegraphListener#elementAdded} event on all + * timegraph listeners. + */ + void fireElementAdded(TimedElement e) { + Iterator i = listeners.iterator(); + while (i.hasNext()) { + ((TimegraphListener) i.next()).elementAdded(e); + } + } + + /** + * Fires an {@link TimegraphListener#elementRemoved} event on all + * timegraph listeners. + */ + void fireElementRemoved(TimedElement e) { + Iterator i = listeners.iterator(); + while (i.hasNext()) { + ((TimegraphListener) i.next()).elementRemoved(e); + } + } + + // XXX Add fire* methods for the other events in TimegraphListener, and make + // TimedElement fire them. + + /** + * Returns whether the specified newly created {@link Interval} should + * propagate its times to the given {@link TimingSpecifier}. + * @param i the Interval that has just been created + * @param ts the TimingSpecifier that is a dependent of the Interval + * @param isBegin whether the dependency is on the begin or end time of + * the Interval + */ + boolean shouldPropagate(Interval i, TimingSpecifier ts, boolean isBegin) { + InstanceTime it = isBegin ? i.getBeginInstanceTime() + : i.getEndInstanceTime(); + if (propagationFlags.contains(it, ts)) { + return false; + } + propagationFlags.add(it, ts); + return true; + } + + /** + * Invoked by timed elements in this document to indicate that the current + * interval will be re-evaluated at the next sample. This should be + * overridden in a concrete class so that ticks can be scheduled immediately + * if they are currently paused due to no animations being active. + */ + protected void currentIntervalWillUpdate() { + } + + /** + * Returns the namespace URI of the event that corresponds to the given + * animation event name. + */ + protected abstract String getEventNamespaceURI(String eventName); + + /** + * Returns the type of the event that corresponds to the given + * animation event name. + */ + protected abstract String getEventType(String eventName); + + /** + * Returns the name of the repeat event. + * @return either "repeat" or "repeatEvent" + */ + protected abstract String getRepeatEventName(); +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/TimedElement.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/TimedElement.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/TimedElement.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,1575 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +import java.util.*; + +import org.apache.batik.anim.AnimationException; +import org.apache.batik.i18n.LocalizableSupport; +import org.apache.batik.parser.ClockHandler; +import org.apache.batik.parser.ClockParser; +import org.apache.batik.parser.ParseException; +import org.apache.batik.util.SMILConstants; + +import org.w3c.dom.Element; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventTarget; + +/** + * An abstract base class for elements that can have timing applied to them. + * The concrete versions of this class do not necessarily have to be the + * same as the DOM class, and in fact, this will mostly be impossible unless + * creating new DOM classes that inherit from these elements. + * + * @author Cameron McCormack + * @version $Id: TimedElement.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public abstract class TimedElement implements SMILConstants { + + // Constants for fill mode. + public static final int FILL_REMOVE = 0; + public static final int FILL_FREEZE = 1; + + // Constants for restart mode. + public static final int RESTART_ALWAYS = 0; + public static final int RESTART_WHEN_NOT_ACTIVE = 1; + public static final int RESTART_NEVER = 2; + + // Constants for time values. + public static final float INDEFINITE = Float.POSITIVE_INFINITY; + public static final float UNRESOLVED = Float.NaN; + + /** + * The root time container. + */ + protected TimedDocumentRoot root; + + /** + * The parent time container. + */ + protected TimeContainer parent; + + /** + * Timing specifiers for the begin times of this element. + */ + protected TimingSpecifier[] beginTimes; + + /** + * Timing specifiers for the end times of this element. + */ + protected TimingSpecifier[] endTimes; + + /** + * Duration of this element, if {@link #durMedia} = false. + * If unspecified, it will be {@link #UNRESOLVED}. + */ + protected float simpleDur; + + /** + * Whether the simple duration of this element should be equal + * to the implicit duration. + */ + protected boolean durMedia; + + /** + * The number of repeats. If unspecified, it will be + * {@link #UNRESOLVED}. + */ + protected float repeatCount; + + /** + * The duration of repeats. If unspecified, it will be + * {@link #UNRESOLVED}. + */ + protected float repeatDur; + + /** + * The current repeat iteration. + */ + protected int currentRepeatIteration; + + /** + * The local active time of the last repeat. + */ + protected float lastRepeatTime; + + /** + * The fill mode for this element. Uses the FILL_* constants + * defined in this class. + */ + protected int fillMode; + + /** + * The restart mode for this element. Uses the RESTART_* constants + * defined in this class. + */ + protected int restartMode; + + /** + * The minimum active duration of this element. If {@link #minMedia} + * = true, it will be 0f. + */ + protected float min; + + /** + * Whether the min value was specified as 'media'. + */ + protected boolean minMedia; + + /** + * The maximum active duration of this element. If {@link #maxMedia} + * = true, it will be {@link #INDEFINITE}. + */ + protected float max; + + /** + * Whether the max value was specified as 'media'. + */ + protected boolean maxMedia; + + /** + * Whether the element is currently active. + */ + protected boolean isActive; + + /** + * Whether the element is currently frozen. + */ + protected boolean isFrozen; + + /** + * The current time of this element in local active time. + */ + protected float lastSampleTime; + + /** + * The computed repeat duration of the element. + */ + protected float repeatDuration; + + /** + * List of begin InstanceTimes. + */ + protected List beginInstanceTimes = new ArrayList(); + + /** + * List of end InstanceTimes. + */ + protected List endInstanceTimes = new ArrayList(); + + /** + * The current Interval. + */ + protected Interval currentInterval; + + /** + * The end time of the previous interval, initially + * {@link Float#NEGATIVE_INFINITY}. + */ + protected float lastIntervalEnd; + + /** + * List of previous intervals. + */ + // protected LinkedList previousIntervals = new LinkedList(); + + /** + * The previous interval. + */ + protected Interval previousInterval; + + /** + * List of TimingSpecifiers on other elements that depend on this + * element's begin times. + */ + protected LinkedList beginDependents = new LinkedList(); + + /** + * List of TimingSpecifiers on other elements that depend on this + * element's end times. + */ + protected LinkedList endDependents = new LinkedList(); + + /** + * Whether the list of instance times should be checked to update + * the current interval. + */ + protected boolean shouldUpdateCurrentInterval = true; + + /** + * Whether this timed element has parsed its timing attributes yet. + */ + protected boolean hasParsed; + + /** + * Map of {@link Event} objects to {@link HashSet}s of {@link + * TimingSpecifier}s that caught them. + */ + protected Map handledEvents = new HashMap(); + + /** + * Whether this timed element is currently being sampled. + */ + protected boolean isSampling; + + /** + * Whether an instance time update message has already been propagated to + * this timed element. + */ + protected boolean hasPropagated; + + /** + * Creates a new TimedElement. + */ + public TimedElement() { + beginTimes = new TimingSpecifier[0]; + endTimes = beginTimes; + simpleDur = UNRESOLVED; + repeatCount = UNRESOLVED; + repeatDur = UNRESOLVED; + lastRepeatTime = UNRESOLVED; + max = INDEFINITE; + lastSampleTime = UNRESOLVED; + lastIntervalEnd = Float.NEGATIVE_INFINITY; + } + + /** + * Returns the root time container of this timed element. + */ + public TimedDocumentRoot getRoot() { + return root; + } + + /** + * Returns the current active time of this element. + */ + public float getActiveTime() { + return lastSampleTime; + } + + /** + * Returns the current simple time of this element. + */ + public float getSimpleTime() { + return lastSampleTime - lastRepeatTime; + } + + /** + * Called by a TimingSpecifier of this element when a new + * InstanceTime is created. This will be in response to an event + * firing, a DOM method being called or a new Instance being + * created by a syncbase element. + */ + protected float addInstanceTime(InstanceTime time, boolean isBegin) { + // Trace.enter(this, "addInstanceTime", new Object[] { time, new Boolean(isBegin) } ); try { + hasPropagated = true; + List instanceTimes = isBegin ? beginInstanceTimes : endInstanceTimes; + int index = Collections.binarySearch(instanceTimes, time); + if (index < 0) { + index = -(index + 1); + } + instanceTimes.add(index, time); + shouldUpdateCurrentInterval = true; + float ret; + if (root.isSampling() && !isSampling) { + ret = sampleAt(root.getCurrentTime(), root.isHyperlinking()); + } else { + ret = Float.POSITIVE_INFINITY; + } + hasPropagated = false; + root.currentIntervalWillUpdate(); + return ret; + // } finally { Trace.exit(); } + } + + /** + * Called by a TimingSpecifier of this element when an InstanceTime + * should be removed. This will be in response to the pruning of an + * Interval. + */ + protected float removeInstanceTime(InstanceTime time, boolean isBegin) { + // Trace.enter(this, "removeInstanceTime", new Object[] { time, new Boolean(isBegin) } ); try { + hasPropagated = true; + List instanceTimes = isBegin ? beginInstanceTimes : endInstanceTimes; + int index = Collections.binarySearch(instanceTimes, time); + for (int i = index; i >= 0; i--) { + InstanceTime it = (InstanceTime) instanceTimes.get(i); + if (it == time) { + instanceTimes.remove(i); + break; + } + if (it.compareTo(time) != 0) { + break; + } + } + int len = instanceTimes.size(); + for (int i = index + 1; i < len; i++) { + InstanceTime it = (InstanceTime) instanceTimes.get(i); + if (it == time) { + instanceTimes.remove(i); + break; + } + if (it.compareTo(time) != 0) { + break; + } + } + shouldUpdateCurrentInterval = true; + float ret; + if (root.isSampling() && !isSampling) { + ret = sampleAt(root.getCurrentTime(), root.isHyperlinking()); + } else { + ret = Float.POSITIVE_INFINITY; + } + hasPropagated = false; + root.currentIntervalWillUpdate(); + return ret; + // } finally { Trace.exit(); } + } + + /** + * Called by a TimingSpecifier of this element when an InstanceTime + * has been updated. This will be in response to a dependent + * syncbase change. + */ + protected float instanceTimeChanged(InstanceTime time, boolean isBegin) { + // Trace.enter(this, "instanceTimeChanged", new Object[] { time, new Boolean(isBegin) } ); try { + hasPropagated = true; + shouldUpdateCurrentInterval = true; + float ret; + if (root.isSampling() && !isSampling) { + ret = sampleAt(root.getCurrentTime(), root.isHyperlinking()); + } else { + ret = Float.POSITIVE_INFINITY; + } + hasPropagated = false; + return ret; + // } finally { Trace.exit(); } + } + + /** + * Adds a dependent TimingSpecifier for this element. + */ + protected void addDependent(TimingSpecifier dependent, boolean forBegin) { + // Trace.enter(this, "addDependent", new Object[] { dependent, new Boolean(forBegin) } ); try { + if (forBegin) { + beginDependents.add(dependent); + } else { + endDependents.add(dependent); + } + // } finally { Trace.exit(); } + } + + /** + * Removes a dependent TimingSpecifier for this element. + */ + protected void removeDependent(TimingSpecifier dependent, + boolean forBegin) { + // Trace.enter(this, "removeDependent", new Object[] { dependent, new Boolean(forBegin) } ); try { + if (forBegin) { + beginDependents.remove(dependent); + } else { + endDependents.remove(dependent); + } + // } finally { Trace.exit(); } + } + + /** + * Returns the simple duration time of this element. + */ + public float getSimpleDur() { + if (durMedia) { + return getImplicitDur(); + } else if (isUnresolved(simpleDur)) { + if (isUnresolved(repeatCount) && isUnresolved(repeatDur) + && endTimes.length > 0) { + return INDEFINITE; + } + return getImplicitDur(); + } else { + return simpleDur; + } + } + + /** + * Returns whether the given time value is equal to the + * {@link #UNRESOLVED} value. + */ + public static boolean isUnresolved(float t) { + return Float.isNaN(t); + } + + /** + * Returns the active duration time of this element. + */ + public float getActiveDur(float B, float end) { + float d = getSimpleDur(); + float PAD; + if (!isUnresolved(end) && d == INDEFINITE) { + PAD = minusTime(end, B); + repeatDuration = minTime(max, maxTime(min, PAD)); + return repeatDuration; + } + + float IAD; + if (d == 0) { + IAD = 0; + } else { + if (isUnresolved(repeatDur) && isUnresolved(repeatCount)) { + IAD = d; + } else { + float p1 = isUnresolved(repeatCount) + ? INDEFINITE + : multiplyTime(d, repeatCount); + float p2 = isUnresolved(repeatDur) + ? INDEFINITE + : repeatDur; + IAD = minTime(minTime(p1, p2), INDEFINITE); + } + } + if (isUnresolved(end) || end == INDEFINITE) { + PAD = IAD; + } else { + PAD = minTime(IAD, minusTime(end, B)); + } + repeatDuration = IAD; + return minTime(max, maxTime(min, PAD)); + } + + /** + * Subtracts one simple time from another. + */ + protected float minusTime(float t1, float t2) { + if (isUnresolved(t1) || isUnresolved(t2)) { + return UNRESOLVED; + } + if (t1 == INDEFINITE || t2 == INDEFINITE) { + return INDEFINITE; + } + return t1 - t2; + } + + /** + * Multiplies one simple time by n. + */ + protected float multiplyTime(float t, float n) { + if (isUnresolved(t) || t == INDEFINITE) { + return t; + } + return t * n; + } + + /** + * Returns the minimum of two time values. + */ + protected float minTime(float t1, float t2) { + if (t1 == 0.0f || t2 == 0.0f) { + return 0.0f; + } + if ((t1 == INDEFINITE || isUnresolved(t1)) + && t2 != INDEFINITE && !isUnresolved(t2)) { + return t2; + } + if ((t2 == INDEFINITE || isUnresolved(t2)) + && t1 != INDEFINITE && !isUnresolved(t1)) { + return t1; + } + if (t1 == INDEFINITE && isUnresolved(t2) + || isUnresolved(t1) && t2 == INDEFINITE) { + return INDEFINITE; + } + if (t1 < t2) { + return t1; + } + return t2; + } + + /** + * Returns the maximum of two time values. + */ + protected float maxTime(float t1, float t2) { + if ((t1 == INDEFINITE || isUnresolved(t1)) + && t2 != INDEFINITE && !isUnresolved(t2)) { + return t1; + } + if ((t2 == INDEFINITE || isUnresolved(t2)) + && t1 != INDEFINITE && !isUnresolved(t1)) { + return t2; + } + if (t1 == INDEFINITE && isUnresolved(t2) + || isUnresolved(t1) && t2 == INDEFINITE) { + return UNRESOLVED; + } + if (t1 > t2) { + return t1; + } + return t2; + } + + /** + * Returns the implicit duration of the element. Currently, nested time + * containers are not supported by SVG so this just returns + * {@link #UNRESOLVED} by default. This should be overriden in derived + * classes that play media, since they will have an implicit duration. + */ + protected float getImplicitDur() { + return UNRESOLVED; + } + + /** + * Notifies dependents of a new interval. + */ + protected float notifyNewInterval(Interval interval) { + // Trace.enter(this, "notifyNewInterval", new Object[] { interval } ); try { + float dependentMinTime = Float.POSITIVE_INFINITY; + Iterator i = beginDependents.iterator(); + while (i.hasNext()) { + TimingSpecifier ts = (TimingSpecifier) i.next(); + // Trace.print(ts.owner + "'s " + (ts.isBegin ? "begin" : "end" ) + ": " + ts); + float t = ts.newInterval(interval); + if (t < dependentMinTime) { + dependentMinTime = t; + } + } + i = endDependents.iterator(); + while (i.hasNext()) { + TimingSpecifier ts = (TimingSpecifier) i.next(); + // Trace.print(ts.owner + "'s " + (ts.isBegin ? "begin" : "end" ) + ": " + ts); + float t = ts.newInterval(interval); + if (t < dependentMinTime) { + dependentMinTime = t; + } + } + return dependentMinTime; + // } finally { Trace.exit(); } + } + + /** + * Notifies dependents of a removed interval. + */ + protected float notifyRemoveInterval(Interval interval) { + // Trace.enter(this, "notifyRemoveInterval", new Object[] { interval } ); try { + float dependentMinTime = Float.POSITIVE_INFINITY; + Iterator i = beginDependents.iterator(); + while (i.hasNext()) { + TimingSpecifier ts = (TimingSpecifier) i.next(); + float t = ts.removeInterval(interval); + if (t < dependentMinTime) { + dependentMinTime = t; + } + } + i = endDependents.iterator(); + while (i.hasNext()) { + TimingSpecifier ts = (TimingSpecifier) i.next(); + float t = ts.removeInterval(interval); + if (t < dependentMinTime) { + dependentMinTime = t; + } + } + return dependentMinTime; + // } finally { Trace.exit(); } + } + + /** + * Calculates the local simple time. Currently the hyperlinking parameter + * is ignored, so DOM timing events are fired during hyperlinking seeks. + * If we were following SMIL 2.1 rather than SMIL Animation, then these + * events would have to be suppressed. + * + * @return the number of seconds until this element becomes active again + * if it currently is not, {@link Float#POSITIVE_INFINITY} if this + * element will become active at some undetermined point in the + * future (because of unresolved begin times, for example) or + * will never become active again, or 0f if the + * element is currently active. + */ + protected float sampleAt(float parentSimpleTime, boolean hyperlinking) { + // Trace.enter(this, "sampleAt", new Object[] { new Float(parentSimpleTime) } ); try { + isSampling = true; + + float time = parentSimpleTime; // No time containers in SVG. + + // First, process any events that occurred since the last sampling, + // taking into account event sensitivity. + Iterator i = handledEvents.entrySet().iterator(); + while (i.hasNext()) { + Map.Entry e = (Map.Entry) i.next(); + Event evt = (Event) e.getKey(); + Set ts = (Set) e.getValue(); + Iterator j = ts.iterator(); + boolean hasBegin = false, hasEnd = false; + while (j.hasNext() && !(hasBegin && hasEnd)) { + EventLikeTimingSpecifier t = + (EventLikeTimingSpecifier) j.next(); + if (t.isBegin()) { + hasBegin = true; + } else { + hasEnd = true; + } + } + boolean useBegin, useEnd; + if (hasBegin && hasEnd) { + useBegin = !isActive || restartMode == RESTART_ALWAYS; + useEnd = !useBegin; + } else if (hasBegin && (!isActive || + restartMode == RESTART_ALWAYS)) { + useBegin = true; + useEnd = false; + } else if (hasEnd && isActive) { + useBegin = false; + useEnd = true; + } else { + continue; + } + j = ts.iterator(); + while (j.hasNext()) { + EventLikeTimingSpecifier t = + (EventLikeTimingSpecifier) j.next(); + boolean isBegin = t.isBegin(); + if (isBegin && useBegin || !isBegin && useEnd) { + t.resolve(evt); + shouldUpdateCurrentInterval = true; + } + } + } + handledEvents.clear(); + + // Now process intervals. + if (currentInterval != null) { + float begin = currentInterval.getBegin(); + if (lastSampleTime < begin && time >= begin) { + if (!isActive) { + toActive(begin); + } + isActive = true; + isFrozen = false; + lastRepeatTime = begin; + fireTimeEvent + (SMIL_BEGIN_EVENT_NAME, currentInterval.getBegin(), 0); + } + } + // For each sample, we might need to update the current interval's + // begin and end times, or end the current interval and compute + // a new one. + boolean hasEnded = currentInterval != null + && time >= currentInterval.getEnd(); + // Fire any repeat events that should have been fired since the + // last sample. + if (currentInterval != null) { + float begin = currentInterval.getBegin(); + if (time >= begin) { + float d = getSimpleDur(); + while (time - lastRepeatTime >= d + && lastRepeatTime + d < begin + repeatDuration) { + lastRepeatTime += d; + currentRepeatIteration++; + fireTimeEvent(root.getRepeatEventName(), lastRepeatTime, + currentRepeatIteration); + } + } + } + + // Trace.print("begin loop"); + float dependentMinTime = Float.POSITIVE_INFINITY; + if (hyperlinking) { + shouldUpdateCurrentInterval = true; + } + while (shouldUpdateCurrentInterval || hasEnded) { + if (hasEnded) { + // previousIntervals.add(currentInterval); + previousInterval = currentInterval; + isActive = false; + isFrozen = fillMode == FILL_FREEZE; + toInactive(false, isFrozen); + fireTimeEvent(SMIL_END_EVENT_NAME, currentInterval.getEnd(), 0); + } + boolean first = + // currentInterval == null && previousIntervals.isEmpty(); + currentInterval == null && previousInterval == null; + if (currentInterval != null && hyperlinking) { + // Hyperlinking, so remove the current interval and force a new + // one to be computed. + isActive = false; + isFrozen = false; + toInactive(false, false); + currentInterval = null; + // fireTimeEvent(SMIL_END_EVENT_NAME, currentInterval.getEnd(), 0); + } + if (currentInterval == null || hasEnded) { + if (first || hyperlinking || restartMode != RESTART_NEVER) { + float beginAfter; + boolean incl = true; + if (first || hyperlinking) { + beginAfter = Float.NEGATIVE_INFINITY; + } else { + // beginAfter = ((Interval) previousIntervals.getLast()).getEnd(); + beginAfter = previousInterval.getEnd(); + incl = beginAfter != previousInterval.getBegin(); + } + Interval interval = + computeInterval(first, false, beginAfter, incl); + if (interval == null) { + currentInterval = null; + } else { + float dmt = selectNewInterval(time, interval); + if (dmt < dependentMinTime) { + dependentMinTime = dmt; + } + } + } else { + currentInterval = null; + } + } else { + float currentBegin = currentInterval.getBegin(); + if (currentBegin > time) { + // Interval hasn't started yet. + float beginAfter; + boolean incl = true; + // if (previousIntervals.isEmpty()) { + if (previousInterval == null) { + beginAfter = Float.NEGATIVE_INFINITY; + } else { + // beginAfter = ((Interval) previousIntervals.getLast()).getEnd(); + beginAfter = previousInterval.getEnd(); + incl = beginAfter != previousInterval.getBegin(); + } + Interval interval = + computeInterval(false, false, beginAfter, incl); + float dmt = notifyRemoveInterval(currentInterval); + if (dmt < dependentMinTime) { + dependentMinTime = dmt; + } + if (interval == null) { + currentInterval = null; + } else { + dmt = selectNewInterval(time, interval); + if (dmt < dependentMinTime) { + dependentMinTime = dmt; + } + } + } else { + // Interval has already started. + Interval interval = + computeInterval(false, true, currentBegin, true); + float newEnd = interval.getEnd(); + if (currentInterval.getEnd() != newEnd) { + float dmt = + currentInterval.setEnd + (newEnd, interval.getEndInstanceTime()); + if (dmt < dependentMinTime) { + dependentMinTime = dmt; + } + } + } + } + shouldUpdateCurrentInterval = false; + hyperlinking = false; + hasEnded = currentInterval != null && time >= currentInterval.getEnd(); + } + // Trace.print("end loop"); + + float d = getSimpleDur(); + if (isActive && !isFrozen) { + if (time - currentInterval.getBegin() >= repeatDuration) { + // Trace.print("element between repeat and active duration"); + isFrozen = fillMode == FILL_FREEZE; + toInactive(true, isFrozen); + } else { + // Trace.print("element active, sampling at simple time " + (time - lastRepeatTime)); + sampledAt(time - lastRepeatTime, d, currentRepeatIteration); + } + } + if (isFrozen) { + float t; + boolean atLast; + if (isActive) { + t = currentInterval.getBegin() + repeatDuration - lastRepeatTime; + atLast = lastRepeatTime + d == currentInterval.getBegin() + repeatDuration; + } else { + // Interval previousInterval = (Interval) previousIntervals.getLast(); + t = previousInterval.getEnd() - lastRepeatTime; + atLast = lastRepeatTime + d == previousInterval.getEnd(); + } + if (atLast) { + // Trace.print("element frozen" + (isActive ? " (but still active)" : "") + ", sampling last value"); + sampledLastValue(currentRepeatIteration); + } else { + // Trace.print("element frozen" + (isActive ? " (but still active)" : "") + ", sampling at simple time " + (t % d)); + sampledAt(t % d, d, currentRepeatIteration); + } + } else if (!isActive) { + // Trace.print("element not sampling"); + } + + isSampling = false; + + lastSampleTime = time; + if (currentInterval != null) { + float t = currentInterval.getBegin() - time; + if (t <= 0) { + t = isConstantAnimation() || isFrozen ? currentInterval.getEnd() - time : 0; + } + if (dependentMinTime < t) { + return dependentMinTime; + } + return t; + } + return dependentMinTime; + // } finally { Trace.exit(); } + } + + /** + * Returns whether the end timing specifier list contains any eventbase, + * accesskey or repeat timing specifiers. + */ + protected boolean endHasEventConditions() { + for (int i = 0; i < endTimes.length; i++) { + if (endTimes[i].isEventCondition()) { + return true; + } + } + return false; + } + + /** + * Sets the current interval to the one specified. This will notify + * dependents and fire the 'begin' and any necessary 'repeat' events. + * @param time the current sampling time + * @param interval the Interval object to select to be current + * @return the minimum time the animation engine can safely wait, as + * determined by dependents of the interval + */ + protected float selectNewInterval(float time, Interval interval) { + // Trace.enter(this, "selectNewInterval", new Object[] { interval }); try { + currentInterval = interval; + float dmt = notifyNewInterval(currentInterval); + float beginEventTime = currentInterval.getBegin(); + if (time >= beginEventTime) { + lastRepeatTime = beginEventTime; + if (beginEventTime < 0) { + beginEventTime = 0; + } + toActive(beginEventTime); + isActive = true; + isFrozen = false; + fireTimeEvent(SMIL_BEGIN_EVENT_NAME, beginEventTime, 0); + float d = getSimpleDur(); + float end = currentInterval.getEnd(); + while (time - lastRepeatTime >= d + && lastRepeatTime + d < end) { + lastRepeatTime += d; + currentRepeatIteration++; + fireTimeEvent(root.getRepeatEventName(), lastRepeatTime, + currentRepeatIteration); + } + } + return dmt; + // } finally { Trace.exit(); } + } + + /** + * Computes an interval from the begin and end instance time lists. + * @param first indicates whether this is the first interval to compute + * @param fixedBegin if true, specifies that the value given for + * beginAfter is taken to be the actual begin + * time for the interval; only the end value is computed. + * @param beginAfter the earliest possible begin time for the computed + * interval. + * @param incl if true (and !fixedBegin), specifies that the + * new interval's begin time must be greater than + * beginAfter; otherwise, the begin time must be + * greater than or equal to beginAfter. + */ + protected Interval computeInterval(boolean first, boolean fixedBegin, + float beginAfter, boolean incl) { + // Trace.enter(this, "computeInterval", new Object[] { new Boolean(first), new Boolean(fixedBegin), new Float(beginAfter)} ); try { + // Trace.print("computing interval from begins=" + beginInstanceTimes + ", ends=" + endInstanceTimes); + Iterator beginIterator = beginInstanceTimes.iterator(); + Iterator endIterator = endInstanceTimes.iterator(); + float parentSimpleDur = parent.getSimpleDur(); + InstanceTime endInstanceTime = endIterator.hasNext() + ? (InstanceTime) endIterator.next() + : null; + boolean firstEnd = true; + InstanceTime beginInstanceTime = null; + InstanceTime nextBeginInstanceTime = null; + for (;;) { + float tempBegin; + if (fixedBegin) { + tempBegin = beginAfter; + while (beginIterator.hasNext()) { + nextBeginInstanceTime = (InstanceTime) beginIterator.next(); + if (nextBeginInstanceTime.getTime() > tempBegin) { + break; + } + } + } else { + for (;;) { + if (!beginIterator.hasNext()) { + // ran out of begin values + // Trace.print("returning null interval"); + return null; + } + beginInstanceTime = (InstanceTime) beginIterator.next(); + tempBegin = beginInstanceTime.getTime(); + if (incl && tempBegin >= beginAfter + || !incl && tempBegin > beginAfter) { + if (beginIterator.hasNext()) { + nextBeginInstanceTime = + (InstanceTime) beginIterator.next(); + if (beginInstanceTime.getTime() + == nextBeginInstanceTime.getTime()) { + // XXX Not sure if this is exactly correct to + // skip past these identical times, but it + // avoids an infinite loop of 0s intervals + // being created. + nextBeginInstanceTime = null; + continue; + } + } + break; + } + } + } + if (tempBegin >= parentSimpleDur) { + // the begin value is after the parent has ended + // Trace.print("returning null interval"); + return null; + } + float tempEnd; + if (endTimes.length == 0) { + // no 'end' attribute specified + tempEnd = tempBegin + getActiveDur(tempBegin, INDEFINITE); + // Trace.print("no end specified, so tempEnd = " + tempEnd); + } else { + if (endInstanceTimes.isEmpty()) { + tempEnd = UNRESOLVED; + } else { + tempEnd = endInstanceTime.getTime(); + if (first && !firstEnd && tempEnd == tempBegin + || !first && currentInterval != null + && tempEnd == currentInterval.getEnd() + && (incl && beginAfter >= tempEnd + || !incl && beginAfter > tempEnd)) { + for (;;) { + if (!endIterator.hasNext()) { + if (endHasEventConditions()) { + tempEnd = UNRESOLVED; + break; + } + // Trace.print("returning null interval"); + return null; + } + endInstanceTime = (InstanceTime) endIterator.next(); + tempEnd = endInstanceTime.getTime(); + if (tempEnd > tempBegin) { + break; + } + } + } + firstEnd = false; + for (;;) { + if (tempEnd >= tempBegin) { + break; + } + if (!endIterator.hasNext()) { + if (endHasEventConditions()) { + tempEnd = UNRESOLVED; + break; + } + // Trace.print("returning null interval"); + return null; + } + endInstanceTime = (InstanceTime) endIterator.next(); + tempEnd = endInstanceTime.getTime(); + } + } + float ad = getActiveDur(tempBegin, tempEnd); + tempEnd = tempBegin + ad; + } + if (!first || tempEnd > 0 || tempBegin == 0 && tempEnd == 0 + || isUnresolved(tempEnd)) { + // Trace.print("considering restart semantics"); + if (restartMode == RESTART_ALWAYS + && nextBeginInstanceTime != null) { + float nextBegin = nextBeginInstanceTime.getTime(); + // Trace.print("nextBegin == " + nextBegin); + if (nextBegin < tempEnd || isUnresolved(tempEnd)) { + tempEnd = nextBegin; + endInstanceTime = nextBeginInstanceTime; + } + } + Interval i = new Interval(tempBegin, tempEnd, + beginInstanceTime, endInstanceTime); + // Trace.print("returning interval: " + i); + return i; + } + if (fixedBegin) { + // Trace.print("returning null interval"); + return null; + } + beginAfter = tempEnd; + } + // } finally { Trace.exit(); } + } + + /** + * Resets this element. + */ + protected void reset(boolean clearCurrentBegin) { + Iterator i = beginInstanceTimes.iterator(); + while (i.hasNext()) { + InstanceTime it = (InstanceTime) i.next(); + if (it.getClearOnReset() && + (clearCurrentBegin + || currentInterval == null + || currentInterval.getBeginInstanceTime() != it)) { + i.remove(); + } + } + i = endInstanceTimes.iterator(); + while (i.hasNext()) { + InstanceTime it = (InstanceTime) i.next(); + if (it.getClearOnReset()) { + i.remove(); + } + } + if (isFrozen) { + removeFill(); + } + currentRepeatIteration = 0; + lastRepeatTime = UNRESOLVED; + isActive = false; + isFrozen = false; + lastSampleTime = UNRESOLVED; + // XXX should reconvert resolved syncbase/wallclock/media-marker time + // instances into the parent simple timespace + } + + /** + * Parses the animation attributes for this timed element. + */ + public void parseAttributes(String begin, String dur, String end, + String min, String max, String repeatCount, + String repeatDur, String fill, + String restart) { + if (!hasParsed) { + parseBegin(begin); + parseDur(dur); + parseEnd(end); + parseMin(min); + parseMax(max); + if (this.min > this.max) { + this.min = 0f; + this.max = INDEFINITE; + } + parseRepeatCount(repeatCount); + parseRepeatDur(repeatDur); + parseFill(fill); + parseRestart(restart); + hasParsed = true; + } + } + + /** + * Parses a new 'begin' attribute. + */ + protected void parseBegin(String begin) { + try { + if (begin.length() == 0) { + begin = SMIL_BEGIN_DEFAULT_VALUE; + } + beginTimes = TimingSpecifierListProducer.parseTimingSpecifierList + (TimedElement.this, true, begin, + root.useSVG11AccessKeys, root.useSVG12AccessKeys); + } catch (ParseException ex) { + throw createException + ("attribute.malformed", + new Object[] { null, SMIL_BEGIN_ATTRIBUTE }); + } + } + + /** + * Parses a new 'dur' attribute. + */ + protected void parseDur(String dur) { + if (dur.equals(SMIL_MEDIA_VALUE)) { + durMedia = true; + simpleDur = UNRESOLVED; + } else { + durMedia = false; + if (dur.length() == 0 || dur.equals(SMIL_INDEFINITE_VALUE)) { + simpleDur = INDEFINITE; + } else { + try { + simpleDur = parseClockValue(dur, false); + } catch (ParseException e) { + throw createException + ("attribute.malformed", + new Object[] { null, SMIL_DUR_ATTRIBUTE }); + } + if (simpleDur < 0) { + simpleDur = INDEFINITE; + } + } + } + } + + /** + * Parses a clock value or offset and returns it as a float. + */ + protected float parseClockValue(String s, boolean parseOffset) + throws ParseException { + ClockParser p = new ClockParser(parseOffset); + class Handler implements ClockHandler { + protected float v = 0; + public void clockValue(float newClockValue) { + v = newClockValue; + } + } + + Handler h = new Handler(); + p.setClockHandler(h); + p.parse(s); + return h.v; + } + + /** + * Parses a new 'end' attribute. + */ + protected void parseEnd(String end) { + try { + endTimes = TimingSpecifierListProducer.parseTimingSpecifierList + (TimedElement.this, false, end, + root.useSVG11AccessKeys, root.useSVG12AccessKeys); + } catch (ParseException ex) { + throw createException + ("attribute.malformed", + new Object[] { null, SMIL_END_ATTRIBUTE }); + } + } + + /** + * Parses a new 'min' attribute. + */ + protected void parseMin(String min) { + if (min.equals(SMIL_MEDIA_VALUE)) { + this.min = 0; + minMedia = true; + } else { + minMedia = false; + if (min.length() == 0) { + this.min = 0; + } else { + try { + this.min = parseClockValue(min, false); + } catch (ParseException ex) { + this.min = 0; + } + if (this.min < 0) { + this.min = 0; + } + } + } + } + + /** + * Parses a new 'max' attribute. + */ + protected void parseMax(String max) { + if (max.equals(SMIL_MEDIA_VALUE)) { + this.max = INDEFINITE; + maxMedia = true; + } else { + maxMedia = false; + if (max.length() == 0 || max.equals(SMIL_INDEFINITE_VALUE)) { + this.max = INDEFINITE; + } else { + try { + this.max = parseClockValue(max, false); + } catch (ParseException ex) { + this.max = INDEFINITE; + } + if (this.max < 0) { + this.max = 0; + } + } + } + } + + /** + * Parses a new 'repeatCount' attribute. + */ + protected void parseRepeatCount(String repeatCount) { + if (repeatCount.length() == 0) { + this.repeatCount = UNRESOLVED; + } else if (repeatCount.equals(SMIL_INDEFINITE_VALUE)) { + this.repeatCount = INDEFINITE; + } else { + try { + this.repeatCount = Float.parseFloat(repeatCount); + if (this.repeatCount > 0) { + return; + } + } catch (NumberFormatException ex) { + throw createException + ("attribute.malformed", + new Object[] { null, SMIL_REPEAT_COUNT_ATTRIBUTE }); + } + } + } + + /** + * Parses a new 'repeatDur' attribute. + */ + protected void parseRepeatDur(String repeatDur) { + try { + if (repeatDur.length() == 0) { + this.repeatDur = UNRESOLVED; + } else if (repeatDur.equals(SMIL_INDEFINITE_VALUE)) { + this.repeatDur = INDEFINITE; + } else { + this.repeatDur = parseClockValue(repeatDur, false); + } + } catch (ParseException ex) { + throw createException + ("attribute.malformed", + new Object[] { null, SMIL_REPEAT_DUR_ATTRIBUTE }); + } + } + + /** + * Parses a new 'fill' attribute. + */ + protected void parseFill(String fill) { + if (fill.length() == 0 || fill.equals(SMIL_REMOVE_VALUE)) { + fillMode = FILL_REMOVE; + } else if (fill.equals(SMIL_FREEZE_VALUE)) { + fillMode = FILL_FREEZE; + } else { + throw createException + ("attribute.malformed", + new Object[] { null, SMIL_FILL_ATTRIBUTE }); + } + } + + /** + * Parses a new 'restart' attribute. + */ + protected void parseRestart(String restart) { + if (restart.length() == 0 || restart.equals(SMIL_ALWAYS_VALUE)) { + restartMode = RESTART_ALWAYS; + } else if (restart.equals(SMIL_WHEN_NOT_ACTIVE_VALUE)) { + restartMode = RESTART_WHEN_NOT_ACTIVE; + } else if (restart.equals(SMIL_NEVER_VALUE)) { + restartMode = RESTART_NEVER; + } else { + throw createException + ("attribute.malformed", + new Object[] { null, SMIL_RESTART_ATTRIBUTE }); + } + } + + /** + * Initializes this timed element. + */ + public void initialize() { + for (int i = 0; i < beginTimes.length; i++) { + beginTimes[i].initialize(); + } + for (int i = 0; i < endTimes.length; i++) { + endTimes[i].initialize(); + } + } + + /** + * Deinitializes this timed element. + */ + public void deinitialize() { + for (int i = 0; i < beginTimes.length; i++) { + beginTimes[i].deinitialize(); + } + for (int i = 0; i < endTimes.length; i++) { + endTimes[i].deinitialize(); + } + } + + /** + * Adds a time to the begin time instance list that will cause + * the element to begin immediately (if restart semantics allow it). + */ + public void beginElement() { + beginElement(0); + } + + /** + * Adds a time to the begin time instance list that will cause + * the element to begin at some offset to the current time (if restart + * semantics allow it). + */ + public void beginElement(float offset) { + float t = root.convertWallclockTime( Calendar.getInstance()); + InstanceTime it = new InstanceTime(null, t + offset, true); + addInstanceTime(it, true); + } + + /** + * Adds a time to the end time instance list that will cause + * the element to end immediately (if restart semantics allow it). + */ + public void endElement() { + endElement(0); + } + + /** + * Adds a time to the end time instance list that will cause + * the element to end at some offset to the current time (if restart + * semantics allow it). + */ + public void endElement(float offset) { + float t = root.convertWallclockTime(Calendar.getInstance()); + InstanceTime it = new InstanceTime(null, t + offset, true); + addInstanceTime(it, false); + } + + /** + * Returns the last sample time of this element, in local active time. + */ + public float getLastSampleTime() { + return lastSampleTime; + } + + /** + * Returns the begin time of the current interval, in parent simple time, + * or Float.NaN if the element is not active. + */ + public float getCurrentBeginTime() { + float begin; + if (currentInterval == null + || (begin = currentInterval.getBegin()) < lastSampleTime) { + return Float.NaN; + } + return begin; + } + + /** + * Returns whether this element can be begun or restarted currently. + */ + public boolean canBegin() { + return currentInterval == null + || isActive && restartMode != RESTART_NEVER; + } + + /** + * Returns whether this element can be ended currently. + */ + public boolean canEnd() { + return isActive; + } + + /** + * Returns the time that the document would seek to if this animation + * element were hyperlinked to, or NaN if there is no + * such begin time. + */ + public float getHyperlinkBeginTime() { + if (isActive) { + return currentInterval.getBegin(); + } + if (!beginInstanceTimes.isEmpty()) { + return ((InstanceTime) beginInstanceTimes.get(0)).getTime(); + } + return Float.NaN; + } + + /** + * Fires a TimeEvent of the given type on this element. + * @param eventType the type of TimeEvent ("beginEvent", "endEvent" + * or "repeatEvent"). + * @param time the timestamp of the event object + * @param detail the repeat iteration, if this event is a repeat event + */ + protected void fireTimeEvent(String eventType, float time, int detail) { + Calendar t = (Calendar) root.getDocumentBeginTime().clone(); + t.add(Calendar.MILLISECOND, (int) Math.round(time * 1e3)); + fireTimeEvent(eventType, t, detail); + } + + /** + * Invoked by a {@link TimingSpecifier} to indicate that an event occurred + * that would create a new instance time for this timed element. These + * will be processed at the beginning of the next tick. + */ + void eventOccurred(TimingSpecifier t, Event e) { + Set ts = (HashSet) handledEvents.get(e); + if (ts == null) { + ts = new HashSet(); + handledEvents.put(e, ts); + } + ts.add(t); + root.currentIntervalWillUpdate(); + } + + /** + * Fires a TimeEvent of the given type on this element. + * @param eventType the type of TimeEvent ("beginEvent", "endEvent" + * or "repeatEvent"). + * @param time the timestamp of the event object + */ + protected abstract void fireTimeEvent(String eventType, Calendar time, + int detail); + + /** + * Invoked to indicate this timed element became active at the + * specified time. + * @param begin the time the element became active, in document simple time + */ + protected abstract void toActive(float begin); + + /** + * Invoked to indicate that this timed element became inactive. + * @param stillActive if true, indicates that the element is still actually + * active, but between the end of the computed repeat + * duration and the end of the interval + * @param isFrozen whether the element is frozen or not + */ + protected abstract void toInactive(boolean stillActive, boolean isFrozen); + + /** + * Invoked to indicate that this timed element has had its fill removed. + */ + protected abstract void removeFill(); + + /** + * Invoked to indicate that this timed element has been sampled at the + * given time. + * @param simpleTime the sample time in local simple time + * @param simpleDur the simple duration of the element + * @param repeatIteration the repeat iteration during which the element + * was sampled + */ + protected abstract void sampledAt(float simpleTime, float simpleDur, + int repeatIteration); + + /** + * Invoked to indicate that this timed element has been sampled + * at the end of its active time, at an integer multiple of the + * simple duration. This is the "last" value that will be used + * for filling, which cannot be sampled normally. + */ + protected abstract void sampledLastValue(int repeatIteration); + + /** + * Returns the timed element with the given ID. + */ + protected abstract TimedElement getTimedElementById(String id); + + /** + * Returns the event target with the given ID. + */ + protected abstract EventTarget getEventTargetById(String id); + + /** + * Returns the event target that should be listened to for + * access key events. + */ + protected abstract EventTarget getRootEventTarget(); + + /** + * Returns the DOM element that corresponds to this timed element, if + * such a DOM element exists. + */ + public abstract Element getElement(); + + /** + * Returns the target of this animation as an {@link EventTarget}. Used + * for eventbase timing specifiers where the element ID is omitted. + */ + protected abstract EventTarget getAnimationEventTarget(); + + /** + * Returns whether this timed element comes before the given timed element + * in document order. + */ + public abstract boolean isBefore(TimedElement other); + + /** + * Returns whether this timed element is for a constant animation (i.e., a + * 'set' animation. + */ + protected abstract boolean isConstantAnimation(); + + /** + * Creates and returns a new {@link AnimationException}. + */ + public AnimationException createException(String code, Object[] params) { + Element e = getElement(); + if (e != null) { + params[0] = e.getNodeName(); + } + return new AnimationException(this, code, params); + } + + /** + * The error messages bundle class name. + */ + protected static final String RESOURCES = + "org.apache.batik.anim.resources.Messages"; + + /** + * The localizable support for the error messages. + */ + protected static LocalizableSupport localizableSupport = + new LocalizableSupport(RESOURCES, TimedElement.class.getClassLoader()); + + /** + * Implements {@link org.apache.batik.i18n.Localizable#setLocale(java.util.Locale)}. + */ + public static void setLocale( Locale l) { + localizableSupport.setLocale(l); + } + + /** + * Implements {@link org.apache.batik.i18n.Localizable#getLocale()}. + */ + public static Locale getLocale() { + return localizableSupport.getLocale(); + } + + /** + * Implements {@link + * org.apache.batik.i18n.Localizable#formatMessage(String,Object[])}. + */ + public static String formatMessage(String key, Object[] args) + throws MissingResourceException { + return localizableSupport.formatMessage(key, args); + } + + /** + * Returns a string representation of the given time value. + */ + public static String toString(float time) { + if (Float.isNaN(time)) { + return "UNRESOLVED"; + } else if (time == Float.POSITIVE_INFINITY) { + return "INDEFINITE"; + } else { + return Float.toString(time); + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/TimegraphAdapter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/TimegraphAdapter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/TimegraphAdapter.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,106 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +/** + * An adapter class for {@link TimegraphListener}s. + * + * @author Cameron McCormack + * @version $Id: TimegraphAdapter.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class TimegraphAdapter implements TimegraphListener { + + /** + * Invoked to indicate that a timed element has been added to the + * document. + */ + public void elementAdded(TimedElement e) { + } + + /** + * Invoked to indicate that a timed element has been removed from the + * document. + */ + public void elementRemoved(TimedElement e) { + } + + /** + * Invoked to indicate that a timed element has become active. + * @param e the TimedElement that became active + * @param t the time (in parent simple time) that the element became active + */ + public void elementActivated(TimedElement e, float t) { + } + + /** + * Invoked to indicate that a timed element has become inactive + * and is filling. + */ + public void elementFilled(TimedElement e, float t) { + } + + /** + * Invoked to indicate that a timed element has become inactive + * and is not filling. + */ + public void elementDeactivated(TimedElement e, float t) { + } + + /** + * Invoked to indivate that an interval was created for the given + * timed element. + */ + public void intervalCreated(TimedElement e, Interval i) { + } + + /** + * Invoked to indivate that an interval was removed for the given + * timed element. + */ + public void intervalRemoved(TimedElement e, Interval i) { + } + + /** + * Invoked to indivate that an interval's endpoints were changed. + */ + public void intervalChanged(TimedElement e, Interval i) { + } + + /** + * Invoked to indivate that the given interval began. + * @param i the Interval that began, or null if no interval is + * active for the given timed element. + */ + public void intervalBegan(TimedElement e, Interval i) { + } + + /** + * Invoked to indicate that the given timed element began a repeat + * iteration at the specified time. + */ + public void elementRepeated(TimedElement e, int i, float t) { + } + + /** + * Invoked to indicate that the list of instance times for the given + * timed element has been updated. + */ + public void elementInstanceTimesChanged(TimedElement e, float isBegin) { + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/TimegraphListener.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/TimegraphListener.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/TimegraphListener.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,95 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +/** + * An interface for listening to timing events in a timed document. + * + * @author Cameron McCormack + * @version $Id: TimegraphListener.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public interface TimegraphListener { + + /** + * Invoked to indicate that a timed element has been added to the + * document. + */ + void elementAdded(TimedElement e); + + /** + * Invoked to indicate that a timed element has been removed from the + * document. + */ + void elementRemoved(TimedElement e); + + /** + * Invoked to indicate that a timed element has become active. + * @param e the TimedElement that became active + * @param t the time (in parent simple time) that the element became active + */ + void elementActivated(TimedElement e, float t); + + /** + * Invoked to indicate that a timed element has become inactive + * and is filling. + */ + void elementFilled(TimedElement e, float t); + + /** + * Invoked to indicate that a timed element has become inactive + * and is not filling. + */ + void elementDeactivated(TimedElement e, float t); + + /** + * Invoked to indivate that an interval was created for the given + * timed element. + */ + void intervalCreated(TimedElement e, Interval i); + + /** + * Invoked to indivate that an interval was removed for the given + * timed element. + */ + void intervalRemoved(TimedElement e, Interval i); + + /** + * Invoked to indivate that an interval's endpoints were changed. + */ + void intervalChanged(TimedElement e, Interval i); + + /** + * Invoked to indivate that the given interval began. + * @param i the Interval that began, or null if no interval is + * active for the given timed element. + */ + void intervalBegan(TimedElement e, Interval i); + + /** + * Invoked to indicate that the given timed element began a repeat + * iteration at the specified time. + */ + void elementRepeated(TimedElement e, int i, float t); + + /** + * Invoked to indicate that the list of instance times for the given + * timed element has been updated. + */ + void elementInstanceTimesChanged(TimedElement e, float isBegin); +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/TimingSpecifier.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/TimingSpecifier.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/TimingSpecifier.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,110 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +/** + * An abstract class for SMIL timing specifiers. + * + * @author Cameron McCormack + * @version $Id: TimingSpecifier.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public abstract class TimingSpecifier { + + /** + * The element that owns this timing specifier. + */ + protected TimedElement owner; + + /** + * Whether this timing specifier is for a begin time or an end time. + */ + protected boolean isBegin; + + /** + * Creates a new TimingSpecifier object. + */ + protected TimingSpecifier(TimedElement owner, boolean isBegin) { + this.owner = owner; + this.isBegin = isBegin; + } + + /** + * Returns the element that owns this timing specifier. + */ + public TimedElement getOwner() { + return owner; + } + + /** + * Returns true if this timing specifier is in the owner's begin list, + * false if it is in the owner's end list. + */ + public boolean isBegin() { + return isBegin; + } + + /** + * Initializes this timing specifier by adding the initial instance time + * to the owner's instance time list or setting up any event listeners. + * This should be overriden in descendant classes. + */ + public void initialize() { + } + + /** + * Deinitializes this timing specifier by removing any event listeners. + * This should be overriden in descendant classes. + */ + public void deinitialize() { + } + + /** + * Returns whether this timing specifier is event-like (i.e., if it is + * an eventbase, accesskey or a repeat timing specifier). + */ + public abstract boolean isEventCondition(); + + /** + * Called by the timebase element when it creates a new Interval. + * This should be overridden in descendant classes that generate + * time instances based on the interval of a timebase element. + */ + float newInterval(Interval interval) { + return Float.POSITIVE_INFINITY; + } + + /** + * Called by the timebase element when it deletes an Interval. + * This should be overridden in descendant classes that generate + * time instances based on the interval of a timebase element. + */ + float removeInterval(Interval interval) { + return Float.POSITIVE_INFINITY; + } + + /** + * Called by an {@link InstanceTime} created by this TimingSpecifier + * to indicate that its value has changed. This should be overriden + * in descendant classes that generate time instances based on the + * interval of a timebase element. + */ + float handleTimebaseUpdate(InstanceTime instanceTime, float newTime) { + return Float.POSITIVE_INFINITY; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/TimingSpecifierListProducer.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/TimingSpecifierListProducer.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/TimingSpecifierListProducer.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,177 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +import java.util.Calendar; +import java.util.LinkedList; + +import org.apache.batik.parser.DefaultTimingSpecifierListHandler; +import org.apache.batik.parser.TimingSpecifierListParser; + +/** + * A {@link org.apache.batik.parser.TimingSpecifierListHandler} that creates + * {@link TimingSpecifier}s. + * + * @author Cameron McCormack + * @version $Id: TimingSpecifierListProducer.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class TimingSpecifierListProducer + extends DefaultTimingSpecifierListHandler { + + /** + * The list of parsed timing specifiers. + */ + protected LinkedList timingSpecifiers = new LinkedList(); + + /** + * The owner TimedElement used when creating the TimingSpecifiers. + */ + protected TimedElement owner; + + /** + * Whether the created TimingSpecifiers should be begin times. + */ + protected boolean isBegin; + + /** + * Creates a new TimingSpecifierListProducer. + */ + public TimingSpecifierListProducer(TimedElement owner, boolean isBegin) { + this.owner = owner; + this.isBegin = isBegin; + } + + /** + * Returns an array of the parsed TimingSpecifiers. + */ + public TimingSpecifier[] getTimingSpecifiers() { + return (TimingSpecifier[]) timingSpecifiers.toArray(new TimingSpecifier[0]); + } + + /** + * Parses a timing specifier list. + */ + public static TimingSpecifier[] parseTimingSpecifierList + (TimedElement owner, boolean isBegin, String spec, + boolean useSVG11AccessKeys, boolean useSVG12AccessKeys) { + TimingSpecifierListParser p = + new TimingSpecifierListParser(useSVG11AccessKeys, + useSVG12AccessKeys); + TimingSpecifierListProducer pp = + new TimingSpecifierListProducer(owner, isBegin); + p.setTimingSpecifierListHandler(pp); + p.parse(spec); + TimingSpecifier[] specs = pp.getTimingSpecifiers(); + return specs; + } + + // TimingSpecifierHandler //////////////////////////////////////////////// + + /** + * Invoked when an offset value timing specifier is parsed. + */ + public void offset(float offset) { + TimingSpecifier ts = new OffsetTimingSpecifier(owner, isBegin, offset); + timingSpecifiers.add(ts); + } + + /** + * Invoked when a syncbase value timing specifier is parsed. + */ + public void syncbase(float offset, String syncbaseID, + String timeSymbol) { + TimingSpecifier ts = new SyncbaseTimingSpecifier + (owner, isBegin, offset, syncbaseID, timeSymbol.charAt(0) == 'b'); + timingSpecifiers.add(ts); + } + + /** + * Invoked when an eventbase value timing specifier is parsed. + */ + public void eventbase(float offset, String eventbaseID, + String eventType) { + TimingSpecifier ts = new EventbaseTimingSpecifier + (owner, isBegin, offset, eventbaseID, eventType); + timingSpecifiers.add(ts); + } + + /** + * Invoked when a repeat value timing specifier with no iteration + * is parsed. + */ + public void repeat(float offset, String syncbaseID) { + TimingSpecifier ts = new RepeatTimingSpecifier + (owner, isBegin, offset, syncbaseID); + timingSpecifiers.add(ts); + } + + /** + * Invoked when a repeat value timing specifier with an iteration + * is parsed. + */ + public void repeat(float offset, String syncbaseID, + int repeatIteration) { + TimingSpecifier ts = new RepeatTimingSpecifier + (owner, isBegin, offset, syncbaseID, repeatIteration); + timingSpecifiers.add(ts); + } + + /** + * Invoked when an accesskey value timing specifier is parsed. + */ + public void accesskey(float offset, char key) { + TimingSpecifier ts = new AccesskeyTimingSpecifier + (owner, isBegin, offset, key); + timingSpecifiers.add(ts); + } + + /** + * Invoked when an SVG 1.2 accessKey value timing specifier is parsed. + */ + public void accessKeySVG12(float offset, String keyName) { + TimingSpecifier ts = new AccesskeyTimingSpecifier + (owner, isBegin, offset, keyName); + timingSpecifiers.add(ts); + } + + /** + * Invoked when a media marker value timing specifier is parsed. + */ + public void mediaMarker(String syncbaseID, String markerName) { + TimingSpecifier ts = new MediaMarkerTimingSpecifier + (owner, isBegin, syncbaseID, markerName); + timingSpecifiers.add(ts); + } + + /** + * Invoked when a wallclock value timing specifier is parsed. + */ + public void wallclock(Calendar time) { + TimingSpecifier ts = new WallclockTimingSpecifier(owner, isBegin, time); + timingSpecifiers.add(ts); + } + + /** + * Invoked when an indefinite value timing specifier is parsed. + */ + public void indefinite() { + TimingSpecifier ts = new IndefiniteTimingSpecifier(owner, isBegin); + timingSpecifiers.add(ts); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/Trace.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/Trace.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/Trace.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,68 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +/** + * Animation debugging support. To be removed. + * + * @author Cameron McCormack + * @version $Id: Trace.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class Trace { + + private static int level; + + private static boolean enabled = false; + + public static void enter(Object o, String fn, Object[] args) { + if (enabled) { + System.err.print("LOG\t"); + for (int i = 0; i < level; i++) { + System.err.print(" "); + } + if (fn == null) { + System.err.print("new " + o.getClass().getName() + "("); + } else { + System.err.print(o + "." + fn + "("); + } + if (args != null) { + System.err.print(args[0]); + for (int i = 1; i < args.length; i++) { + System.err.print(", " + args[i]); + } + } + System.err.println(")"); + } + level++; + } + + public static void exit() { + level--; + } + + public static void print(String s) { + if (enabled) { + System.err.print("LOG\t"); + for (int i = 0; i < level; i++) { + System.err.print(" "); + } + System.err.println(s); + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/timing/WallclockTimingSpecifier.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/timing/WallclockTimingSpecifier.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/timing/WallclockTimingSpecifier.java 8 Apr 2013 10:54:57 -0000 1.1 @@ -0,0 +1,74 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.timing; + +import java.util.Calendar; + +/** + * A class to handle wallclock SMIL timing specifiers. + * + * @author Cameron McCormack + * @version $Id: WallclockTimingSpecifier.java,v 1.1 2013/04/08 10:54:57 marcin Exp $ + */ +public class WallclockTimingSpecifier extends TimingSpecifier { + + /** + * The wallclock time. + */ + protected Calendar time; + + /** + * The instance time. + */ + protected InstanceTime instance; + + /** + * Creates a new WallclockTimingSpecifier object. + */ + public WallclockTimingSpecifier(TimedElement owner, boolean isBegin, + Calendar time) { + super(owner, isBegin); + this.time = time; + } + + /** + * Returns a string representation of this timing specifier. + */ + public String toString() { + return "wallclock(" + time.toString() + ")"; + } + + /** + * Initializes this timing specifier by adding the initial instance time + * to the owner's instance time list or setting up any event listeners. + */ + public void initialize() { + float t = owner.getRoot().convertWallclockTime(time); + instance = new InstanceTime(this, t, false); + owner.addInstanceTime(instance, isBegin); + } + + /** + * Returns whether this timing specifier is event-like (i.e., if it is + * an eventbase, accesskey or a repeat timing specifier). + */ + public boolean isEventCondition() { + return false; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableAngleOrIdentValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableAngleOrIdentValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableAngleOrIdentValue.java 8 Apr 2013 10:55:47 -0000 1.1 @@ -0,0 +1,179 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +import org.w3c.dom.svg.SVGAngle; + +/** + * An SVG angle-or-identifier value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableAngleOrIdentValue.java,v 1.1 2013/04/08 10:55:47 marcin Exp $ + */ +public class AnimatableAngleOrIdentValue extends AnimatableAngleValue { + + /** + * Whether this value is an identifier. + */ + protected boolean isIdent; + + /** + * The identifier. + */ + protected String ident; + + /** + * Creates a new, uninitialized AnimatableAngleOrIdentValue. + */ + protected AnimatableAngleOrIdentValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableAngleOrIdentValue for an angle value. + */ + public AnimatableAngleOrIdentValue(AnimationTarget target, float v, short unit) { + super(target, v, unit); + } + + /** + * Creates a new AnimatableAngleOrIdentValue for an identifier value. + */ + public AnimatableAngleOrIdentValue(AnimationTarget target, String ident) { + super(target); + this.ident = ident; + this.isIdent = true; + } + + /** + * Returns whether the value is an identifier. + */ + public boolean isIdent() { + return isIdent; + } + + /** + * Returns the identifiers. + */ + public String getIdent() { + return ident; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableAngleOrIdentValue + (target, 0, SVGAngle.SVG_ANGLETYPE_UNSPECIFIED); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + if (isIdent) { + return ident; + } + return super.getCssText(); + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableAngleOrIdentValue res; + if (result == null) { + res = new AnimatableAngleOrIdentValue(target); + } else { + res = (AnimatableAngleOrIdentValue) result; + } + + if (to == null) { + if (isIdent) { + res.hasChanged = !res.isIdent || !res.ident.equals(ident); + res.ident = ident; + res.isIdent = true; + } else { + short oldUnit = res.unit; + float oldValue = res.value; + super.interpolate(res, to, interpolation, accumulation, + multiplier); + if (res.unit != oldUnit || res.value != oldValue) { + res.hasChanged = true; + } + } + } else { + AnimatableAngleOrIdentValue toValue + = (AnimatableAngleOrIdentValue) to; + if (isIdent || toValue.isIdent) { + if (interpolation >= 0.5) { + if (res.isIdent != toValue.isIdent + || res.unit != toValue.unit + || res.value != toValue.value + || res.isIdent && toValue.isIdent + && !toValue.ident.equals(ident)) { + res.isIdent = toValue.isIdent; + res.ident = toValue.ident; + res.unit = toValue.unit; + res.value = toValue.value; + res.hasChanged = true; + } + } else { + if (res.isIdent != isIdent + || res.unit != unit + || res.value != value + || res.isIdent && isIdent + && !res.ident.equals(ident)) { + res.isIdent = isIdent; + res.ident = ident; + res.unit = unit; + res.value = value; + res.hasChanged = true; + } + } + } else { + super.interpolate(res, to, interpolation, accumulation, + multiplier); + } + } + + return res; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableAngleValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableAngleValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableAngleValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,149 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +import org.w3c.dom.svg.SVGAngle; + +/** + * An SVG angle value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableAngleValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatableAngleValue extends AnimatableNumberValue { + + /** + * The unit string representations. + */ + protected static final String[] UNITS = { + "", "", "deg", "rad", "grad" + }; + + /** + * The angle unit. + */ + protected short unit; + + /** + * Creates a new, uninitialized AnimatableAngleValue. + */ + public AnimatableAngleValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableAngleValue. + */ + public AnimatableAngleValue(AnimationTarget target, float v, short unit) { + super(target, v); + this.unit = unit; + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableAngleValue res; + if (result == null) { + res = new AnimatableAngleValue(target); + } else { + res = (AnimatableAngleValue) result; + } + + float v = value; + short u = unit; + if (to != null) { + AnimatableAngleValue toAngle = (AnimatableAngleValue) to; + if (toAngle.unit != u) { + v = rad(v, u); + v += interpolation * (rad(toAngle.value, toAngle.unit) - v); + u = SVGAngle.SVG_ANGLETYPE_RAD; + } else { + v += interpolation * (toAngle.value - v); + } + } + if (accumulation != null) { + AnimatableAngleValue accAngle = (AnimatableAngleValue) accumulation; + if (accAngle.unit != u) { + v += multiplier * rad(accAngle.value, accAngle.unit); + u = SVGAngle.SVG_ANGLETYPE_RAD; + } else { + v += multiplier * accAngle.value; + } + } + + if (res.value != v || res.unit != u) { + res.value = v; + res.unit = u; + res.hasChanged = true; + } + return res; + } + + /** + * Returns the angle unit. + */ + public short getUnit() { + return unit; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + AnimatableAngleValue o = (AnimatableAngleValue) other; + return Math.abs(rad(value, unit) - rad(o.value, o.unit)); + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableAngleValue + (target, 0, SVGAngle.SVG_ANGLETYPE_UNSPECIFIED); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + return super.getCssText() + UNITS[unit]; + } + + /** + * Converts an angle value to radians. + */ + public static float rad(float v, short unit) { + switch (unit) { + case SVGAngle.SVG_ANGLETYPE_RAD: + return v; + case SVGAngle.SVG_ANGLETYPE_GRAD: + return (float) Math.PI * v / 200; + default: + return (float) Math.PI * v / 180; + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableBooleanValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableBooleanValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableBooleanValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,117 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * A boolean value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableBooleanValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatableBooleanValue extends AnimatableValue { + + /** + * The boolean value. + */ + protected boolean value; + + /** + * Creates a new, uninitialized AnimatableBooleanValue. + */ + protected AnimatableBooleanValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableBooleanValue. + */ + public AnimatableBooleanValue(AnimationTarget target, boolean b) { + super(target); + value = b; + } + + /** + * Performs interpolation to the given value. Boolean values cannot be + * interpolated. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableBooleanValue res; + if (result == null) { + res = new AnimatableBooleanValue(target); + } else { + res = (AnimatableBooleanValue) result; + } + + boolean newValue; + if (to != null && interpolation >= 0.5) { + AnimatableBooleanValue toValue = (AnimatableBooleanValue) to; + newValue = toValue.value; + } else { + newValue = value; + } + + if (res.value != newValue) { + res.value = newValue; + res.hasChanged = true; + } + return res; + } + + /** + * Returns the boolean value. + */ + public boolean getValue() { + return value; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableBooleanValue(target, false); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + return (value)?"true":"false"; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableColorValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableColorValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableColorValue.java 8 Apr 2013 10:55:47 -0000 1.1 @@ -0,0 +1,145 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * An SVG color value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableColorValue.java,v 1.1 2013/04/08 10:55:47 marcin Exp $ + */ +public class AnimatableColorValue extends AnimatableValue { + + /** + * The red component. + */ + protected float red; + + /** + * The green component. + */ + protected float green; + + /** + * The blue component. + */ + protected float blue; + + /** + * Creates a new AnimatableColorValue. + */ + protected AnimatableColorValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableColorValue. + */ + public AnimatableColorValue(AnimationTarget target, + float r, float g, float b) { + super(target); + red = r; + green = g; + blue = b; + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableColorValue res; + if (result == null) { + res = new AnimatableColorValue(target); + } else { + res = (AnimatableColorValue) result; + } + + float oldRed = res.red; + float oldGreen = res.green; + float oldBlue = res.blue; + + res.red = red; + res.green = green; + res.blue = blue; + + AnimatableColorValue toColor = (AnimatableColorValue) to; + AnimatableColorValue accColor = (AnimatableColorValue) accumulation; + + // XXX Should handle non-sRGB colours and non-sRGB interpolation. + + if (to != null) { + res.red += interpolation * (toColor.red - res.red); + res.green += interpolation * (toColor.green - res.green); + res.blue += interpolation * (toColor.blue - res.blue); + } + + if (accumulation != null) { + res.red += multiplier * accColor.red; + res.green += multiplier * accColor.green; + res.blue += multiplier * accColor.blue; + } + + if (res.red != oldRed || res.green != oldGreen || res.blue != oldBlue) { + res.hasChanged = true; + } + return res; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return true; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + AnimatableColorValue o = (AnimatableColorValue) other; + float dr = red - o.red; + float dg = green - o.green; + float db = blue - o.blue; + return (float) Math.sqrt(dr * dr + dg * dg + db * db); + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableColorValue(target, 0f, 0f, 0f); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + return "rgb(" + Math.round(red * 255) + ',' + + Math.round(green * 255) + ',' + + Math.round(blue * 255) + ')'; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableIntegerValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableIntegerValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableIntegerValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,121 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * An integer in the animation engine. + * + * @author Cameron McCormack + * @version $Id: AnimatableIntegerValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatableIntegerValue extends AnimatableValue { + + /** + * The value. + */ + protected int value; + + /** + * Creates a new, uninitialized AnimatableIntegerValue. + */ + protected AnimatableIntegerValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableIntegerValue. + */ + public AnimatableIntegerValue(AnimationTarget target, int v) { + super(target); + value = v; + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableIntegerValue res; + if (result == null) { + res = new AnimatableIntegerValue(target); + } else { + res = (AnimatableIntegerValue) result; + } + + int v = value; + if (to != null) { + AnimatableIntegerValue toInteger = (AnimatableIntegerValue) to; + v += value + interpolation * (toInteger.getValue() - value); + } + if (accumulation != null) { + AnimatableIntegerValue accInteger = + (AnimatableIntegerValue) accumulation; + v += multiplier * accInteger.getValue(); + } + + if (res.value != v) { + res.value = v; + res.hasChanged = true; + } + return res; + } + + /** + * Returns the integer value. + */ + public int getValue() { + return value; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return true; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + AnimatableIntegerValue o = (AnimatableIntegerValue) other; + return Math.abs(value - o.value); + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableIntegerValue(target, 0); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + return Integer.toString(value); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableLengthListValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableLengthListValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableLengthListValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,224 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +import org.w3c.dom.svg.SVGLength; + +/** + * An SVG length list value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableLengthListValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatableLengthListValue extends AnimatableValue { + + /** + * The length types. + */ + protected short[] lengthTypes; + + /** + * The length values. These should be one of the constants defined in + * {@link SVGLength}. + */ + protected float[] lengthValues; + + /** + * How to interpret percentage values. These should be one of the + * {@link AnimationTarget}.PERCENTAGE_* constants. + */ + protected short percentageInterpretation; + + /** + * Creates a new, uninitialized AnimatableLengthListValue. + */ + protected AnimatableLengthListValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableLengthListValue. + */ + public AnimatableLengthListValue(AnimationTarget target, short[] types, + float[] values, short pcInterp) { + super(target); + this.lengthTypes = types; + this.lengthValues = values; + this.percentageInterpretation = pcInterp; + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableLengthListValue toLengthList = (AnimatableLengthListValue) to; + AnimatableLengthListValue accLengthList + = (AnimatableLengthListValue) accumulation; + + boolean hasTo = to != null; + boolean hasAcc = accumulation != null; + boolean canInterpolate = + !(hasTo && toLengthList.lengthTypes.length != lengthTypes.length) + && !(hasAcc && accLengthList.lengthTypes.length != lengthTypes.length); + + short[] baseLengthTypes; + float[] baseLengthValues; + if (!canInterpolate && hasTo && interpolation >= 0.5) { + baseLengthTypes = toLengthList.lengthTypes; + baseLengthValues = toLengthList.lengthValues; + } else { + baseLengthTypes = lengthTypes; + baseLengthValues = lengthValues; + } + int len = baseLengthTypes.length; + + AnimatableLengthListValue res; + if (result == null) { + res = new AnimatableLengthListValue(target); + res.lengthTypes = new short[len]; + res.lengthValues = new float[len]; + } else { + res = (AnimatableLengthListValue) result; + if (res.lengthTypes == null || res.lengthTypes.length != len) { + res.lengthTypes = new short[len]; + res.lengthValues = new float[len]; + } + } + + res.hasChanged = + percentageInterpretation != res.percentageInterpretation; + res.percentageInterpretation = percentageInterpretation; + + for (int i = 0; i < len; i++) { + float toV = 0, accV = 0; + short newLengthType = baseLengthTypes[i]; + float newLengthValue = baseLengthValues[i]; + if (canInterpolate) { + if (hasTo && !AnimatableLengthValue.compatibleTypes + (newLengthType, + percentageInterpretation, + toLengthList.lengthTypes[i], + toLengthList.percentageInterpretation) + || hasAcc && !AnimatableLengthValue.compatibleTypes + (newLengthType, + percentageInterpretation, + accLengthList.lengthTypes[i], + accLengthList.percentageInterpretation)) { + newLengthValue = target.svgToUserSpace + (newLengthValue, newLengthType, + percentageInterpretation); + newLengthType = SVGLength.SVG_LENGTHTYPE_NUMBER; + if (hasTo) { + toV = to.target.svgToUserSpace + (toLengthList.lengthValues[i], + toLengthList.lengthTypes[i], + toLengthList.percentageInterpretation); + } + if (hasAcc) { + accV = accumulation.target.svgToUserSpace + (accLengthList.lengthValues[i], + accLengthList.lengthTypes[i], + accLengthList.percentageInterpretation); + } + } else { + if (hasTo) { + toV = toLengthList.lengthValues[i]; + } + if (hasAcc) { + accV = accLengthList.lengthValues[i]; + } + } + newLengthValue += + interpolation * (toV - newLengthValue) + + multiplier * accV; + } + if (!res.hasChanged) { + res.hasChanged = newLengthType != res.lengthTypes[i] + || newLengthValue != res.lengthValues[i]; + } + res.lengthTypes[i] = newLengthType; + res.lengthValues[i] = newLengthValue; + } + + return res; + } + + /** + * Gets the length types. + */ + public short[] getLengthTypes() { + return lengthTypes; + } + + /** + * Gets the length values. + */ + public float[] getLengthValues() { + return lengthValues; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + float[] vs = new float[lengthValues.length]; + return new AnimatableLengthListValue + (target, lengthTypes, vs, percentageInterpretation); + } + + /** + * Returns the CSS text representation of the value. + * Length lists can never be used for CSS properties. + */ + public String getCssText() { + StringBuffer sb = new StringBuffer(); + if (lengthValues.length > 0) { + sb.append(formatNumber(lengthValues[0])); + sb.append(AnimatableLengthValue.UNITS[lengthTypes[0] - 1]); + } + for (int i = 1; i < lengthValues.length; i++) { + sb.append(','); + sb.append(formatNumber(lengthValues[i])); + sb.append(AnimatableLengthValue.UNITS[lengthTypes[i] - 1]); + } + return sb.toString(); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableLengthOrIdentValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableLengthOrIdentValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableLengthOrIdentValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,185 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +import org.w3c.dom.svg.SVGLength; + +/** + * An SVG length-or-identifier value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableLengthOrIdentValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatableLengthOrIdentValue extends AnimatableLengthValue { + + /** + * Whether this value is an identifier. + */ + protected boolean isIdent; + + /** + * The identifier. + */ + protected String ident; + + /** + * Creates a new, uninitialized AnimatableLengthOrIdentValue. + */ + protected AnimatableLengthOrIdentValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableLengthOrIdentValue for a length value. + */ + public AnimatableLengthOrIdentValue(AnimationTarget target, short type, + float v, short pcInterp) { + super(target, type, v, pcInterp); + } + + /** + * Creates a new AnimatableLengthOrIdentValue for an identifier value. + */ + public AnimatableLengthOrIdentValue(AnimationTarget target, String ident) { + super(target); + this.ident = ident; + this.isIdent = true; + } + + /** + * Returns whether this value is an identifier or a length. + */ + public boolean isIdent() { + return isIdent; + } + + /** + * Returns the identifier. + */ + public String getIdent() { + return ident; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableLengthOrIdentValue + (target, SVGLength.SVG_LENGTHTYPE_NUMBER, 0f, + percentageInterpretation); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + if (isIdent) { + return ident; + } + return super.getCssText(); + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableLengthOrIdentValue res; + if (result == null) { + res = new AnimatableLengthOrIdentValue(target); + } else { + res = (AnimatableLengthOrIdentValue) result; + } + + if (to == null) { + if (isIdent) { + res.hasChanged = !res.isIdent || !res.ident.equals(ident); + res.ident = ident; + res.isIdent = true; + } else { + short oldLengthType = res.lengthType; + float oldLengthValue = res.lengthValue; + short oldPercentageInterpretation = res.percentageInterpretation; + super.interpolate(res, to, interpolation, accumulation, + multiplier); + if (res.lengthType != oldLengthType + || res.lengthValue != oldLengthValue + || res.percentageInterpretation + != oldPercentageInterpretation) { + res.hasChanged = true; + } + } + } else { + AnimatableLengthOrIdentValue toValue + = (AnimatableLengthOrIdentValue) to; + if (isIdent || toValue.isIdent) { + if (interpolation >= 0.5) { + if (res.isIdent != toValue.isIdent + || res.lengthType != toValue.lengthType + || res.lengthValue != toValue.lengthValue + || res.isIdent && toValue.isIdent + && !toValue.ident.equals(ident)) { + res.isIdent = toValue.isIdent; + res.ident = toValue.ident; + res.lengthType = toValue.lengthType; + res.lengthValue = toValue.lengthValue; + res.hasChanged = true; + } + } else { + if (res.isIdent != isIdent + || res.lengthType != lengthType + || res.lengthValue != lengthValue + || res.isIdent && isIdent + && !res.ident.equals(ident)) { + res.isIdent = isIdent; + res.ident = ident; + res.ident = ident; + res.lengthType = lengthType; + res.hasChanged = true; + } + } + } else { + super.interpolate(res, to, interpolation, accumulation, + multiplier); + } + } + + return res; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableLengthValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableLengthValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableLengthValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,214 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +import org.w3c.dom.svg.SVGLength; + +/** + * An SVG length value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableLengthValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatableLengthValue extends AnimatableValue { + + /** + * Length units. + */ + protected static final String[] UNITS = { + "", "%", "em", "ex", "px", "cm", "mm", "in", "pt", "pc" + }; + + /** + * The length type. + */ + protected short lengthType; + + /** + * The length value. This should be one of the constants defined in + * {@link SVGLength}. + */ + protected float lengthValue; + + /** + * How to interpret percentage values. One of the + * {@link AnimationTarget}.PERCENTAGE_* constants. + */ + protected short percentageInterpretation; + + /** + * Creates a new AnimatableLengthValue with no length. + */ + protected AnimatableLengthValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableLengthValue. + */ + public AnimatableLengthValue(AnimationTarget target, short type, float v, + short pcInterp) { + super(target); + lengthType = type; + lengthValue = v; + percentageInterpretation = pcInterp; + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableLengthValue res; + if (result == null) { + res = new AnimatableLengthValue(target); + } else { + res = (AnimatableLengthValue) result; + } + + short oldLengthType = res.lengthType; + float oldLengthValue = res.lengthValue; + short oldPercentageInterpretation = res.percentageInterpretation; + + res.lengthType = lengthType; + res.lengthValue = lengthValue; + res.percentageInterpretation = percentageInterpretation; + + if (to != null) { + AnimatableLengthValue toLength = (AnimatableLengthValue) to; + float toValue; + if (!compatibleTypes + (res.lengthType, res.percentageInterpretation, + toLength.lengthType, toLength.percentageInterpretation)) { + res.lengthValue = target.svgToUserSpace + (res.lengthValue, res.lengthType, + res.percentageInterpretation); + res.lengthType = SVGLength.SVG_LENGTHTYPE_NUMBER; + toValue = toLength.target.svgToUserSpace + (toLength.lengthValue, toLength.lengthType, + toLength.percentageInterpretation); + } else { + toValue = toLength.lengthValue; + } + res.lengthValue += interpolation * (toValue - res.lengthValue); + } + + if (accumulation != null) { + AnimatableLengthValue accLength = (AnimatableLengthValue) accumulation; + float accValue; + if (!compatibleTypes + (res.lengthType, res.percentageInterpretation, + accLength.lengthType, + accLength.percentageInterpretation)) { + res.lengthValue = target.svgToUserSpace + (res.lengthValue, res.lengthType, + res.percentageInterpretation); + res.lengthType = SVGLength.SVG_LENGTHTYPE_NUMBER; + accValue = accLength.target.svgToUserSpace + (accLength.lengthValue, accLength.lengthType, + accLength.percentageInterpretation); + } else { + accValue = accLength.lengthValue; + } + res.lengthValue += multiplier * accValue; + } + + if (oldPercentageInterpretation != res.percentageInterpretation + || oldLengthType != res.lengthType + || oldLengthValue != res.lengthValue) { + res.hasChanged = true; + } + return res; + } + + /** + * Determines if two SVG length types are compatible. + * @param t1 the first SVG length type + * @param pi1 the first percentage interpretation type + * @param t2 the second SVG length type + * @param pi2 the second percentage interpretation type + */ + public static boolean compatibleTypes(short t1, short pi1, short t2, + short pi2) { + return t1 == t2 + && (t1 != SVGLength.SVG_LENGTHTYPE_PERCENTAGE || pi1 == pi2) + || t1 == SVGLength.SVG_LENGTHTYPE_NUMBER + && t2 == SVGLength.SVG_LENGTHTYPE_PX + || t1 == SVGLength.SVG_LENGTHTYPE_PX + && t2 == SVGLength.SVG_LENGTHTYPE_NUMBER; + } + + /** + * Returns the unit type of this length value. + */ + public int getLengthType() { + return lengthType; + } + + /** + * Returns the magnitude of this length value. + */ + public float getLengthValue() { + return lengthValue; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return true; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + AnimatableLengthValue o = (AnimatableLengthValue) other; + float v1 = target.svgToUserSpace(lengthValue, lengthType, + percentageInterpretation); + float v2 = target.svgToUserSpace(o.lengthValue, o.lengthType, + o.percentageInterpretation); + return Math.abs(v1 - v2); + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableLengthValue + (target, SVGLength.SVG_LENGTHTYPE_NUMBER, 0f, + percentageInterpretation); + } + + /** + * Returns the CSS text representation of the value. This could use + * org.apache.batik.css.engine.value.FloatValue.getCssText, but we don't + * want a dependency on the CSS package. + */ + public String getCssText() { + return formatNumber(lengthValue) + UNITS[lengthType - 1]; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableMotionPointValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableMotionPointValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableMotionPointValue.java 8 Apr 2013 10:55:49 -0000 1.1 @@ -0,0 +1,169 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * A point value in the animation system from a motion animation. + * + * @author Cameron McCormack + * @version $Id: AnimatableMotionPointValue.java,v 1.1 2013/04/08 10:55:49 marcin Exp $ + */ +public class AnimatableMotionPointValue extends AnimatableValue { + + /** + * The x coordinate. + */ + protected float x; + + /** + * The y coordinate. + */ + protected float y; + + /** + * The rotation angle in radians. + */ + protected float angle; + + /** + * Creates a new, uninitialized AnimatableMotionPointValue. + */ + protected AnimatableMotionPointValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableMotionPointValue with one x. + */ + public AnimatableMotionPointValue(AnimationTarget target, float x, float y, + float angle) { + super(target); + this.x = x; + this.y = y; + this.angle = angle; + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableMotionPointValue res; + if (result == null) { + res = new AnimatableMotionPointValue(target); + } else { + res = (AnimatableMotionPointValue) result; + } + + float newX = x, newY = y, newAngle = angle; + int angleCount = 1; + + if (to != null) { + AnimatableMotionPointValue toValue = + (AnimatableMotionPointValue) to; + newX += interpolation * (toValue.x - x); + newY += interpolation * (toValue.y - y); + newAngle += toValue.angle; + angleCount++; + } + if (accumulation != null && multiplier != 0) { + AnimatableMotionPointValue accValue = + (AnimatableMotionPointValue) accumulation; + newX += multiplier * accValue.x; + newY += multiplier * accValue.y; + newAngle += accValue.angle; + angleCount++; + } + newAngle /= angleCount; + + if (res.x != newX || res.y != newY || res.angle != newAngle) { + res.x = newX; + res.y = newY; + res.angle = newAngle; + res.hasChanged = true; + } + return res; + } + + /** + * Returns the x coordinate. + */ + public float getX() { + return x; + } + + /** + * Returns the y coordinate. + */ + public float getY() { + return y; + } + + /** + * Returns the rotation angle. + */ + public float getAngle() { + return angle; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return true; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + AnimatableMotionPointValue o = (AnimatableMotionPointValue) other; + float dx = x - o.x; + float dy = y - o.y; + return (float) Math.sqrt(dx * dx + dy * dy); + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableMotionPointValue(target, 0f, 0f, 0f); + } + + /** + * Returns a string representation of this object. + */ + public String toStringRep() { + StringBuffer sb = new StringBuffer(); + sb.append(formatNumber(x)); + sb.append(','); + sb.append(formatNumber(y)); + sb.append(','); + sb.append(formatNumber(angle)); + sb.append("rad"); + return sb.toString(); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberListValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberListValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberListValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,151 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * A number list in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableNumberListValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatableNumberListValue extends AnimatableValue { + + /** + * The numbers. + */ + protected float[] numbers; + + /** + * Creates a new, uninitialized AnimatableNumberListValue. + */ + protected AnimatableNumberListValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableNumberListValue. + */ + public AnimatableNumberListValue(AnimationTarget target, float[] numbers) { + super(target); + this.numbers = numbers; + } + + /** + * Performs interpolation to the given value. Number list values cannot + * be interpolated. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableNumberListValue toNumList = (AnimatableNumberListValue) to; + AnimatableNumberListValue accNumList = + (AnimatableNumberListValue) accumulation; + + boolean hasTo = to != null; + boolean hasAcc = accumulation != null; + boolean canInterpolate = + !(hasTo && toNumList.numbers.length != numbers.length) + && !(hasAcc && accNumList.numbers.length != numbers.length); + + float[] baseValues; + if (!canInterpolate && hasTo && interpolation >= 0.5) { + baseValues = toNumList.numbers; + } else { + baseValues = numbers; + } + int len = baseValues.length; + + AnimatableNumberListValue res; + if (result == null) { + res = new AnimatableNumberListValue(target); + res.numbers = new float[len]; + } else { + res = (AnimatableNumberListValue) result; + if (res.numbers == null || res.numbers.length != len) { + res.numbers = new float[len]; + } + } + + for (int i = 0; i < len; i++) { + float newValue = baseValues[i]; + if (canInterpolate) { + if (hasTo) { + newValue += interpolation * (toNumList.numbers[i] - newValue); + } + if (hasAcc) { + newValue += multiplier * accNumList.numbers[i]; + } + } + if (res.numbers[i] != newValue) { + res.numbers[i] = newValue; + res.hasChanged = true; + } + } + + return res; + } + + /** + * Gets the numbers. + */ + public float[] getNumbers() { + return numbers; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + float[] ns = new float[numbers.length]; + return new AnimatableNumberListValue(target, ns); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + StringBuffer sb = new StringBuffer(); + sb.append(numbers[0]); + for (int i = 1; i < numbers.length; i++) { + sb.append(' '); + sb.append(numbers[i]); + } + return sb.toString(); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberOptionalNumberValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberOptionalNumberValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberOptionalNumberValue.java 8 Apr 2013 10:55:47 -0000 1.1 @@ -0,0 +1,174 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * A number-optional-number value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableNumberOptionalNumberValue.java,v 1.1 2013/04/08 10:55:47 marcin Exp $ + */ +public class AnimatableNumberOptionalNumberValue extends AnimatableValue { + + /** + * The first number. + */ + protected float number; + + /** + * Whether the optional number is present. + */ + protected boolean hasOptionalNumber; + + /** + * The optional number. + */ + protected float optionalNumber; + + /** + * Creates a new, uninitialized AnimatableNumberOptionalNumberValue. + */ + protected AnimatableNumberOptionalNumberValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableNumberOptionalNumberValue with one number. + */ + public AnimatableNumberOptionalNumberValue(AnimationTarget target, + float n) { + super(target); + number = n; + } + + /** + * Creates a new AnimatableNumberOptionalNumberValue with two numbers. + */ + public AnimatableNumberOptionalNumberValue(AnimationTarget target, float n, + float on) { + super(target); + number = n; + optionalNumber = on; + hasOptionalNumber = true; + } + + /** + * Performs interpolation to the given value. Number-optional-number + * values cannot be interpolated. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableNumberOptionalNumberValue res; + if (result == null) { + res = new AnimatableNumberOptionalNumberValue(target); + } else { + res = (AnimatableNumberOptionalNumberValue) result; + } + + float newNumber, newOptionalNumber; + boolean newHasOptionalNumber; + + if (to != null && interpolation >= 0.5) { + AnimatableNumberOptionalNumberValue toValue + = (AnimatableNumberOptionalNumberValue) to; + newNumber = toValue.number; + newOptionalNumber = toValue.optionalNumber; + newHasOptionalNumber = toValue.hasOptionalNumber; + } else { + newNumber = number; + newOptionalNumber = optionalNumber; + newHasOptionalNumber = hasOptionalNumber; + } + + if (res.number != newNumber + || res.hasOptionalNumber != newHasOptionalNumber + || res.optionalNumber != newOptionalNumber) { + res.number = number; + res.optionalNumber = optionalNumber; + res.hasOptionalNumber = hasOptionalNumber; + res.hasChanged = true; + } + return res; + } + + /** + * Returns the first number. + */ + public float getNumber() { + return number; + } + + /** + * Returns whether the optional number is present. + */ + public boolean hasOptionalNumber() { + return hasOptionalNumber; + } + + /** + * Returns the optional number. + */ + public float getOptionalNumber() { + return optionalNumber; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + if (hasOptionalNumber) { + return new AnimatableNumberOptionalNumberValue(target, 0f, 0f); + } + return new AnimatableNumberOptionalNumberValue(target, 0f); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + StringBuffer sb = new StringBuffer(); + sb.append(formatNumber(number)); + if (hasOptionalNumber) { + sb.append(' '); + sb.append(formatNumber(optionalNumber)); + } + return sb.toString(); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberOrIdentValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberOrIdentValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberOrIdentValue.java 8 Apr 2013 10:55:47 -0000 1.1 @@ -0,0 +1,177 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * A number-or-identifier value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableNumberOrIdentValue.java,v 1.1 2013/04/08 10:55:47 marcin Exp $ + */ +public class AnimatableNumberOrIdentValue extends AnimatableNumberValue { + + /** + * Whether this value is an identifier. + */ + protected boolean isIdent; + + /** + * The identifier. + */ + protected String ident; + + /** + * Whether numbers should be considered as numeric keywords, as with the + * font-weight property. + */ + protected boolean numericIdent; + + /** + * Creates a new, uninitialized AnimatableNumberOrIdentValue. + */ + protected AnimatableNumberOrIdentValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableNumberOrIdentValue for a Number value. + */ + public AnimatableNumberOrIdentValue(AnimationTarget target, float v, + boolean numericIdent) { + super(target, v); + this.numericIdent = numericIdent; + } + + /** + * Creates a new AnimatableNumberOrIdentValue for an identifier value. + */ + public AnimatableNumberOrIdentValue(AnimationTarget target, String ident) { + super(target); + this.ident = ident; + this.isIdent = true; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableNumberOrIdentValue(target, 0f, numericIdent); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + if (isIdent) { + return ident; + } + if (numericIdent) { + return Integer.toString((int) value); + } + return super.getCssText(); + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableNumberOrIdentValue res; + if (result == null) { + res = new AnimatableNumberOrIdentValue(target); + } else { + res = (AnimatableNumberOrIdentValue) result; + } + + if (to == null) { + if (isIdent) { + res.hasChanged = !res.isIdent || !res.ident.equals(ident); + res.ident = ident; + res.isIdent = true; + } else if (numericIdent) { + res.hasChanged = res.value != value || res.isIdent; + res.value = value; + res.isIdent = false; + res.hasChanged = true; + res.numericIdent = true; + } else { + float oldValue = res.value; + super.interpolate(res, to, interpolation, accumulation, + multiplier); + res.numericIdent = false; + if (res.value != oldValue) { + res.hasChanged = true; + } + } + } else { + AnimatableNumberOrIdentValue toValue + = (AnimatableNumberOrIdentValue) to; + if (isIdent || toValue.isIdent || numericIdent) { + if (interpolation >= 0.5) { + if (res.isIdent != toValue.isIdent + || res.value != toValue.value + || res.isIdent && toValue.isIdent + && !toValue.ident.equals(ident)) { + res.isIdent = toValue.isIdent; + res.ident = toValue.ident; + res.value = toValue.value; + res.numericIdent = toValue.numericIdent; + res.hasChanged = true; + } + } else { + if (res.isIdent != isIdent + || res.value != value + || res.isIdent && isIdent + && !res.ident.equals(ident)) { + res.isIdent = isIdent; + res.ident = ident; + res.value = value; + res.numericIdent = numericIdent; + res.hasChanged = true; + } + } + } else { + super.interpolate(res, to, interpolation, accumulation, + multiplier); + res.numericIdent = false; + } + } + return res; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberOrPercentageValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberOrPercentageValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberOrPercentageValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,155 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * A number-or-percentage value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableNumberOrPercentageValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatableNumberOrPercentageValue extends AnimatableNumberValue { + + /** + * Whether the number is a percentage. + */ + protected boolean isPercentage; + + /** + * Creates a new, uninitialized AnimatableNumberOrPercentageValue. + */ + protected AnimatableNumberOrPercentageValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableNumberOrPercentageValue with a number. + */ + public AnimatableNumberOrPercentageValue(AnimationTarget target, float n) { + super(target, n); + } + + /** + * Creates a new AnimatableNumberOrPercentageValue with either a number + * or a percentage. + */ + public AnimatableNumberOrPercentageValue(AnimationTarget target, float n, + boolean isPercentage) { + super(target, n); + this.isPercentage = isPercentage; + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableNumberOrPercentageValue res; + if (result == null) { + res = new AnimatableNumberOrPercentageValue(target); + } else { + res = (AnimatableNumberOrPercentageValue) result; + } + + float newValue; + boolean newIsPercentage; + + AnimatableNumberOrPercentageValue toValue + = (AnimatableNumberOrPercentageValue) to; + AnimatableNumberOrPercentageValue accValue + = (AnimatableNumberOrPercentageValue) accumulation; + + if (to != null) { + if (toValue.isPercentage == isPercentage) { + newValue = value + interpolation * (toValue.value - value); + newIsPercentage = isPercentage; + } else { + if (interpolation >= 0.5) { + newValue = toValue.value; + newIsPercentage = toValue.isPercentage; + } else { + newValue = value; + newIsPercentage = isPercentage; + } + } + } else { + newValue = value; + newIsPercentage = isPercentage; + } + + if (accumulation != null && accValue.isPercentage == newIsPercentage) { + newValue += multiplier * accValue.value; + } + + if (res.value != newValue + || res.isPercentage != newIsPercentage) { + res.value = newValue; + res.isPercentage = newIsPercentage; + res.hasChanged = true; + } + return res; + } + + /** + * Returns whether the value is a percentage. + */ + public boolean isPercentage() { + return isPercentage; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableNumberOrPercentageValue(target, 0, isPercentage); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + StringBuffer sb = new StringBuffer(); + sb.append(formatNumber(value)); + if (isPercentage) { + sb.append('%'); + } + return sb.toString(); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableNumberValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,120 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * A number value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableNumberValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatableNumberValue extends AnimatableValue { + + /** + * The value. + */ + protected float value; + + /** + * Creates a new, uninitialized AnimatableNumberValue. + */ + protected AnimatableNumberValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableNumberValue. + */ + public AnimatableNumberValue(AnimationTarget target, float v) { + super(target); + value = v; + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableNumberValue res; + if (result == null) { + res = new AnimatableNumberValue(target); + } else { + res = (AnimatableNumberValue) result; + } + + float v = value; + if (to != null) { + AnimatableNumberValue toNumber = (AnimatableNumberValue) to; + v += interpolation * (toNumber.value - value); + } + if (accumulation != null) { + AnimatableNumberValue accNumber = (AnimatableNumberValue) accumulation; + v += multiplier * accNumber.value; + } + + if (res.value != v) { + res.value = v; + res.hasChanged = true; + } + return res; + } + + /** + * Returns the number value. + */ + public float getValue() { + return value; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return true; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + AnimatableNumberValue o = (AnimatableNumberValue) other; + return Math.abs(value - o.value); + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableNumberValue(target, 0); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + return formatNumber(value); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePaintValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePaintValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePaintValue.java 8 Apr 2013 10:55:49 -0000 1.1 @@ -0,0 +1,283 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * An SVG paint value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatablePaintValue.java,v 1.1 2013/04/08 10:55:49 marcin Exp $ + */ +public class AnimatablePaintValue extends AnimatableColorValue { + + // Constants for paintType. + public static final int PAINT_NONE = 0; + public static final int PAINT_CURRENT_COLOR = 1; + public static final int PAINT_COLOR = 2; + public static final int PAINT_URI = 3; + public static final int PAINT_URI_NONE = 4; + public static final int PAINT_URI_CURRENT_COLOR = 5; + public static final int PAINT_URI_COLOR = 6; + public static final int PAINT_INHERIT = 7; + + /** + * The type of paint. + */ + protected int paintType; + + /** + * The URI of the referenced paint server. + */ + protected String uri; + + /** + * Creates a new, uninitialized AnimatablePaintValue. + */ + protected AnimatablePaintValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatablePaintValue. + */ + protected AnimatablePaintValue(AnimationTarget target, float r, float g, + float b) { + super(target, r, g, b); + } + + /** + * Creates a new AnimatablePaintValue for a 'none' value. + */ + public static AnimatablePaintValue createNonePaintValue + (AnimationTarget target) { + AnimatablePaintValue v = new AnimatablePaintValue(target); + v.paintType = PAINT_NONE; + return v; + } + + /** + * Creates a new AnimatablePaintValue for a 'currentColor' value. + */ + public static AnimatablePaintValue createCurrentColorPaintValue + (AnimationTarget target) { + AnimatablePaintValue v = new AnimatablePaintValue(target); + v.paintType = PAINT_CURRENT_COLOR; + return v; + } + + /** + * Creates a new AnimatablePaintValue for a color value. + */ + public static AnimatablePaintValue createColorPaintValue + (AnimationTarget target, float r, float g, float b) { + AnimatablePaintValue v = new AnimatablePaintValue(target, r, g, b); + v.paintType = PAINT_COLOR; + return v; + } + + /** + * Creates a new AnimatablePaintValue for a URI reference. + */ + public static AnimatablePaintValue createURIPaintValue + (AnimationTarget target, String uri) { + AnimatablePaintValue v = new AnimatablePaintValue(target); + v.uri = uri; + v.paintType = PAINT_URI; + return v; + } + + /** + * Creates a new AnimatablePaintValue for a URI reference with a + * 'none' fallback. + */ + public static AnimatablePaintValue createURINonePaintValue + (AnimationTarget target, String uri) { + AnimatablePaintValue v = new AnimatablePaintValue(target); + v.uri = uri; + v.paintType = PAINT_URI_NONE; + return v; + } + + /** + * Creates a new AnimatablePaintValue for a URI reference with a + * 'currentColor' fallback. + */ + public static AnimatablePaintValue createURICurrentColorPaintValue + (AnimationTarget target, String uri) { + AnimatablePaintValue v = new AnimatablePaintValue(target); + v.uri = uri; + v.paintType = PAINT_URI_CURRENT_COLOR; + return v; + } + + /** + * Creates a new AnimatablePaintValue for a URI reference with a + * color fallback. + */ + public static AnimatablePaintValue createURIColorPaintValue + (AnimationTarget target, String uri, float r, float g, float b) { + AnimatablePaintValue v = new AnimatablePaintValue(target, r, g, b); + v.uri = uri; + v.paintType = PAINT_URI_COLOR; + return v; + } + + /** + * Creates a new AnimatablePaintValue for a 'inherit' value. + */ + public static AnimatablePaintValue createInheritPaintValue + (AnimationTarget target) { + AnimatablePaintValue v = new AnimatablePaintValue(target); + v.paintType = PAINT_INHERIT; + return v; + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatablePaintValue res; + if (result == null) { + res = new AnimatablePaintValue(target); + } else { + res = (AnimatablePaintValue) result; + } + + if (paintType == PAINT_COLOR) { + boolean canInterpolate = true; + if (to != null) { + AnimatablePaintValue toPaint = (AnimatablePaintValue) to; + canInterpolate = toPaint.paintType == PAINT_COLOR; + } + if (accumulation != null) { + AnimatablePaintValue accPaint = + (AnimatablePaintValue) accumulation; + canInterpolate = + canInterpolate && accPaint.paintType == PAINT_COLOR; + } + if (canInterpolate) { + res.paintType = PAINT_COLOR; + return super.interpolate + (res, to, interpolation, accumulation, multiplier); + } + } + + int newPaintType; + String newURI; + float newRed, newGreen, newBlue; + + if (to != null && interpolation >= 0.5) { + AnimatablePaintValue toValue = (AnimatablePaintValue) to; + newPaintType = toValue.paintType; + newURI = toValue.uri; + newRed = toValue.red; + newGreen = toValue.green; + newBlue = toValue.blue; + } else { + newPaintType = paintType; + newURI = uri; + newRed = red; + newGreen = green; + newBlue = blue; + } + + if (res.paintType != newPaintType + || res.uri == null + || !res.uri.equals(newURI) + || res.red != newRed + || res.green != newGreen + || res.blue != newBlue) { + res.paintType = newPaintType; + res.uri = newURI; + res.red = newRed; + res.green = newGreen; + res.blue = newBlue; + res.hasChanged = true; + } + + return res; + } + + /** + * Returns the type of paint this value represents. + */ + public int getPaintType() { + return paintType; + } + + /** + * Returns the paint server URI. + */ + public String getURI() { + return uri; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return AnimatablePaintValue.createColorPaintValue(target, 0f, 0f, 0f); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + switch (paintType) { + case PAINT_NONE: + return "none"; + case PAINT_CURRENT_COLOR: + return "currentColor"; + case PAINT_COLOR: + return super.getCssText(); + case PAINT_URI: + return "url(" + uri + ")"; + case PAINT_URI_NONE: + return "url(" + uri + ") none"; + case PAINT_URI_CURRENT_COLOR: + return "url(" + uri + ") currentColor"; + case PAINT_URI_COLOR: + return "url(" + uri + ") " + super.getCssText(); + default: // PAINT_INHERIT + return "inherit"; + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePathDataValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePathDataValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePathDataValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,198 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import java.util.Arrays; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * An SVG path value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatablePathDataValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatablePathDataValue extends AnimatableValue { + + /** + * The path commands. These must be one of the PATHSEG_* + * constants defined in {@link org.w3c.dom.svg.SVGPathSeg}. + */ + protected short[] commands; + + /** + * The path parameters. Also includes the booleans. + */ + protected float[] parameters; + + /** + * Creates a new, uninitialized AnimatablePathDataValue. + */ + protected AnimatablePathDataValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatablePathDataValue. + */ + public AnimatablePathDataValue(AnimationTarget target, short[] commands, + float[] parameters) { + super(target); + this.commands = commands; + this.parameters = parameters; + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatablePathDataValue toValue = (AnimatablePathDataValue) to; + AnimatablePathDataValue accValue = + (AnimatablePathDataValue) accumulation; + + boolean hasTo = to != null; + boolean hasAcc = accumulation != null; + boolean canInterpolate = hasTo + && toValue.parameters.length == parameters.length + && Arrays.equals(toValue.commands, commands); + boolean canAccumulate = hasAcc + && accValue.parameters.length == parameters.length + && Arrays.equals(accValue.commands, commands); + + AnimatablePathDataValue base; + if (!canInterpolate && hasTo && interpolation >= 0.5) { + base = toValue; + } else { + base = this; + } + int cmdCount = base.commands.length; + int paramCount = base.parameters.length; + + AnimatablePathDataValue res; + if (result == null) { + res = new AnimatablePathDataValue(target); + res.commands = new short[cmdCount]; + res.parameters = new float[paramCount]; + System.arraycopy(base.commands, 0, res.commands, 0, cmdCount); + } else { + res = (AnimatablePathDataValue) result; + if (res.commands == null || res.commands.length != cmdCount) { + res.commands = new short[cmdCount]; + System.arraycopy(base.commands, 0, res.commands, 0, cmdCount); + res.hasChanged = true; + } else { + if (!Arrays.equals(base.commands, res.commands)) { + System.arraycopy(base.commands, 0, res.commands, 0, + cmdCount); + res.hasChanged = true; + } + } + } + + for (int i = 0; i < paramCount; i++) { + float newValue = base.parameters[i]; + if (canInterpolate) { + newValue += interpolation * (toValue.parameters[i] - newValue); + } + if (canAccumulate) { + newValue += multiplier * accValue.parameters[i]; + } + if (res.parameters[i] != newValue) { + res.parameters[i] = newValue; + res.hasChanged = true; + } + } + + return res; + } + + /** + * Returns the array of path data commands. + */ + public short[] getCommands() { + return commands; + } + + /** + * Returns the array of path data parameters. + */ + public float[] getParameters() { + return parameters; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + short[] cmds = new short[commands.length]; + System.arraycopy(commands, 0, cmds, 0, commands.length); + float[] params = new float[parameters.length]; + return new AnimatablePathDataValue(target, cmds, params); + } + + /** + * The path data commands. + */ + protected static final char[] PATH_COMMANDS = { + ' ', 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a', 'H', 'h', + 'V', 'v', 'S', 's', 'T', 't' + }; + + /** + * The number of parameters for each path command. + */ + protected static final int[] PATH_PARAMS = { + 0, 0, 2, 2, 2, 2, 6, 6, 4, 4, 7, 7, 1, 1, 1, 1, 4, 4, 2, 2 + }; + + /** + * Returns a string representation of this object. + */ + public String toStringRep() { + StringBuffer sb = new StringBuffer(); + int k = 0; + for (int i = 0; i < commands.length; i++) { + sb.append(PATH_COMMANDS[commands[i]]); + for (int j = 0; j < PATH_PARAMS[commands[i]]; j++) { + sb.append(' '); + sb.append(parameters[k++]); + } + } + return sb.toString(); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePercentageValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePercentageValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePercentageValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,73 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * A percentage value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatablePercentageValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatablePercentageValue extends AnimatableNumberValue { + + /** + * Creates a new, uninitialized AnimatablePercentageValue. + */ + protected AnimatablePercentageValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatablePercentageValue. + */ + public AnimatablePercentageValue(AnimationTarget target, float v) { + super(target, v); + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + if (result == null) { + result = new AnimatablePercentageValue(target); + } + return super.interpolate + (result, to, interpolation, accumulation, multiplier); + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatablePercentageValue(target, 0); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + return super.getCssText() + "%"; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePointListValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePointListValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePointListValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,83 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * An SVG point list value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatablePointListValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatablePointListValue extends AnimatableNumberListValue { + + /** + * Creates a new, uninitialized AnimatablePointListValue. + */ + protected AnimatablePointListValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatablePointListValue. + */ + public AnimatablePointListValue(AnimationTarget target, float[] numbers) { + super(target, numbers); + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + if (result == null) { + result = new AnimatablePointListValue(target); + } + return super.interpolate + (result, to, interpolation, accumulation, multiplier); + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + float[] ns = new float[numbers.length]; + return new AnimatablePointListValue(target, ns); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePreserveAspectRatioValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePreserveAspectRatioValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatablePreserveAspectRatioValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,176 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; +import org.apache.batik.util.SVGConstants; + +import org.w3c.dom.svg.SVGPreserveAspectRatio; + +/** + * An SVG preserveAspectRatio value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatablePreserveAspectRatioValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatablePreserveAspectRatioValue extends AnimatableValue { + + /** + * Strings for the 'align' values. + */ + protected static final String[] ALIGN_VALUES = { + null, + SVGConstants.SVG_NONE_VALUE, + SVGConstants.SVG_XMINYMIN_VALUE, + SVGConstants.SVG_XMIDYMIN_VALUE, + SVGConstants.SVG_XMAXYMIN_VALUE, + SVGConstants.SVG_XMINYMID_VALUE, + SVGConstants.SVG_XMIDYMID_VALUE, + SVGConstants.SVG_XMAXYMID_VALUE, + SVGConstants.SVG_XMINYMAX_VALUE, + SVGConstants.SVG_XMIDYMAX_VALUE, + SVGConstants.SVG_XMAXYMAX_VALUE + }; + + /** + * Strings for the 'meet-or-slice' values. + */ + protected static final String[] MEET_OR_SLICE_VALUES = { + null, + SVGConstants.SVG_MEET_VALUE, + SVGConstants.SVG_SLICE_VALUE + }; + + /** + * The align value. + */ + protected short align; + + /** + * The meet-or-slice value. + */ + protected short meetOrSlice; + + /** + * Creates a new, uninitialized AnimatablePreserveAspectRatioValue. + */ + protected AnimatablePreserveAspectRatioValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatablePreserveAspectRatioValue. + */ + public AnimatablePreserveAspectRatioValue(AnimationTarget target, + short align, short meetOrSlice) { + super(target); + this.align = align; + this.meetOrSlice = meetOrSlice; + } + + /** + * Performs interpolation to the given value. Preserve aspect ratio values + * cannot be interpolated. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatablePreserveAspectRatioValue res; + if (result == null) { + res = new AnimatablePreserveAspectRatioValue(target); + } else { + res = (AnimatablePreserveAspectRatioValue) result; + } + + short newAlign, newMeetOrSlice; + if (to != null && interpolation >= 0.5) { + AnimatablePreserveAspectRatioValue toValue = + (AnimatablePreserveAspectRatioValue) to; + newAlign = toValue.align; + newMeetOrSlice = toValue.meetOrSlice; + } else { + newAlign = align; + newMeetOrSlice = meetOrSlice; + } + + if (res.align != newAlign || res.meetOrSlice != newMeetOrSlice) { + res.align = align; + res.meetOrSlice = meetOrSlice; + res.hasChanged = true; + } + return res; + } + + /** + * Returns the align value. + */ + public short getAlign() { + return align; + } + + /** + * Returns the meet-or-slice value. + */ + public short getMeetOrSlice() { + return meetOrSlice; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatablePreserveAspectRatioValue + (target, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_NONE, + SVGPreserveAspectRatio.SVG_MEETORSLICE_MEET); + } + + /** + * Returns a string representation of this object. + */ + public String toStringRep() { + if (align < 1 || align > 10) { + return null; + } + String value = ALIGN_VALUES[align]; + if (align == SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_NONE) { + return value; + } + if (meetOrSlice < 1 || meetOrSlice > 2) { + return null; + } + return value + ' ' + MEET_OR_SLICE_VALUES[meetOrSlice]; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableRectValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableRectValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableRectValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,177 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * An SVG rect value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableRectValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatableRectValue extends AnimatableValue { + + /** + * The x coordinate. + */ + protected float x; + + /** + * The y coordinate. + */ + protected float y; + + /** + * The width. + */ + protected float width; + + /** + * The height. + */ + protected float height; + + /** + * Creates a new, uninitialized AnimatableRectValue. + */ + protected AnimatableRectValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableRectValue with one number. + */ + public AnimatableRectValue(AnimationTarget target, float x, float y, + float w, float h) { + super(target); + this.x = x; + this.y = y; + this.width = w; + this.height = h; + } + + /** + * Performs interpolation to the given value. Rect values cannot be + * interpolated. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableRectValue res; + if (result == null) { + res = new AnimatableRectValue(target); + } else { + res = (AnimatableRectValue) result; + } + + float newX = x, newY = y, newWidth = width, newHeight = height; + if (to != null) { + AnimatableRectValue toValue = (AnimatableRectValue) to; + newX += interpolation * (toValue.x - x); + newY += interpolation * (toValue.y - y); + newWidth += interpolation * (toValue.width - width); + newHeight += interpolation * (toValue.height - height); + } + if (accumulation != null && multiplier != 0) { + AnimatableRectValue accValue = (AnimatableRectValue) accumulation; + newX += multiplier * accValue.x; + newY += multiplier * accValue.y; + newWidth += multiplier * accValue.width; + newHeight += multiplier * accValue.height; + } + if (res.x != newX || res.y != newY + || res.width != newWidth || res.height != newHeight) { + res.x = newX; + res.y = newY; + res.width = newWidth; + res.height = newHeight; + res.hasChanged = true; + } + return res; + } + + /** + * Returns the x coordinate. + */ + public float getX() { + return x; + } + + /** + * Returns the y coordinate. + */ + public float getY() { + return y; + } + + /** + * Returns the width. + */ + public float getWidth() { + return width; + } + + /** + * Returns the height. + */ + public float getHeight() { + return height; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableRectValue(target, 0f, 0f, 0f, 0f); + } + + /** + * Returns a string representation of this object. + */ + public String toStringRep() { + StringBuffer sb = new StringBuffer(); + sb.append(x); + sb.append(','); + sb.append(y); + sb.append(','); + sb.append(width); + sb.append(','); + sb.append(height); + return sb.toString(); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableStringValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableStringValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableStringValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,118 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * A string value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableStringValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatableStringValue extends AnimatableValue { + + /** + * The string value. + */ + protected String string; + + /** + * Creates a new, uninitialized AnimatableStringValue. + */ + protected AnimatableStringValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableStringValue. + */ + public AnimatableStringValue(AnimationTarget target, String s) { + super(target); + string = s; + } + + /** + * Performs interpolation to the given value. String values cannot be + * interpolated. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, float interpolation, + AnimatableValue accumulation, + int multiplier) { + AnimatableStringValue res; + if (result == null) { + res = new AnimatableStringValue(target); + } else { + res = (AnimatableStringValue) result; + } + + String newString; + if (to != null && interpolation >= 0.5) { + AnimatableStringValue toValue = + (AnimatableStringValue) to; + newString = toValue.string; + } else { + newString = string; + } + + if (res.string == null || !res.string.equals(newString)) { + res.string = newString; + res.hasChanged = true; + } + return res; + } + + /** + * Returns the string. + */ + public String getString() { + return string; + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return false; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public AnimatableValue getZeroValue() { + return new AnimatableStringValue(target, ""); + } + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + return string; + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableTransformListValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableTransformListValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableTransformListValue.java 8 Apr 2013 10:55:48 -0000 1.1 @@ -0,0 +1,611 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import java.util.Iterator; +import java.util.Vector; +import java.util.List; + +import org.apache.batik.dom.anim.AnimationTarget; +import org.apache.batik.dom.svg.AbstractSVGTransform; +import org.apache.batik.dom.svg.SVGOMTransform; + +import org.w3c.dom.svg.SVGMatrix; +import org.w3c.dom.svg.SVGTransform; + +/** + * An SVG transform list value in the animation system. + * + * @author Cameron McCormack + * @version $Id: AnimatableTransformListValue.java,v 1.1 2013/04/08 10:55:48 marcin Exp $ + */ +public class AnimatableTransformListValue extends AnimatableValue { + + /** + * Identity transform value of type 'skewX'. + */ + protected static SVGOMTransform IDENTITY_SKEWX = new SVGOMTransform(); + + /** + * Identity transform value of type 'skewY'. + */ + protected static SVGOMTransform IDENTITY_SKEWY = new SVGOMTransform(); + + /** + * Identity transform value of type 'scale'. + */ + protected static SVGOMTransform IDENTITY_SCALE = new SVGOMTransform(); + + /** + * Identity transform value of type 'rotate'. + */ + protected static SVGOMTransform IDENTITY_ROTATE = new SVGOMTransform(); + + /** + * Identity transform value of type 'translate'. + */ + protected static SVGOMTransform IDENTITY_TRANSLATE = new SVGOMTransform(); + + static { + IDENTITY_SKEWX.setSkewX(0f); + IDENTITY_SKEWY.setSkewY(0f); + IDENTITY_SCALE.setScale(0f, 0f); + IDENTITY_ROTATE.setRotate(0f, 0f, 0f); + IDENTITY_TRANSLATE.setTranslate(0f, 0f); + } + + /** + * List of transforms. + */ + protected Vector transforms; + + /** + * Creates a new, uninitialized AnimatableTransformListValue. + */ + protected AnimatableTransformListValue(AnimationTarget target) { + super(target); + } + + /** + * Creates a new AnimatableTransformListValue with a single transform. + */ + public AnimatableTransformListValue(AnimationTarget target, + AbstractSVGTransform t) { + super(target); + this.transforms = new Vector(); + this.transforms.add(t); + } + + /** + * Creates a new AnimatableTransformListValue with a transform list. + */ + public AnimatableTransformListValue(AnimationTarget target, + List transforms) { + super(target); + + this.transforms = new Vector( transforms ); + + } + + /** + * Performs interpolation to the given value. + */ + public AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier) { + + AnimatableTransformListValue toTransformList = + (AnimatableTransformListValue) to; + AnimatableTransformListValue accTransformList = + (AnimatableTransformListValue) accumulation; + + int accSize = accumulation == null ? 0 : accTransformList.transforms.size(); + int newSize = transforms.size() + accSize * multiplier; + + AnimatableTransformListValue res; + if (result == null) { + res = new AnimatableTransformListValue(target); + res.transforms = new Vector(newSize); + res.transforms.setSize(newSize); + } else { + res = (AnimatableTransformListValue) result; + if (res.transforms == null) { + res.transforms = new Vector(newSize); + res.transforms.setSize(newSize); + } else if (res.transforms.size() != newSize) { + res.transforms.setSize(newSize); + } + } + + int index = 0; + for (int j = 0; j < multiplier; j++) { + for (int i = 0; i < accSize; i++, index++) { + res.transforms.setElementAt + (accTransformList.transforms.elementAt(i), index); + } + } + for (int i = 0; i < transforms.size() - 1; i++, index++) { + res.transforms.setElementAt(transforms.elementAt(i), index); + } + + if (to != null) { + AbstractSVGTransform tt = + (AbstractSVGTransform) toTransformList.transforms.lastElement(); + AbstractSVGTransform ft = null; + int type; + if (transforms.isEmpty()) { + // For the case of an additive animation with an underlying + // transform list of zero elements. + type = tt.getType(); + switch (type) { + case SVGTransform.SVG_TRANSFORM_SKEWX: + ft = IDENTITY_SKEWX; + break; + case SVGTransform.SVG_TRANSFORM_SKEWY: + ft = IDENTITY_SKEWY; + break; + case SVGTransform.SVG_TRANSFORM_SCALE: + ft = IDENTITY_SCALE; + break; + case SVGTransform.SVG_TRANSFORM_ROTATE: + ft = IDENTITY_ROTATE; + break; + case SVGTransform.SVG_TRANSFORM_TRANSLATE: + ft = IDENTITY_TRANSLATE; + break; + } + } else { + ft = (AbstractSVGTransform) transforms.lastElement(); + type = ft.getType(); + } + if (type == tt.getType()) { + AbstractSVGTransform t; + if (res.transforms.isEmpty()) { + t = new SVGOMTransform(); + res.transforms.add(t); + } else { + t = (AbstractSVGTransform) res.transforms.elementAt(index); + if (t == null) { + t = new SVGOMTransform(); + res.transforms.setElementAt(t, index); + } + } + float x, y, r = 0; + switch (type) { + case SVGTransform.SVG_TRANSFORM_SKEWX: + case SVGTransform.SVG_TRANSFORM_SKEWY: + r = ft.getAngle(); + r += interpolation * (tt.getAngle() - r); + if (type == SVGTransform.SVG_TRANSFORM_SKEWX) { + t.setSkewX(r); + } else if (type == SVGTransform.SVG_TRANSFORM_SKEWY) { + t.setSkewY(r); + } + break; + case SVGTransform.SVG_TRANSFORM_SCALE: { + SVGMatrix fm = ft.getMatrix(); + SVGMatrix tm = tt.getMatrix(); + x = fm.getA(); + y = fm.getD(); + x += interpolation * (tm.getA() - x); + y += interpolation * (tm.getD() - y); + t.setScale(x, y); + break; + } + case SVGTransform.SVG_TRANSFORM_ROTATE: { + x = ft.getX(); + y = ft.getY(); + x += interpolation * (tt.getX() - x); + y += interpolation * (tt.getY() - y); + r = ft.getAngle(); + r += interpolation * (tt.getAngle() - r); + t.setRotate(r, x, y); + break; + } + case SVGTransform.SVG_TRANSFORM_TRANSLATE: { + SVGMatrix fm = ft.getMatrix(); + SVGMatrix tm = tt.getMatrix(); + x = fm.getE(); + y = fm.getF(); + x += interpolation * (tm.getE() - x); + y += interpolation * (tm.getF() - y); + t.setTranslate(x, y); + break; + } + } + } + } else { + AbstractSVGTransform ft = + (AbstractSVGTransform) transforms.lastElement(); + AbstractSVGTransform t = + (AbstractSVGTransform) res.transforms.elementAt(index); + if (t == null) { + t = new SVGOMTransform(); + res.transforms.setElementAt(t, index); + } + t.assign(ft); + } + + // XXX Do better checking for changes. + res.hasChanged = true; + + return res; + } + + /** + * Performs a two-way interpolation between the specified values. + * value[12] and to[12] must all be of the same type, either scale or + * translation transforms, or all null. + */ + public static AnimatableTransformListValue interpolate + (AnimatableTransformListValue res, + AnimatableTransformListValue value1, + AnimatableTransformListValue value2, + AnimatableTransformListValue to1, + AnimatableTransformListValue to2, + float interpolation1, + float interpolation2, + AnimatableTransformListValue accumulation, + int multiplier) { + + int accSize = accumulation == null ? 0 : accumulation.transforms.size(); + int newSize = accSize * multiplier + 1; + + if (res == null) { + res = new AnimatableTransformListValue(to1.target); + res.transforms = new Vector(newSize); + res.transforms.setSize(newSize); + } else { + if (res.transforms == null) { + res.transforms = new Vector(newSize); + res.transforms.setSize(newSize); + } else if (res.transforms.size() != newSize) { + res.transforms.setSize(newSize); + } + } + + int index = 0; + for (int j = 0; j < multiplier; j++) { + for (int i = 0; i < accSize; i++, index++) { + res.transforms.setElementAt + (accumulation.transforms.elementAt(i), index); + } + } + + AbstractSVGTransform ft1 = + (AbstractSVGTransform) value1.transforms.lastElement(); + AbstractSVGTransform ft2 = + (AbstractSVGTransform) value2.transforms.lastElement(); + + AbstractSVGTransform t = + (AbstractSVGTransform) res.transforms.elementAt(index); + if (t == null) { + t = new SVGOMTransform(); + res.transforms.setElementAt(t, index); + } + + int type = ft1.getType(); + + float x, y; + if (type == SVGTransform.SVG_TRANSFORM_SCALE) { + x = ft1.getMatrix().getA(); + y = ft2.getMatrix().getD(); + } else { + x = ft1.getMatrix().getE(); + y = ft2.getMatrix().getF(); + } + + if (to1 != null) { + AbstractSVGTransform tt1 = + (AbstractSVGTransform) to1.transforms.lastElement(); + AbstractSVGTransform tt2 = + (AbstractSVGTransform) to2.transforms.lastElement(); + + if (type == SVGTransform.SVG_TRANSFORM_SCALE) { + x += interpolation1 * (tt1.getMatrix().getA() - x); + y += interpolation2 * (tt2.getMatrix().getD() - y); + } else { + x += interpolation1 * (tt1.getMatrix().getE() - x); + y += interpolation2 * (tt2.getMatrix().getF() - y); + } + } + + if (type == SVGTransform.SVG_TRANSFORM_SCALE) { + t.setScale(x, y); + } else { + t.setTranslate(x, y); + } + + // XXX Do better checking for changes. + res.hasChanged = true; + + return res; + } + + /** + * Performs a three-way interpolation between the specified values. + * value[123] and to[123] must all be single rotation transforms, + * or all null. + */ + public static AnimatableTransformListValue interpolate + (AnimatableTransformListValue res, + AnimatableTransformListValue value1, + AnimatableTransformListValue value2, + AnimatableTransformListValue value3, + AnimatableTransformListValue to1, + AnimatableTransformListValue to2, + AnimatableTransformListValue to3, + float interpolation1, + float interpolation2, + float interpolation3, + AnimatableTransformListValue accumulation, + int multiplier) { + + int accSize = accumulation == null ? 0 : accumulation.transforms.size(); + int newSize = accSize * multiplier + 1; + + if (res == null) { + res = new AnimatableTransformListValue(to1.target); + res.transforms = new Vector(newSize); + res.transforms.setSize(newSize); + } else { + if (res.transforms == null) { + res.transforms = new Vector(newSize); + res.transforms.setSize(newSize); + } else if (res.transforms.size() != newSize) { + res.transforms.setSize(newSize); + } + } + + int index = 0; + for (int j = 0; j < multiplier; j++) { + for (int i = 0; i < accSize; i++, index++) { + res.transforms.setElementAt + (accumulation.transforms.elementAt(i), index); + } + } + + AbstractSVGTransform ft1 = + (AbstractSVGTransform) value1.transforms.lastElement(); + AbstractSVGTransform ft2 = + (AbstractSVGTransform) value2.transforms.lastElement(); + AbstractSVGTransform ft3 = + (AbstractSVGTransform) value3.transforms.lastElement(); + + AbstractSVGTransform t = + (AbstractSVGTransform) res.transforms.elementAt(index); + if (t == null) { + t = new SVGOMTransform(); + res.transforms.setElementAt(t, index); + } + + float x, y, r; + r = ft1.getAngle(); + x = ft2.getX(); + y = ft3.getY(); + + if (to1 != null) { + AbstractSVGTransform tt1 = + (AbstractSVGTransform) to1.transforms.lastElement(); + AbstractSVGTransform tt2 = + (AbstractSVGTransform) to2.transforms.lastElement(); + AbstractSVGTransform tt3 = + (AbstractSVGTransform) to3.transforms.lastElement(); + + r += interpolation1 * (tt1.getAngle() - r); + x += interpolation2 * (tt2.getX() - x); + y += interpolation3 * (tt3.getY() - y); + } + t.setRotate(r, x, y); + + // XXX Do better checking for changes. + res.hasChanged = true; + + return res; + } + + /** + * Gets the transforms. + */ + public Iterator getTransforms() { + return transforms.iterator(); + } + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public boolean canPace() { + return true; + } + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public float distanceTo(AnimatableValue other) { + AnimatableTransformListValue o = (AnimatableTransformListValue) other; + if (transforms.isEmpty() || o.transforms.isEmpty()) { + return 0f; + } + AbstractSVGTransform t1 = (AbstractSVGTransform) transforms.lastElement(); + AbstractSVGTransform t2 = (AbstractSVGTransform) o.transforms.lastElement(); + short type1 = t1.getType(); + if (type1 != t2.getType()) { + return 0f; + } + SVGMatrix m1 = t1.getMatrix(); + SVGMatrix m2 = t2.getMatrix(); + switch (type1) { + case SVGTransform.SVG_TRANSFORM_TRANSLATE: + return Math.abs(m1.getE() - m2.getE()) + Math.abs(m1.getF() - m2.getF()); + case SVGTransform.SVG_TRANSFORM_SCALE: + return Math.abs(m1.getA() - m2.getA()) + Math.abs(m1.getD() - m2.getD()); + case SVGTransform.SVG_TRANSFORM_ROTATE: + case SVGTransform.SVG_TRANSFORM_SKEWX: + case SVGTransform.SVG_TRANSFORM_SKEWY: + return Math.abs(t1.getAngle() - t2.getAngle()); + } + return 0f; + } + + /** + * Returns the distance between this value's first component and the + * specified other value's first component. + */ + public float distanceTo1(AnimatableValue other) { + AnimatableTransformListValue o = (AnimatableTransformListValue) other; + if (transforms.isEmpty() || o.transforms.isEmpty()) { + return 0f; + } + AbstractSVGTransform t1 = (AbstractSVGTransform) transforms.lastElement(); + AbstractSVGTransform t2 = (AbstractSVGTransform) o.transforms.lastElement(); + short type1 = t1.getType(); + if (type1 != t2.getType()) { + return 0f; + } + SVGMatrix m1 = t1.getMatrix(); + SVGMatrix m2 = t2.getMatrix(); + switch (type1) { + case SVGTransform.SVG_TRANSFORM_TRANSLATE: + return Math.abs(m1.getE() - m2.getE()); + case SVGTransform.SVG_TRANSFORM_SCALE: + return Math.abs(m1.getA() - m2.getA()); + case SVGTransform.SVG_TRANSFORM_ROTATE: + case SVGTransform.SVG_TRANSFORM_SKEWX: + case SVGTransform.SVG_TRANSFORM_SKEWY: + return Math.abs(t1.getAngle() - t2.getAngle()); + } + return 0f; + } + + /** + * Returns the distance between this value's second component and the + * specified other value's second component. + */ + public float distanceTo2(AnimatableValue other) { + AnimatableTransformListValue o = (AnimatableTransformListValue) other; + if (transforms.isEmpty() || o.transforms.isEmpty()) { + return 0f; + } + AbstractSVGTransform t1 = (AbstractSVGTransform) transforms.lastElement(); + AbstractSVGTransform t2 = (AbstractSVGTransform) o.transforms.lastElement(); + short type1 = t1.getType(); + if (type1 != t2.getType()) { + return 0f; + } + SVGMatrix m1 = t1.getMatrix(); + SVGMatrix m2 = t2.getMatrix(); + switch (type1) { + case SVGTransform.SVG_TRANSFORM_TRANSLATE: + return Math.abs(m1.getF() - m2.getF()); + case SVGTransform.SVG_TRANSFORM_SCALE: + return Math.abs(m1.getD() - m2.getD()); + case SVGTransform.SVG_TRANSFORM_ROTATE: + return Math.abs(t1.getX() - t2.getX()); + } + return 0f; + } + + /** + * Returns the distance between this value's third component and the + * specified other value's third component. + */ + public float distanceTo3(AnimatableValue other) { + AnimatableTransformListValue o = (AnimatableTransformListValue) other; + if (transforms.isEmpty() || o.transforms.isEmpty()) { + return 0f; + } + AbstractSVGTransform t1 = (AbstractSVGTransform) transforms.lastElement(); + AbstractSVGTransform t2 = (AbstractSVGTransform) o.transforms.lastElement(); + short type1 = t1.getType(); + if (type1 != t2.getType()) { + return 0f; + } + if (type1 == SVGTransform.SVG_TRANSFORM_ROTATE) { + return Math.abs(t1.getY() - t2.getY()); + } + return 0f; + } + + /** + * Returns a zero value of this AnimatableValue's type. This returns an + * empty transform list. + */ + public AnimatableValue getZeroValue() { + return new AnimatableTransformListValue(target, new Vector(5)); + } + + /** + * Returns the CSS text representation of the value. + */ + public String toStringRep() { + StringBuffer sb = new StringBuffer(); + Iterator i = transforms.iterator(); + while (i.hasNext()) { + AbstractSVGTransform t = (AbstractSVGTransform) i.next(); + if (t == null) { + sb.append("null"); + } else { + SVGMatrix m = t.getMatrix(); + switch (t.getType()) { + case SVGTransform.SVG_TRANSFORM_TRANSLATE: + sb.append("translate("); + sb.append(m.getE()); + sb.append(','); + sb.append(m.getF()); + sb.append(')'); + break; + case SVGTransform.SVG_TRANSFORM_SCALE: + sb.append("scale("); + sb.append(m.getA()); + sb.append(','); + sb.append(m.getD()); + sb.append(')'); + break; + case SVGTransform.SVG_TRANSFORM_SKEWX: + sb.append("skewX("); + sb.append(t.getAngle()); + sb.append(')'); + break; + case SVGTransform.SVG_TRANSFORM_SKEWY: + sb.append("skewY("); + sb.append(t.getAngle()); + sb.append(')'); + break; + case SVGTransform.SVG_TRANSFORM_ROTATE: + sb.append("rotate("); + sb.append(t.getAngle()); + sb.append(','); + sb.append(t.getX()); + sb.append(','); + sb.append(t.getY()); + sb.append(')'); + break; + } + } + if (i.hasNext()) { + sb.append(' '); + } + } + return sb.toString(); + } +} Index: 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableValue.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableValue.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/anim/values/AnimatableValue.java 8 Apr 2013 10:55:49 -0000 1.1 @@ -0,0 +1,134 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.anim.values; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.Locale; + +import org.apache.batik.dom.anim.AnimationTarget; + +/** + * An abstract class for values in the animation engine. + * + * @author Cameron McCormack + * @version $Id: AnimatableValue.java,v 1.1 2013/04/08 10:55:49 marcin Exp $ + */ +public abstract class AnimatableValue { + + /** + * A formatting object to get CSS compatible float strings. + */ + protected static DecimalFormat decimalFormat = new DecimalFormat + ("0.0###########################################################", + new DecimalFormatSymbols(Locale.ENGLISH)); + + /** + * The target of the animation. + */ + protected AnimationTarget target; + + /** + * Whether this value has changed since the last call to + * {@link #hasChanged()}. This must be updated within {@link #interpolate} + * in descendant classes. + */ + protected boolean hasChanged = true; + + /** + * Creates a new AnimatableValue. + */ + protected AnimatableValue(AnimationTarget target) { + this.target = target; + } + + /** + * Returns a CSS compatible string version of the specified float. + */ + public static String formatNumber(float f) { + return decimalFormat.format(f); + } + + /** + * Performs interpolation to the given value. + * @param result the object in which to store the result of the + * interpolation, or null if a new object should be created + * @param to the value this value should be interpolated towards, or null + * if no actual interpolation should be performed + * @param interpolation the interpolation distance, 0 <= interpolation + * <= 1 + * @param accumulation an accumulation to add to the interpolated value + * @param multiplier an amount the accumulation values should be multiplied + * by before being added to the interpolated value + */ + public abstract AnimatableValue interpolate(AnimatableValue result, + AnimatableValue to, + float interpolation, + AnimatableValue accumulation, + int multiplier); + + /** + * Returns whether two values of this type can have their distance + * computed, as needed by paced animation. + */ + public abstract boolean canPace(); + + /** + * Returns the absolute distance between this value and the specified other + * value. + */ + public abstract float distanceTo(AnimatableValue other); + + /** + * Returns a zero value of this AnimatableValue's type. + */ + public abstract AnimatableValue getZeroValue(); + + /** + * Returns the CSS text representation of the value. + */ + public String getCssText() { + return null; + } + + /** + * Returns whether the value in this AnimatableValue has been modified. + */ + public boolean hasChanged() { + boolean ret = hasChanged; + hasChanged = false; + return ret; + } + + /** + * Returns a string representation of this object. This should be + * overridden in classes that do not have a CSS representation. + */ + public String toStringRep() { + return getCssText(); + } + + /** + * Returns a string representation of this object prefixed with its + * class name. + */ + public String toString() { + return getClass().getName() + "[" + toStringRep() + "]"; + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/DefaultSVGConverterController.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/rasterizer/DefaultSVGConverterController.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/DefaultSVGConverterController.java 8 Apr 2013 10:55:05 -0000 1.1 @@ -0,0 +1,87 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.rasterizer; + +import java.io.File; +import java.util.Map; +import java.util.List; + +import org.apache.batik.transcoder.Transcoder; + +/** + * Default controller for the + * SVGConverter operation. + * + * @author Vincent Hardy + * @version $Id: DefaultSVGConverterController.java,v 1.1 2013/04/08 10:55:05 marcin Exp $ + */ +public class DefaultSVGConverterController implements SVGConverterController { + /** + * Invoked when the rasterizer has computed the + * exact description of what it should do. The controller + * should return true if the transcoding process should + * proceed or false otherwise. + * + * @param transcoder Transcoder which will be used for the conversion + * @param hints set of hints that were set on the transcoder + * @param sources list of SVG sources it will convert. + * @param dest list of destination file it will use + */ + public boolean proceedWithComputedTask(Transcoder transcoder, + Map hints, + List sources, + List dest){ + return true; + } + + /** + * Invoked when the rasterizer is about to start transcoding + * of a given source. + * The controller should return true if the source should be + * transcoded and false otherwise. + */ + public boolean proceedWithSourceTranscoding(SVGConverterSource source, + File dest) { + System.out.println("About to transcoder source of type: " + source.getClass().getName()); + return true; + } + + /** + * Invoked when the rasterizer got an error while + * transcoding the input source. + * The controller should return true if the transcoding process + * should continue on other sources and it should return false + * if it should not. + * + * @param errorCode see the {@link SVGConverter} error code descriptions. + */ + public boolean proceedOnSourceTranscodingFailure(SVGConverterSource source, + File dest, + String errorCode){ + return true; + } + + /** + * Invoked when the rasterizer successfully transcoded + * the input source. + */ + public void onSourceTranscodingSuccess(SVGConverterSource source, + File dest){ + } +} \ No newline at end of file Index: 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/DestinationType.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/rasterizer/DestinationType.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/DestinationType.java 8 Apr 2013 10:55:05 -0000 1.1 @@ -0,0 +1,130 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.rasterizer; + +import org.apache.batik.transcoder.Transcoder; +import org.apache.batik.transcoder.image.JPEGTranscoder; +import org.apache.batik.transcoder.image.PNGTranscoder; +import org.apache.batik.transcoder.image.TIFFTranscoder; + +/** + * Describes the type of destination for an SVGConverter + * operation. + * + * @author Henri Ruini + * @author Vincent Hardy + * @version $Id: DestinationType.java,v 1.1 2013/04/08 10:55:05 marcin Exp $ + */ +public final class DestinationType { + public static final String PNG_STR = "image/png"; + public static final String JPEG_STR = "image/jpeg"; + public static final String TIFF_STR = "image/tiff"; + public static final String PDF_STR = "application/pdf"; + + public static final int PNG_CODE = 0; + public static final int JPEG_CODE = 1; + public static final int TIFF_CODE = 2; + public static final int PDF_CODE = 3; + + public static final String PNG_EXTENSION = ".png"; + public static final String JPEG_EXTENSION = ".jpg"; + public static final String TIFF_EXTENSION = ".tif"; + public static final String PDF_EXTENSION = ".pdf"; + + public static final DestinationType PNG + = new DestinationType(PNG_STR, PNG_CODE, PNG_EXTENSION); + public static final DestinationType JPEG + = new DestinationType(JPEG_STR, JPEG_CODE, JPEG_EXTENSION); + public static final DestinationType TIFF + = new DestinationType(TIFF_STR, TIFF_CODE, TIFF_EXTENSION); + public static final DestinationType PDF + = new DestinationType(PDF_STR, PDF_CODE, PDF_EXTENSION); + + private String type; + private int code; + private String extension; + + private DestinationType(String type, int code, String extension){ + this.type = type; + this.code = code; + this.extension = extension; + } + + public String getExtension(){ + return extension; + } + + public String toString(){ + return type; + } + + public int toInt(){ + return code; + } + + /** + * Returns a transcoder object of the result image type. + * + * @return Transcoder object or null if there isn't a proper transcoder. + */ + protected Transcoder getTranscoder(){ + switch(code) { + case PNG_CODE: + return new PNGTranscoder(); + case JPEG_CODE: + return new JPEGTranscoder(); + case TIFF_CODE: + return new TIFFTranscoder(); + case PDF_CODE: + try { + Class pdfClass = Class.forName("org.apache.fop.svg.PDFTranscoder"); + return (Transcoder)pdfClass.newInstance(); + } catch(Exception e) { + return null; + } + default: + return null; + } + + } + + /** + * Defines valid image types. + * + * @return Array of valid values as strings. + */ + public DestinationType[] getValues() { + return new DestinationType[]{PNG, JPEG, TIFF, PDF}; + } + + public Object readResolve(){ + switch(code){ + case PNG_CODE: + return PNG; + case JPEG_CODE: + return JPEG; + case TIFF_CODE: + return TIFF; + case PDF_CODE: + return PDF; + default: + throw new Error("unknown code:" + code ); + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/Main.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/rasterizer/Main.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/Main.java 8 Apr 2013 10:55:05 -0000 1.1 @@ -0,0 +1,1043 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.rasterizer; + +import java.awt.Color; +import java.awt.geom.Rectangle2D; +import java.io.File; +import java.util.Iterator; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.List; +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.batik.transcoder.Transcoder; +import org.apache.batik.parser.ClockHandler; +import org.apache.batik.parser.ClockParser; +import org.apache.batik.parser.ParseException; +import org.apache.batik.util.ApplicationSecurityEnforcer; + +/** + * Handles command line parameters to configure the SVGConverter + * and rasterizer images.
+ * + * Each command line option is handled by an OptionHandler which + * is responsible for converting the option into a configuration of the + * SVGConverter which is used to perform the conversion. + * + * @author Vincent Hardy + * @version $Id: Main.java,v 1.1 2013/04/08 10:55:05 marcin Exp $ + */ +public class Main implements SVGConverterController { + /** + * URL for Squiggle's security policy file + */ + public static final String RASTERIZER_SECURITY_POLICY + = "org/apache/batik/apps/rasterizer/resources/rasterizer.policy"; + + /** + * Interface for handling one command line option + */ + public static interface OptionHandler { + /** + * The OptionHandler should configure the SVGConverter + * according to the value of the option. + * + * Should throw an IllegalArgumentException if optionValue + * is not an acceptable option. + */ + void handleOption(String[] optionValues, SVGConverter c); + + /** + * Returns the number of values which the option handler requires. + * This defines the length of the optionValues array passed to + * the handler in the handleOption method + */ + int getOptionValuesLength(); + + /** + * Returns the description for this option + */ + String getOptionDescription(); + } + + /** + * This abstract implementation of the OptionHandler interface + * throws an exception if the number of arguments passed to the + * handleOption method does not match the number of expected + * optionValues. If the size matches, the safeHandleOption + * method is invoked. + * Subclasses can implement the safeHandleOption method + * assuming that the input array size is correct. + */ + public abstract static class AbstractOptionHandler implements OptionHandler { + + public void handleOption(String[] optionValues, SVGConverter c){ + int nOptions = optionValues != null? optionValues.length: 0; + if (nOptions != getOptionValuesLength()){ + throw new IllegalArgumentException(); + } + + safeHandleOption(optionValues, c); + } + + public abstract void safeHandleOption(String[] optionValues, SVGConverter c); + } + + /** + * Base class for options with no option value (i.e., the presence + * of the option means something in itself. Subclasses should implement + * the handleOption method which takes only an SVGConverter + * as a parameter. + */ + public abstract static class NoValueOptionHandler extends AbstractOptionHandler { + public void safeHandleOption(String[] optionValues, SVGConverter c){ + handleOption(c); + } + + public int getOptionValuesLength(){ + return 0; + } + + public abstract void handleOption(SVGConverter c); + } + + /** + * Base class for options with a single option value. Subclasses should + * provide an implementation for the handleOption method which + * takes a String and an SVGConverter as parameters. + */ + public abstract static class SingleValueOptionHandler extends AbstractOptionHandler { + public void safeHandleOption(String[] optionValues, SVGConverter c){ + handleOption(optionValues[0], c); + } + + public int getOptionValuesLength(){ + return 1; + } + + public abstract void handleOption(String optionValue, SVGConverter c); + } + + /** + * Base class for options which expect the single optionValue to + * be a float. Subclasses should implement the handleOption + * method which takes a float and an SVGConverter as + * parameters. + */ + public abstract static class FloatOptionHandler extends SingleValueOptionHandler { + public void handleOption(String optionValue, SVGConverter c){ + try{ + handleOption(Float.parseFloat(optionValue), c); + } catch(NumberFormatException e){ + throw new IllegalArgumentException(); + } + } + + public abstract void handleOption(float optionValue, SVGConverter c); + } + + /** + * Base class for options which expect the single optionValue to + * be a time value. Subclasses should implement the handleOption + * method which takes a float and an SVGConverter as + * parameters. + */ + public abstract static class TimeOptionHandler extends FloatOptionHandler { + public void handleOption(String optionValue, final SVGConverter c) { + try { + ClockParser p = new ClockParser(false); + p.setClockHandler(new ClockHandler() { + public void clockValue(float v) { + handleOption(v, c); + } + }); + p.parse(optionValue); + } catch (ParseException e) { + throw new IllegalArgumentException(); + } + } + + public abstract void handleOption(float optionValue, SVGConverter c); + } + + /** + * Base class for options which expect a Rectangle optionValue. + * Subclasses should implement the handleOption method which + * takes a Rectangle and an SVGConverter as parameters. + */ + public abstract static class RectangleOptionHandler extends SingleValueOptionHandler { + public void handleOption(String optionValue, SVGConverter c){ + Rectangle2D r = parseRect(optionValue); + if (r==null){ + throw new IllegalArgumentException(); + } + handleOption(r, c); + } + + public abstract void handleOption(Rectangle2D r, SVGConverter c); + + public Rectangle2D.Float parseRect(String rectValue){ + Rectangle2D.Float rect = null; + if(rectValue != null){ + if (!rectValue.toLowerCase().endsWith("f")){ + rectValue += "f"; + } + + StringTokenizer st = new StringTokenizer(rectValue, ","); + if(st.countTokens() == 4){ + String xStr = st.nextToken(); + String yStr = st.nextToken(); + String wStr = st.nextToken(); + String hStr = st.nextToken(); + float x=Float.NaN, y=Float.NaN, w=Float.NaN, h=Float.NaN; + try { + x = Float.parseFloat(xStr); + y = Float.parseFloat(yStr); + w = Float.parseFloat(wStr); + h = Float.parseFloat(hStr); + }catch(NumberFormatException e){ + // If an error occured, the x, y, w, h + // values will not be valid + } + + if( !Float.isNaN(x) + && + !Float.isNaN(y) + && + (!Float.isNaN(w) && w > 0) + && + (!Float.isNaN(h) && h > 0) ){ + rect = new Rectangle2D.Float(x, y, w, h); + } + } + } + return rect; + } + } + + /** + * Base class for options which expect a Color optionValue. + * Subclasses should implement the handleOption method which + * takes a Color and an SVGConverter as parameters. + */ + public abstract static class ColorOptionHandler extends SingleValueOptionHandler { + public void handleOption(String optionValue, SVGConverter c){ + Color color = parseARGB(optionValue); + if (color==null){ + throw new IllegalArgumentException(); + } + handleOption(color, c); + } + + public abstract void handleOption(Color color, SVGConverter c); + + /** + * Parse the input value, which should be in the following + * format: a.r.g.b where a, r, g and b are integer values, + * in decimal notation, between 0 and 255. + * @return the parsed color if successful. null otherwise. + */ + public Color parseARGB(String argbVal){ + Color c = null; + if(argbVal != null){ + StringTokenizer st = new StringTokenizer(argbVal, "."); + if(st.countTokens() == 4){ + String aStr = st.nextToken(); + String rStr = st.nextToken(); + String gStr = st.nextToken(); + String bStr = st.nextToken(); + int a = -1, r = -1, g = -1, b = -1; + try { + a = Integer.parseInt(aStr); + r = Integer.parseInt(rStr); + g = Integer.parseInt(gStr); + b = Integer.parseInt(bStr); + }catch(NumberFormatException e){ + // If an error occured, the a, r, g, b + // values will not be in the 0-255 range + // and the next if test will fail + } + + if( a>=0 && a<=255 + && + r>=0 && r<=255 + && + g>=0 && g<=255 + && + b>=0 && b<=255 ){ + c = new Color(r,g,b,a); + } + } + } + return c; + } + } + + + + /** + * Describes the command line options for the rasterizer + */ + public static String USAGE = + Messages.formatMessage("Main.usage", null); + + // + // The command line options are found in the properties + // file. + // + + /** + * Option to specify the output directory or file + */ + public static String CL_OPTION_OUTPUT + = Messages.get("Main.cl.option.output", "-d"); + + public static String CL_OPTION_OUTPUT_DESCRIPTION + = Messages.get("Main.cl.option.output.description", "No description"); + + /** + * Option to specify the output image's mime type + */ + public static String CL_OPTION_MIME_TYPE + = Messages.get("Main.cl.option.mime.type", "-m"); + + public static String CL_OPTION_MIME_TYPE_DESCRIPTION + = Messages.get("Main.cl.option.mime.type.description", "No description"); + + /** + * Option to specify the output image's width + */ + public static String CL_OPTION_WIDTH + = Messages.get("Main.cl.option.width", "-w"); + + public static String CL_OPTION_WIDTH_DESCRIPTION + = Messages.get("Main.cl.option.width.description", "No description"); + + /** + * Option to specify the output image's height + */ + public static String CL_OPTION_HEIGHT + = Messages.get("Main.cl.option.height", "-h"); + + public static String CL_OPTION_HEIGHT_DESCRIPTION + = Messages.get("Main.cl.option.height.description", "No description"); + + /** + * Option to specify the output image's maximum width. + */ + public static String CL_OPTION_MAX_WIDTH + = Messages.get("Main.cl.option.max.width", "-maxw"); + + public static String CL_OPTION_MAX_WIDTH_DESCRIPTION + = Messages.get("Main.cl.option.max.width.description", "No description"); + + /** + * Option to specify the output image's maximum height. + */ + public static String CL_OPTION_MAX_HEIGHT + = Messages.get("Main.cl.option.max.height", "-maxh"); + + public static String CL_OPTION_MAX_HEIGHT_DESCRIPTION + = Messages.get("Main.cl.option.max.height.description", "No description"); + + /** + * Option to specify the area of interest in the output + * image. + */ + public static String CL_OPTION_AOI + = Messages.get("Main.cl.option.aoi", "-a"); + + public static String CL_OPTION_AOI_DESCRIPTION + = Messages.get("Main.cl.option.aoi.description", "No description"); + + /** + * Option to specify the output image's background color + */ + public static String CL_OPTION_BACKGROUND_COLOR + = Messages.get("Main.cl.option.background.color", "-bg"); + + public static String CL_OPTION_BACKGROUND_COLOR_DESCRIPTION + = Messages.get("Main.cl.option.background.color.description", "No description"); + + /** + * Option to specify the CSS media type when converting + * the SVG image + */ + public static String CL_OPTION_MEDIA_TYPE + = Messages.get("Main.cl.option.media.type", "-cssMedia"); + + public static String CL_OPTION_MEDIA_TYPE_DESCRIPTION + = Messages.get("Main.cl.option.media.type.description", "No description"); + + /** + * Option to specify the default value for the font-family + * CSS property when converting the SVG image + */ + public static String CL_OPTION_DEFAULT_FONT_FAMILY + = Messages.get("Main.cl.option.default.font.family", "-font-family"); + + public static String CL_OPTION_DEFAULT_FONT_FAMILY_DESCRIPTION + = Messages.get("Main.cl.option.default.font.family.description", "No description"); + + /** + * Option to specify the CSS alternate stylesheet when + * converting the SVG images + */ + public static String CL_OPTION_ALTERNATE_STYLESHEET + = Messages.get("Main.cl.option.alternate.stylesheet", "-cssAlternate"); + + public static String CL_OPTION_ALTERNATE_STYLESHEET_DESCRIPTION + = Messages.get("Main.cl.option.alternate.stylesheet.description", "No description"); + + /** + * Option to specify that the converted SVG files should + * be validated during the conversion process. + */ + public static String CL_OPTION_VALIDATE + = Messages.get("Main.cl.option.validate", "-validate"); + + public static String CL_OPTION_VALIDATE_DESCRIPTION + = Messages.get("Main.cl.option.validate.description", "No description"); + + /** + * Option to specify that the converted SVG files should + * be after the dispatch of the 'onload' event. + */ + public static String CL_OPTION_ONLOAD + = Messages.get("Main.cl.option.onload", "-onload"); + + public static String CL_OPTION_ONLOAD_DESCRIPTION + = Messages.get("Main.cl.option.onload.description", "No description"); + + /** + * Option to specify that the document should be rasterized after + * seeking to the specified document time. + */ + public static String CL_OPTION_SNAPSHOT_TIME + = Messages.get("Main.cl.option.snapshot.time", "-snapshotTime"); + + public static String CL_OPTION_SNAPSHOT_TIME_DESCRIPTION + = Messages.get("Main.cl.option.snapshot.time.description", "No description"); + + /** + * Option to specify the user language with which SVG + * documents should be processed + */ + public static String CL_OPTION_LANGUAGE + = Messages.get("Main.cl.option.language", "-lang"); + + public static String CL_OPTION_LANGUAGE_DESCRIPTION + = Messages.get("Main.cl.option.language.description", "No description"); + + /** + * Option to specify an addition user stylesheet + */ + public static String CL_OPTION_USER_STYLESHEET + = Messages.get("Main.cl.option.user.stylesheet", "-cssUser"); + + public static String CL_OPTION_USER_STYLESHEET_DESCRIPTION + = Messages.get("Main.cl.option.user.stylesheet.description", "No description"); + + /** + * Option to specify the resolution for the output image + */ + public static String CL_OPTION_DPI + = Messages.get("Main.cl.option.dpi", "-dpi"); + + public static String CL_OPTION_DPI_DESCRIPTION + = Messages.get("Main.cl.option.dpi.description", "No description"); + + /** + * Option to specify the output JPEG quality + */ + public static String CL_OPTION_QUALITY + = Messages.get("Main.cl.option.quality", "-q"); + + public static String CL_OPTION_QUALITY_DESCRIPTION + = Messages.get("Main.cl.option.quality.description", "No description"); + + /** + * Option to specify if the PNG should be indexed. + */ + public static String CL_OPTION_INDEXED + = Messages.get("Main.cl.option.indexed", "-indexed"); + + public static String CL_OPTION_INDEXED_DESCRIPTION + = Messages.get("Main.cl.option.indexed.description", "No description"); + + /** + * Option to specify the set of allowed scripts + */ + public static String CL_OPTION_ALLOWED_SCRIPTS + = Messages.get("Main.cl.option.allowed.scripts", "-scripts"); + + public static String CL_OPTION_ALLOWED_SCRIPTS_DESCRIPTION + = Messages.get("Main.cl.option.allowed.scripts.description", "No description"); + + /** + * Option to determine whether scripts a constrained to the + * same origin as the document referencing them. + */ + public static String CL_OPTION_CONSTRAIN_SCRIPT_ORIGIN + = Messages.get("Main.cl.option.constrain.script.origin", "-anyScriptOrigin"); + + public static String CL_OPTION_CONSTRAIN_SCRIPT_ORIGIN_DESCRIPTION + = Messages.get("Main.cl.option.constrain.script.origin.description", "No description"); + + /** + * Option to turn off secure execution of scripts + */ + public static String CL_OPTION_SECURITY_OFF + = Messages.get("Main.cl.option.security.off", "-scriptSecurityOff"); + + public static String CL_OPTION_SECURITY_OFF_DESCRIPTION + = Messages.get("Main.cl.option.security.off.description", "No description"); + + /** + * Static map containing all the option handlers able to analyze the + * various options. + */ + protected static Map optionMap = new HashMap(); + + /** + * Static map containing all the mime types understood by the + * rasterizer + */ + protected static Map mimeTypeMap = new HashMap(); + + /** + * Static initializer: adds all the option handlers to the + * map of option handlers. + */ + static { + mimeTypeMap.put("image/jpg", DestinationType.JPEG); + mimeTypeMap.put("image/jpeg", DestinationType.JPEG); + mimeTypeMap.put("image/jpe", DestinationType.JPEG); + mimeTypeMap.put("image/png", DestinationType.PNG); + mimeTypeMap.put("application/pdf", DestinationType.PDF); + mimeTypeMap.put("image/tiff", DestinationType.TIFF); + + optionMap.put(CL_OPTION_OUTPUT, + new SingleValueOptionHandler(){ + public void handleOption(String optionValue, + SVGConverter c){ + c.setDst(new File(optionValue)); + } + public String getOptionDescription(){ + return CL_OPTION_OUTPUT_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_MIME_TYPE, + new SingleValueOptionHandler(){ + public void handleOption(String optionValue, + SVGConverter c){ + DestinationType dstType = + (DestinationType)mimeTypeMap.get(optionValue); + + if (dstType == null){ + throw new IllegalArgumentException(); + } + + c.setDestinationType(dstType); + } + + public String getOptionDescription(){ + return CL_OPTION_MIME_TYPE_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_WIDTH, + new FloatOptionHandler(){ + public void handleOption(float optionValue, + SVGConverter c){ + if (optionValue <= 0){ + throw new IllegalArgumentException(); + } + + c.setWidth(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_WIDTH_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_HEIGHT, + new FloatOptionHandler(){ + public void handleOption(float optionValue, + SVGConverter c){ + if (optionValue <= 0){ + throw new IllegalArgumentException(); + } + + c.setHeight(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_HEIGHT_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_MAX_WIDTH, + new FloatOptionHandler(){ + public void handleOption(float optionValue, + SVGConverter c){ + if (optionValue <= 0){ + throw new IllegalArgumentException(); + } + + c.setMaxWidth(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_MAX_WIDTH_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_MAX_HEIGHT, + new FloatOptionHandler(){ + public void handleOption(float optionValue, + SVGConverter c){ + if (optionValue <= 0){ + throw new IllegalArgumentException(); + } + + c.setMaxHeight(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_MAX_HEIGHT_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_AOI, + new RectangleOptionHandler(){ + public void handleOption(Rectangle2D optionValue, + SVGConverter c){ + c.setArea(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_AOI_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_BACKGROUND_COLOR, + new ColorOptionHandler(){ + public void handleOption(Color optionValue, + SVGConverter c){ + c.setBackgroundColor(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_BACKGROUND_COLOR_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_MEDIA_TYPE, + new SingleValueOptionHandler(){ + public void handleOption(String optionValue, + SVGConverter c){ + c.setMediaType(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_MEDIA_TYPE_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_DEFAULT_FONT_FAMILY, + new SingleValueOptionHandler() { + public void handleOption(String optionValue, + SVGConverter c){ + c.setDefaultFontFamily(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_DEFAULT_FONT_FAMILY_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_ALTERNATE_STYLESHEET, + new SingleValueOptionHandler(){ + public void handleOption(String optionValue, + SVGConverter c){ + c.setAlternateStylesheet(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_ALTERNATE_STYLESHEET_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_USER_STYLESHEET, + new SingleValueOptionHandler(){ + public void handleOption(String optionValue, + SVGConverter c){ + c.setUserStylesheet(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_USER_STYLESHEET_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_LANGUAGE, + new SingleValueOptionHandler(){ + public void handleOption(String optionValue, + SVGConverter c){ + c.setLanguage(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_LANGUAGE_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_DPI, + new FloatOptionHandler(){ + public void handleOption(float optionValue, + SVGConverter c){ + if (optionValue <= 0){ + throw new IllegalArgumentException(); + } + + c.setPixelUnitToMillimeter + ((2.54f/optionValue)*10); + } + + public String getOptionDescription(){ + return CL_OPTION_DPI_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_QUALITY, + new FloatOptionHandler(){ + public void handleOption(float optionValue, + SVGConverter c){ + if (optionValue <= 0 || optionValue >= 1){ + throw new IllegalArgumentException(); + } + + c.setQuality(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_QUALITY_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_INDEXED, + new FloatOptionHandler(){ + public void handleOption(float optionValue, + SVGConverter c){ + if ((optionValue != 1) && + (optionValue != 2) && + (optionValue != 4) && + (optionValue != 8)) + throw new IllegalArgumentException(); + + c.setIndexed((int)optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_INDEXED_DESCRIPTION; + } + }); + optionMap.put(CL_OPTION_VALIDATE, + new NoValueOptionHandler(){ + public void handleOption(SVGConverter c){ + c.setValidate(true); + } + + public String getOptionDescription(){ + return CL_OPTION_VALIDATE_DESCRIPTION; + } + }); + optionMap.put(CL_OPTION_ONLOAD, + new NoValueOptionHandler(){ + public void handleOption(SVGConverter c){ + c.setExecuteOnload(true); + } + + public String getOptionDescription(){ + return CL_OPTION_ONLOAD_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_SNAPSHOT_TIME, + new TimeOptionHandler(){ + public void handleOption(float optionValue, + SVGConverter c){ + c.setExecuteOnload(true); + c.setSnapshotTime(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_SNAPSHOT_TIME_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_ALLOWED_SCRIPTS, + new SingleValueOptionHandler() { + public void handleOption(String optionValue, + SVGConverter c){ + c.setAllowedScriptTypes(optionValue); + } + + public String getOptionDescription(){ + return CL_OPTION_ALLOWED_SCRIPTS_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_CONSTRAIN_SCRIPT_ORIGIN, + new NoValueOptionHandler(){ + public void handleOption(SVGConverter c){ + c.setConstrainScriptOrigin(false); + } + + public String getOptionDescription(){ + return CL_OPTION_CONSTRAIN_SCRIPT_ORIGIN_DESCRIPTION; + } + }); + + optionMap.put(CL_OPTION_SECURITY_OFF, + new NoValueOptionHandler() { + public void handleOption(SVGConverter c){ + c.setSecurityOff(true); + } + + public String getOptionDescription(){ + return CL_OPTION_SECURITY_OFF_DESCRIPTION; + } + }); + } + + /** + * List of arguments describing the conversion task to be + * performed. + */ + protected List args; + + public Main(String[] args){ + this.args = new ArrayList(); + for (int i=0; i= nArgs){ + error(ERROR_NOT_ENOUGH_OPTION_VALUES, new Object[]{ v, optionHandler.getOptionDescription()}); + return; + } + + String[] optionValues = new String[nOptionArgs]; + for (int j=0; jStephane Hillion + * @version $Id: Messages.java,v 1.1 2013/04/08 10:55:06 marcin Exp $ + */ +public class Messages { + + /** + * This class does not need to be instantiated. + */ + protected Messages() { } + + /** + * The error messages bundle class name. + */ + protected static final String RESOURCES = + "org.apache.batik.apps.rasterizer.resources.Messages"; + + /** + * The localizable support for the error messages. + */ + protected static LocalizableSupport localizableSupport = + new LocalizableSupport(RESOURCES, Messages.class.getClassLoader()); + + /** + * Implements {@link org.apache.batik.i18n.Localizable#setLocale(Locale)}. + */ + public static void setLocale(Locale l) { + localizableSupport.setLocale(l); + } + + /** + * Implements {@link org.apache.batik.i18n.Localizable#getLocale()}. + */ + public static Locale getLocale() { + return localizableSupport.getLocale(); + } + + /** + * Implements {@link + * org.apache.batik.i18n.Localizable#formatMessage(String,Object[])}. + */ + public static String formatMessage(String key, Object[] args) + throws MissingResourceException { + return localizableSupport.formatMessage(key, args); + } + + public static String get(String key) + throws MissingResourceException { + return formatMessage(key, null); + } + + public static String get(String key, String def){ + String value = def; + try{ + value = get(key); + }catch(MissingResourceException e){ + } + + return value; + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverter.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverter.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverter.java 8 Apr 2013 10:55:05 -0000 1.1 @@ -0,0 +1,1152 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.rasterizer; + +import java.awt.Color; +import java.awt.geom.Rectangle2D; +import java.io.File; +import java.io.FileFilter; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.List; +import java.util.ArrayList; + +import org.apache.batik.transcoder.Transcoder; +import org.apache.batik.transcoder.TranscoderInput; +import org.apache.batik.transcoder.TranscoderOutput; +import org.apache.batik.transcoder.image.ImageTranscoder; +import org.apache.batik.transcoder.image.JPEGTranscoder; +import org.apache.batik.transcoder.image.PNGTranscoder; +import org.apache.batik.util.ParsedURL; + +/** + * This application can be used to convert SVG images to raster images. + *
+ * Possible result raster image formats are PNG, JPEG, TIFF, and PDF. + * The Batik Transcoder API is used to execute the conversion. FOP is + * needed to be able to transcode to the PDF format
+ * + * The source has to be list of files or URL (set by the setSources + * method).
+ * + * The destination can be:
+ * + *
+ * + * There are a number of options which control the way the image is + * converted to the destination format:
+ * + * @version $Id: SVGConverter.java,v 1.1 2013/04/08 10:55:05 marcin Exp $ + * @author Henri Ruini + * @author Vincent Hardy + */ +public class SVGConverter { + // + // Error codes reported by the SVGConverter + // + + // + // Reported when no source file has been specified. + // + public static final String ERROR_NO_SOURCES_SPECIFIED + = "SVGConverter.error.no.sources.specified"; + + // + // Reported when there is more than one valid input source + // and no output directory has been set and the source is + // not a file. + // + public static final String ERROR_CANNOT_COMPUTE_DESTINATION + = "SVGConverter.error.cannot.compute.destination"; + + // + // Reported when the dst is a file and there are multiple + // sources. + // + public static final String ERROR_CANNOT_USE_DST_FILE + = "SVGConverter.error.cannot.use.dst.file"; + + // + // Reported when the Transcoder for the requested + // destinationType cannot be found. + // + public static final String ERROR_CANNOT_ACCESS_TRANSCODER + = "SVGConverter.error.cannot.access.transcoder"; + + // + // Reported when the source is found to be the same as + // the destination. Note that it is not guaranteed that + // this error condition will always be detected. + // + public static final String ERROR_SOURCE_SAME_AS_DESTINATION + = "SVGConverter.error.source.same.as.destination"; + + // + // Reported when one of the sources cannot be read. + // + public static final String ERROR_CANNOT_READ_SOURCE + = "SVGConverter.error.cannot.read.source"; + + // + // Reported when an error happens while opening a source + // file. + // + public static final String ERROR_CANNOT_OPEN_SOURCE + = "SVGConverter.error.cannot.open.source"; + + // + // Reported if the output is not writeable. This may + // happen if the output file already exists and does not + // have write permission. + // + public static final String ERROR_OUTPUT_NOT_WRITEABLE + = "SVGConverter.error.output.not.writeable"; + + // + // Reported when an error happens while trying to open + // the output file for writing. + // + public static final String ERROR_CANNOT_OPEN_OUTPUT_FILE + = "SVGConverter.error.cannot.open.output.file"; + + // + // Reported when the converter was not able to create + // the destination directory for the files. + // + public static final String ERROR_UNABLE_TO_CREATE_OUTPUT_DIR + = "SVGConverter.error.unable.to.create.output.dir"; + + // + // Reported when an error occurs while convertion the + // source file. + // + public static final String ERROR_WHILE_RASTERIZING_FILE + = "SVGConverter.error.while.rasterizing.file"; + + // + // Class variables and constants + // + + /** SVG file extension */ + protected static final String SVG_EXTENSION = ".svg"; + + /** Default quality value. A value of -1 means disabled. */ + protected static final float DEFAULT_QUALITY + = -1.0f; + + /** Maximum quality value */ + protected static final float MAXIMUM_QUALITY + = .99F; + + /** Default result type */ + protected static final DestinationType DEFAULT_RESULT_TYPE + = DestinationType.PNG; + + /** Default width */ + protected static final float DEFAULT_WIDTH = -1; + + /** Default height */ + protected static final float DEFAULT_HEIGHT = -1; + + /** Result type */ + protected DestinationType destinationType = DEFAULT_RESULT_TYPE; + + /** Output image height. */ + protected float height = DEFAULT_HEIGHT; + + /** Output image width. */ + protected float width = DEFAULT_WIDTH; + + /** Maximum output image height. */ + protected float maxHeight = DEFAULT_HEIGHT; + + /** Maximum output image width. */ + protected float maxWidth = DEFAULT_WIDTH; + + /** Output image quality. */ + protected float quality = DEFAULT_QUALITY; + + /** Should output Image be indexed . */ + protected int indexed = -1; + + /** Output AOI area. */ + protected Rectangle2D area = null; + + /** Language */ + protected String language = null; + + /** User stylesheet */ + protected String userStylesheet = null; + + /** Millimeters Per Pixel */ + protected float pixelUnitToMillimeter = -1.0f; + + /** Validation flag */ + protected boolean validate = false; + + /** Execute the 'onload' scripts flag */ + protected boolean executeOnload = false; + + /** Document time to seek to. */ + protected float snapshotTime = Float.NaN; + + /** Set of allowed script types. */ + protected String allowedScriptTypes = null; + + /** Controls whether scripts can only have the same origin as + the document which references them. */ + protected boolean constrainScriptOrigin = true; + + /** Controls whether scripts should be run securely or not */ + protected boolean securityOff = false; + + /** Sources files or URLs */ + protected List sources = null; + + /** + * Destination image path. Can be a file (for single source) or + * a directory + */ + protected File dst; + + /** Background color for the output images. */ + protected Color backgroundColor = null; + + /** Media type for which the SVG image should be rendered */ + protected String mediaType = null; + + /** Default value for the font-family when it is unspecified */ + protected String defaultFontFamily = null; + + /** Alternate stylesheet for which should be applied to the SVG */ + protected String alternateStylesheet = null; + + /** Contents of fileset elements. */ + protected List files = new ArrayList(); + + /** + * Controls some aspects of the converter's operation, + * such as whether or not it should proceed in some + * error situations. See {@link SVGConverterController} + */ + protected SVGConverterController controller; + + // + // Default constructor + // + public SVGConverter(){ + this(new DefaultSVGConverterController()); + } + + // + // Constructor + // + public SVGConverter(SVGConverterController controller){ + if (controller == null){ + throw new IllegalArgumentException(); + } + + this.controller = controller; + } + + // + // Property get/set methods + // + + /** + * Sets the destinationType attribute value. + * Should not be null. + */ + public void setDestinationType(DestinationType destinationType) { + if(destinationType == null){ + throw new IllegalArgumentException(); + } + this.destinationType = destinationType; + } + + public DestinationType getDestinationType(){ + return destinationType; + } + + /** + * In less than or equal to zero, the height is not + * constrained on the output image. The height is in + * user space. + */ + public void setHeight(float height) { + this.height = height; + } + + public float getHeight(){ + return height; + } + + /** + * In less than or equal to zero, the width is not + * constrained on the output image. The width is in + * user space. + */ + public void setWidth(float width) { + this.width = width; + } + + public float getWidth(){ + return width; + } + + /** + * If less than or equal to zero, the maximum height + * does not have any effect on the output image. + * The maximum height is in user space. + */ + public void setMaxHeight(float height) { + this.maxHeight = height; + } + + public float getMaxHeight(){ + return maxHeight; + } + + /** + * If less than or equal to zero, the maximum width + * does not have any effect on the output image. + * The maximum width is in user space. + */ + public void setMaxWidth(float width) { + this.maxWidth = width; + } + + public float getMaxWidth(){ + return maxWidth; + } + + /** + * Sets the JPEG encoding quality. The value should be strictly + * less than 1. If the value is less than zero, then the maximum + * encoding quality is used. + */ + public void setQuality(float quality) throws IllegalArgumentException { + if(quality >= 1){ + throw new IllegalArgumentException(); + } + + this.quality = quality; + } + + public float getQuality(){ + return quality; + } + + /** + * Tells the PNG encoder to reduce the image to 256 colors, so the + * PNG file is indexed. + */ + public void setIndexed(int bits) throws IllegalArgumentException { + this.indexed = bits; + } + + public int getIndexed(){ + return indexed; + } + + /** + * Sets the user language. If the value is null, then the default (see + * {@link org.apache.batik.bridge.UserAgent#getLanguages}) + * is used. + */ + public void setLanguage(String language){ + this.language = language; + } + + public String getLanguage(){ + return language; + } + + /** + * Sets the user stylesheet. May be null. + */ + public void setUserStylesheet(String userStylesheet){ + this.userStylesheet = userStylesheet; + } + + public String getUserStylesheet(){ + return userStylesheet; + } + + /** + * Sets the millimeters per pixel constant. A negative + * value will cause the default value + * (see {@link org.apache.batik.bridge.UserAgent#getPixelUnitToMillimeter}) + * to be used. + */ + public void setPixelUnitToMillimeter(float pixelUnitToMillimeter){ + this.pixelUnitToMillimeter = pixelUnitToMillimeter; + } + + public float getPixelUnitToMillimeter(){ + return pixelUnitToMillimeter; + } + + /** + * Sets the area as a Rectangle. This value can + * be null in which case the whole image will be rendered. If the + * area is not null, then only the portion of the image it + * defines will be rendered. + */ + public void setArea(Rectangle2D area){ + this.area = area; + } + + public Rectangle2D getArea(){ + return area; + } + + /** + * Sets the list of individual SVG sources. The strings + * can be either URLs or file names. Note that invalid + * sources (e.g., read-protected files or invalid URLs) + * will cause SVGConverterExceptions to be + * thrown during the transcoding process (see {@link #execute}); + */ + public void setSources(String[] sources) { + if(sources == null){ + this.sources = null; + } + else{ + this.sources = new ArrayList(); + for (int i=0; ibackgroundColor value. This can be + * null in which case no color will be used to fill the + * background before rendering this SVG image. + */ + public void setBackgroundColor(Color backgroundColor){ + this.backgroundColor = backgroundColor; + } + + public Color getBackgroundColor(){ + return backgroundColor; + } + + /** + * Sets the mediaType value. This value controls + * the CSS media for which the image should be rendered. It + * can be null, in which case no specific media selectors will + * apply. If it is not null, it can contain space separated values + * of the medias for which the image should be rendered. For example, + * "screen", "print" or "scree projection" are valid values. + */ + public void setMediaType(String mediaType){ + this.mediaType = mediaType; + } + + public String getMediaType(){ + return mediaType; + } + + /** + * Sets the defaultFontFamily value. This value controls + * the default value for the font-family CSS property when that + * property is unspecified. + */ + public void setDefaultFontFamily(String defaultFontFamily) { + this.defaultFontFamily = defaultFontFamily; + } + + public String getDefaultFontFamily() { + return defaultFontFamily; + } + + /** + * Sets the alternateStyleSheet value. This value + * controls the CSS alternate stylesheet to select in the + * rendered SVG file(s). It may be null, in which case no alternate + * stylesheet will be selected. + */ + public void setAlternateStylesheet(String alternateStylesheet){ + this.alternateStylesheet = alternateStylesheet; + } + + public String getAlternateStylesheet(){ + return alternateStylesheet; + } + + /** + * Defines whether or not input sources should be validated in + * the conversion process + */ + public void setValidate(boolean validate){ + this.validate = validate; + } + + public boolean getValidate(){ + return validate; + } + + /** + * Sets whether or not scripts attached to the DOM using 'onload' + * event attribute must be executed before rasterizing. + * + * @param b true means scripts will be executed + */ + public void setExecuteOnload(boolean b){ + this.executeOnload = b; + } + + /** + * Returns true if the scripts attached to the DOM using 'onload' + * event attribute is going to be executed before rasterizing, + * false otherwise. + */ + public boolean getExecuteOnload(){ + return executeOnload; + } + + /** + * Sets the document time to seek to before rasterizing. + * + * @param t the document time, in seconds + */ + public void setSnapshotTime(float t) { + snapshotTime = t; + } + + /** + * Returns the document to to seek to before rasterizing. + */ + public float getSnapshotTime() { + return snapshotTime; + } + + /** + * Sets the set of allowed script types (i.e., the set of possible + * values for the type attribute in the <script> element), + * as a comma separated list of allowed values. + */ + public void setAllowedScriptTypes(String allowedScriptTypes){ + this.allowedScriptTypes = allowedScriptTypes; + } + + /** + * Returns the list of allowed script types. + * + * @see #setAllowedScriptTypes + */ + public String getAllowedScriptTypes(){ + return allowedScriptTypes; + } + + /** + * Sets whether scripts should only be loaded from the same + * location as the documents referencing them. + */ + public void setConstrainScriptOrigin(boolean constrainScriptOrigin){ + this.constrainScriptOrigin = constrainScriptOrigin; + } + + /** + * Returns whether scripts can only be loaded from the same + * origin as the documents referencing them. + */ + public boolean getConstrainScriptOrigin(){ + return constrainScriptOrigin; + } + + /** + * Sets whether or not scripts should be run securely + */ + public void setSecurityOff(boolean securityOff){ + this.securityOff = securityOff; + } + + /** + * Returns whether or not scripts will be run securely + */ + public boolean getSecurityOff(){ + return securityOff; + } + + /** + * Returns true if f is a File. f is found to be a file if + * it exists and is a file. If it does not exist, it is declared + * to be a file if it has the same extension as the DestinationType. + */ + protected boolean isFile(File f){ + if (f.exists()){ + return f.isFile(); + } else { + if (f.toString().toLowerCase().endsWith(destinationType.getExtension())){ + return true; + } + } + + return false; + } + + /** + * Starts the conversion process. + * @throws SVGConverterException thrown if parameters are not set correctly. + */ + public void execute() throws SVGConverterException { + // Compute the set of SVGConverterSource from the source properties + // (srcDir and srcFile); + // This throws an exception if there is not at least one src file. + List sources = computeSources(); + + // Compute the destination files from dest + List dstFiles = null; + if(sources.size() == 1 && dst != null && isFile(dst)){ + dstFiles = new ArrayList(); + dstFiles.add(dst); + } + else{ + dstFiles = computeDstFiles(sources); + } + + // Now, get the transcoder to use for the operation + Transcoder transcoder = destinationType.getTranscoder(); + if(transcoder == null) { + throw new SVGConverterException(ERROR_CANNOT_ACCESS_TRANSCODER, + new Object[]{destinationType.toString()}, + true /* fatal error */); + } + + // Now, compute the set of transcoding hints to use + Map hints = computeTranscodingHints(); + transcoder.setTranscodingHints(hints); + + // Notify listener that task has been computed + if(!controller.proceedWithComputedTask(transcoder, + hints, + sources, + dstFiles)){ + return; + } + + // Convert files one by one + for(int i = 0 ; i < sources.size() ; i++) { + // Get the file from the vector. + SVGConverterSource currentFile + = (SVGConverterSource)sources.get(i); + File outputFile = (File)dstFiles.get(i); + + createOutputDir(outputFile); + transcode(currentFile, outputFile, transcoder); + } + } + + /** + * Populates a vector with destination files names + * computed from the names of the files in the sources vector + * and the value of the dst property + */ + protected List computeDstFiles(List sources) + throws SVGConverterException { + List dstFiles = new ArrayList(); + if (dst != null) { + if (dst.exists() && dst.isFile()) { + throw new SVGConverterException(ERROR_CANNOT_USE_DST_FILE); + } + + // + // Either dst exist and is a directory or dst does not + // exist and we may fail later on in createOutputDir + // + int n = sources.size(); + for(int i=0; i -1){ + result[0] = fileName.substring(0, n); + if (n+1 < fileName.length()){ + result[1] = fileName.substring(n+1); + } + } + + return result; + } + + // ----------------------------------------------------------------------- + // Internal methods + // ----------------------------------------------------------------------- + + /** + * Computes the set of transcoding hints to use for the operation + */ + protected Map computeTranscodingHints(){ + Map map = new HashMap(); + + // Set AOI. ---------------------------------------------------------- + if (area != null) { + map.put(ImageTranscoder.KEY_AOI, area); + } + + // Set image quality. ------------------------------------------------ + if (quality > 0) { + map.put(JPEGTranscoder.KEY_QUALITY, new Float(this.quality)); + } + + // Set image indexed. ------------------------------------------------ + if (indexed != -1) { + map.put(PNGTranscoder.KEY_INDEXED, new Integer(indexed)); + } + + // Set image background color ----------------------------------------- + if (backgroundColor != null){ + map.put(ImageTranscoder.KEY_BACKGROUND_COLOR, backgroundColor); + } + + // Set image height and width. ---------------------------------------- + if (height > 0) { + map.put(ImageTranscoder.KEY_HEIGHT, new Float(this.height)); + } + if (width > 0){ + map.put(ImageTranscoder.KEY_WIDTH, new Float(this.width)); + } + + // Set maximum height and width --------------------------------------- + if (maxHeight > 0) { + map.put(ImageTranscoder.KEY_MAX_HEIGHT, new Float(this.maxHeight)); + } + if (maxWidth > 0){ + map.put(ImageTranscoder.KEY_MAX_WIDTH, new Float(this.maxWidth)); + } + + // Set CSS Media + if (mediaType != null){ + map.put(ImageTranscoder.KEY_MEDIA, mediaType); + } + + // Set default font-family + if (defaultFontFamily != null) { + map.put(ImageTranscoder.KEY_DEFAULT_FONT_FAMILY, defaultFontFamily); + } + + // Set alternateStylesheet + if (alternateStylesheet != null){ + map.put(ImageTranscoder.KEY_ALTERNATE_STYLESHEET, alternateStylesheet); + } + + // Set user stylesheet + if (userStylesheet != null) { + String userStylesheetURL; + try { + URL userDir = new File(System.getProperty("user.dir")).toURL(); + userStylesheetURL = new ParsedURL(userDir, userStylesheet).toString(); + } catch (Exception e) { + userStylesheetURL = userStylesheet; + } + map.put(ImageTranscoder.KEY_USER_STYLESHEET_URI, userStylesheetURL); + } + + // Set the user language + if (language != null){ + map.put(ImageTranscoder.KEY_LANGUAGE, language); + } + + // Sets the millimeters per pixel + if (pixelUnitToMillimeter > 0){ + map.put(ImageTranscoder.KEY_PIXEL_UNIT_TO_MILLIMETER, + new Float(pixelUnitToMillimeter)); + } + + // Set validation + if (validate){ + map.put(ImageTranscoder.KEY_XML_PARSER_VALIDATING, Boolean.TRUE); + } + + // Set onload + if (executeOnload) { + map.put(ImageTranscoder.KEY_EXECUTE_ONLOAD, Boolean.TRUE); + } + + // Set snapshot time + if (!Float.isNaN(snapshotTime)) { + map.put(ImageTranscoder.KEY_SNAPSHOT_TIME, new Float(snapshotTime)); + } + + // Set allowed scripts + if (allowedScriptTypes != null) { + map.put(ImageTranscoder.KEY_ALLOWED_SCRIPT_TYPES, allowedScriptTypes); + } + + // Set constrain script origin + if (!constrainScriptOrigin) { + map.put(ImageTranscoder.KEY_CONSTRAIN_SCRIPT_ORIGIN, Boolean.FALSE); + } + + return map; + } + + /** + * Converts the input image to the result image. + * with the given transcoder. If a failure happens, the + * controller is notified and decides whether to proceed + * or not. If it decides to proceed, the converter will + * continue processing other files. Otherwise, it will + * throw an exception. + */ + protected void transcode(SVGConverterSource inputFile, + File outputFile, + Transcoder transcoder) + throws SVGConverterException { + TranscoderInput input = null; + TranscoderOutput output = null; + OutputStream outputStream = null; + + if (!controller.proceedWithSourceTranscoding(inputFile, + outputFile)){ + return; + } + + try { + if (inputFile.isSameAs(outputFile.getPath())) { + throw new SVGConverterException(ERROR_SOURCE_SAME_AS_DESTINATION, + true /* fatal error */); + } + + // Compute transcoder input. + if (!inputFile.isReadable()) { + throw new SVGConverterException(ERROR_CANNOT_READ_SOURCE, + new Object[]{inputFile.getName()}); + } + + try { + InputStream in = inputFile.openStream(); + in.close(); + } catch(IOException ioe) { + throw new SVGConverterException(ERROR_CANNOT_OPEN_SOURCE, + new Object[] {inputFile.getName(), + ioe.toString()}); + } + + input = new TranscoderInput(inputFile.getURI()); + + // Compute transcoder output. + if (!isWriteable(outputFile)) { + throw new SVGConverterException(ERROR_OUTPUT_NOT_WRITEABLE, + new Object[] {outputFile.getName()}); + } + try { + outputStream = new FileOutputStream(outputFile); + } catch(FileNotFoundException fnfe) { + throw new SVGConverterException(ERROR_CANNOT_OPEN_OUTPUT_FILE, + new Object[] {outputFile.getName()}); + } + + output = new TranscoderOutput(outputStream); + } catch(SVGConverterException e){ + boolean proceed = controller.proceedOnSourceTranscodingFailure + (inputFile, outputFile, e.getErrorCode()); + if (proceed){ + return; + } else { + throw e; + } + } + + // Transcode now + boolean success = false; + try { + transcoder.transcode(input, output); + success = true; + } catch(Exception te) { + te.printStackTrace(); + try { + outputStream.flush(); + outputStream.close(); + } catch(IOException ioe) {} + + // Report error to the controller. If controller decides + // to stop, throw an exception + boolean proceed = controller.proceedOnSourceTranscodingFailure + (inputFile, outputFile, ERROR_WHILE_RASTERIZING_FILE); + + if (!proceed){ + throw new SVGConverterException(ERROR_WHILE_RASTERIZING_FILE, + new Object[] {outputFile.getName(), + te.getMessage()}); + } + } + + // Close streams and clean up. + try { + outputStream.flush(); + outputStream.close(); + } catch(IOException ioe) { + return; + } + + if (success){ + controller.onSourceTranscodingSuccess(inputFile, outputFile); + } + } + + /** + * Get the name of the result image file. + * + *

This method modifies the result filename, it changes the existing + * suffix to correspong the result file type. It also adds the suffix + * if the file doesn't have one.

+ * + * @param file Result file name as a String object. + * + * @return Name of the file. The directory of the file is not returned. + * The returned string is empty if the parameter is not a file. + */ + protected String getDestinationFile(String file) { + int suffixStart; // Location of the first char of + // the suffix in a String. + String oldName; // Existing filename. + String newSuffix = destinationType.getExtension(); + // New suffix. + + oldName = file; + // Find the first char of the suffix. + suffixStart = oldName.lastIndexOf( '.' ); + String dest = null; + if (suffixStart != -1) { + // Replace existing suffix. + dest = oldName.substring(0, suffixStart) + newSuffix; + } else { + // Add new suffix. + dest = oldName + newSuffix; + } + + return dest; + } + + /** + * Creates directories for output files if needed. + * + * @param output Output file with path. + * + * @throws SVGConverterException Output directory doesn't exist and it can't be created. + */ + protected void createOutputDir(File output) + throws SVGConverterException { + + File outputDir; // Output directory object. + boolean success = true; // false if the output directory + // doesn't exist and it can't be created + // true otherwise + + + // Create object from output directory. + String parentDir = output.getParent(); + if (parentDir != null){ + outputDir = new File(output.getParent()); + if ( ! outputDir.exists() ) { + // Output directory doesn't exist, so create it. + success = outputDir.mkdirs(); + } else { + if ( ! outputDir.isDirectory() ) { + // File, which have a same name as the output directory, exists. + // Create output directory. + success = outputDir.mkdirs(); + } + } + } + + if (!success) { + throw new SVGConverterException(ERROR_UNABLE_TO_CREATE_OUTPUT_DIR); + } + } + + /** + * Checks if the application is allowed to write to the file. + * + * @param file File to be checked. + * + * @return true if the file is writeable and false otherwise. + */ + protected boolean isWriteable(File file) { + if (file.exists()) { + // Check the existing file. + if (!file.canWrite()) { + return false; + } + } else { + // Check the file that doesn't exist yet. + // Create a new file. The file is writeable if + // the creation succeeds. + try { + file.createNewFile(); + } catch(IOException ioe) { + return false; + } + } + return true; + } + + // ----------------------------------------------------------------------- + // Inner classes + // ----------------------------------------------------------------------- + + /** + * Convenience class to filter svg files + */ + public static class SVGFileFilter implements FileFilter { + public static final String SVG_EXTENSION = ".svg"; + + public boolean accept(File file){ + if (file != null && file.getName().toLowerCase().endsWith(SVG_EXTENSION)){ + return true; + } + + return false; + } + } + +} + Index: 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterController.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterController.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterController.java 8 Apr 2013 10:55:06 -0000 1.1 @@ -0,0 +1,81 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.rasterizer; + +import java.io.File; +import java.util.Map; +import java.util.List; + +import org.apache.batik.transcoder.Transcoder; + +/** + * Interface for controlling some aspectes of the + * SVGConverter operation. + * + * @author Vincent Hardy + * @version $Id: SVGConverterController.java,v 1.1 2013/04/08 10:55:06 marcin Exp $ + */ +public interface SVGConverterController { + /** + * Invoked when the rasterizer has computed the + * exact description of what it should do. The controller + * should return true if the transcoding process should + * proceed or false otherwise. + * + * @param transcoder Transcoder which will be used + * @param hints set of hints that were set on the transcoder + * @param sources list of SVG sources it will convert. + * @param dest list of destination file it will use + */ + boolean proceedWithComputedTask(Transcoder transcoder, + Map hints, + List sources, + List dest); + + /** + * Invoked when the rasterizer is about to start transcoding + * of a given source. + * The controller should return true if the source should be + * transcoded and false otherwise. + */ + boolean proceedWithSourceTranscoding(SVGConverterSource source, + File dest); + + /** + * Invoked when the rasterizer got an error while + * transcoding the input source. + * The controller should return true if the transcoding process + * should continue on other sources and it should return false + * if it should not. + * + * @param errorCode see the {@link SVGConverter} error code descriptions. + */ + boolean proceedOnSourceTranscodingFailure(SVGConverterSource source, + File dest, + String errorCode); + + /** + * Invoked when the rasterizer successfully transcoded + * the input source. + */ + void onSourceTranscodingSuccess(SVGConverterSource source, + File dest); + +} + Index: 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterException.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterException.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterException.java 8 Apr 2013 10:55:05 -0000 1.1 @@ -0,0 +1,76 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.rasterizer; + +/** + * Describes an error condition in SVGConverter + * + * @author Vincent Hardy + * @version $Id: SVGConverterException.java,v 1.1 2013/04/08 10:55:05 marcin Exp $ + */ +public class SVGConverterException extends Exception { + /** + * Error code + */ + protected String errorCode; + + /** + * Additional information about the error condition + */ + protected Object[] errorInfo; + + /** + * Defines whether or not this is a fatal error condition + */ + protected boolean isFatal; + + public SVGConverterException(String errorCode){ + this(errorCode, null, false); + } + + public SVGConverterException(String errorCode, + Object[] errorInfo){ + this(errorCode, errorInfo, false); + } + + public SVGConverterException(String errorCode, + Object[] errorInfo, + boolean isFatal){ + this.errorCode = errorCode; + this.errorInfo = errorInfo; + this.isFatal = isFatal; + } + + public SVGConverterException(String errorCode, + boolean isFatal){ + this(errorCode, null, isFatal); + } + + public boolean isFatal(){ + return isFatal; + } + + public String getMessage(){ + return Messages.formatMessage(errorCode, errorInfo); + } + + public String getErrorCode(){ + return errorCode; + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterFileSource.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterFileSource.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterFileSource.java 8 Apr 2013 10:55:05 -0000 1.1 @@ -0,0 +1,102 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.rasterizer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.net.MalformedURLException; + +/** + * Describes a file source for the SVGConverter + * + * @author Vincent Hardy + * @version $Id: SVGConverterFileSource.java,v 1.1 2013/04/08 10:55:05 marcin Exp $ + */ +public class SVGConverterFileSource implements SVGConverterSource { + File file; + String ref; + + public SVGConverterFileSource(File file){ + this.file = file; + } + + public SVGConverterFileSource(File file, String ref){ + this.file = file; + this.ref = ref; + } + + public String getName(){ + String name = file.getName(); + if (ref != null && !"".equals(ref)){ + name += '#' + ref; + } + return name; + } + + public File getFile(){ + return file; + } + + public String toString(){ + return getName(); + } + + public String getURI(){ + try{ + String uri = file.toURL().toString(); + if (ref != null && !"".equals(ref)){ + uri += '#' + ref; + } + return uri; + } catch(MalformedURLException e){ + throw new Error( e.getMessage() ); + } + } + + public boolean equals(Object o){ + if (o == null || !(o instanceof SVGConverterFileSource)){ + return false; + } + + return file.equals(((SVGConverterFileSource)o).file); + } + + public int hashCode() { + return file.hashCode(); + } + + public InputStream openStream() throws FileNotFoundException{ + return new FileInputStream(file); + } + + public boolean isSameAs(String srcStr){ + if (file.toString().equals(srcStr)){ + return true; + } + + return false; + } + + public boolean isReadable(){ + return file.canRead(); + } +} + Index: 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterSource.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterSource.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterSource.java 8 Apr 2013 10:55:05 -0000 1.1 @@ -0,0 +1,58 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.rasterizer; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Interface used to handle both Files and URLs in the + * SVGConverter + * + * @author Vincent Hardy + * @version $Id: SVGConverterSource.java,v 1.1 2013/04/08 10:55:05 marcin Exp $ + */ +public interface SVGConverterSource { + /** + * Returns the name of the source. That would be the + * name for a File or URL + */ + String getName(); + + /** + * Gets a TranscoderInput for that source + */ + InputStream openStream() throws IOException; + + /** + * Checks if same as source described by srcStr + */ + boolean isSameAs(String srcStr); + + /** + * Checks if source can be read + */ + boolean isReadable(); + + /** + * Returns a URI string corresponding to this source + */ + String getURI(); +} + Index: 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterURLSource.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterURLSource.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/rasterizer/SVGConverterURLSource.java 8 Apr 2013 10:55:05 -0000 1.1 @@ -0,0 +1,129 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.apache.batik.apps.rasterizer; + +import java.io.IOException; +import java.io.InputStream; + +import org.apache.batik.util.ParsedURL; + +/* + * @author Vincent Hardy + * @version $Id: SVGConverterURLSource.java,v 1.1 2013/04/08 10:55:05 marcin Exp $ + */ +public class SVGConverterURLSource implements SVGConverterSource { + /** + * SVG file extension + */ + protected static final String SVG_EXTENSION = ".svg"; + protected static final String SVGZ_EXTENSION = ".svgz"; + + // + // Reported when the URL for one of the sources is + // invalid. This will happen if the URL is malformed or + // if the URL file does not end with the ".svg" extension. + // This is needed to be able to create a file name for + // the ouptut automatically. + // + public static final String ERROR_INVALID_URL + = "SVGConverterURLSource.error.invalid.url"; + + ParsedURL purl; + String name; + + public SVGConverterURLSource(String url) throws SVGConverterException{ + this.purl = new ParsedURL(url); + + // Get the path portion + String path = this.purl.getPath(); + int n = path.lastIndexOf('/'); + String file = path; + if (n != -1){ + // The following is safe because we know there is at least ".svg" + // after the slash. + file = path.substring(n+1); + } + if (file.length() == 0) { + int idx = path.lastIndexOf('/', n-1); + file = path.substring(idx+1, n); + } + if (file.length() == 0) { + throw new SVGConverterException(ERROR_INVALID_URL, + new Object[]{url}); + } + n = file.indexOf('?'); + String args = ""; + if (n != -1) { + args = file.substring(n+1); + file = file.substring(0, n); + } + + name = file; + + // + // The following will force creation of different output file names + // for urls with references (e.g., anne.svg#svgView(viewBox(0,0,4,5))) + // + String ref = this.purl.getRef(); + if ((ref != null) && (ref.length()!=0)) { + name += "_" + ref.hashCode(); + } + if ((args != null) && (args.length()!=0)) { + name += "_" + args.hashCode(); + } + } + + public String toString(){ + return purl.toString(); + } + + public String getURI(){ + return toString(); + } + + public boolean equals(Object o){ + if (o == null || !(o instanceof SVGConverterURLSource)){ + return false; + } + + return purl.equals(((SVGConverterURLSource)o).purl); + } + + public int hashCode() { + return purl.hashCode(); + } + + + public InputStream openStream() throws IOException { + return purl.openStream(); + } + + public boolean isSameAs(String srcStr){ + return toString().equals(srcStr); + } + + public boolean isReadable(){ + return true; + } + + public String getName(){ + return name; + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/slideshow/Main.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/slideshow/Main.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/slideshow/Main.java 8 Apr 2013 10:55:59 -0000 1.1 @@ -0,0 +1,458 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.slideshow; + +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.ArrayList; + +import javax.swing.JComponent; +import javax.swing.JWindow; + +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.DocumentLoader; +import org.apache.batik.bridge.GVTBuilder; +import org.apache.batik.bridge.UserAgent; +import org.apache.batik.bridge.UserAgentAdapter; +import org.apache.batik.bridge.ViewBox; +import org.apache.batik.gvt.GraphicsNode; +import org.apache.batik.gvt.renderer.StaticRenderer; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.svg.SVGDocument; + +/** + * + * @version $Id: Main.java,v 1.1 2013/04/08 10:55:59 marcin Exp $ + */ +public class Main extends JComponent { + + StaticRenderer renderer; + UserAgent userAgent; + DocumentLoader loader; + BridgeContext ctx; + + BufferedImage image; + BufferedImage display; + File [] files; + + static int duration = 3000; + static int frameDelay = duration+7000; + + volatile boolean done = false; + + public Main(File []files, Dimension size) { + setBackground(Color.black); + this.files = files; + UserAgentAdapter ua = new UserAgentAdapter(); + renderer = new StaticRenderer(); + userAgent = ua; + loader = new DocumentLoader(userAgent); + ctx = new BridgeContext(userAgent, loader); + ua.setBridgeContext(ctx); + + if (size == null) { + size = Toolkit.getDefaultToolkit().getScreenSize(); + } + + setPreferredSize(size); + setDoubleBuffered(false); + addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent me) { + if (done) + System.exit(0); + else + togglePause(); + } + }); + + size.width += 2; + size.height += 2; + display = new BufferedImage(size.width, size.height, + BufferedImage.TYPE_INT_BGR); + + Thread t = new RenderThread(); + t.start(); + + JWindow w = new JWindow(); + w.setBackground(Color.black); + w.getContentPane().setBackground(Color.black); + w.getContentPane().add(this); + w.pack(); + w.setLocation(new Point(-1, -1)); + w.setVisible(true); + } + + class RenderThread extends Thread { + RenderThread(){ + super("RenderThread"); + setDaemon( true ); + } + + public void run() { + renderer.setDoubleBuffered(true); + for (int i=0; i 500) { + System.gc(); + currTrans = System.currentTimeMillis(); + stime = frameDelay-(currTrans-startLastTransition); + } + if (stime > 0) sleep(stime); + } catch (InterruptedException ie) { } + currTrans = System.currentTimeMillis(); + } + + synchronized(this) { + while (paused) { + try { + wait(); + } catch (InterruptedException ie) { } + } + } + + long last = startLastTransition = System.currentTimeMillis(); + + for (int i=0; i src.getWidth()) w = src.getWidth()-x; + if (y+h > src.getHeight()) h = src.getHeight()-y; + + synchronized (display) { + g2d.fillRect(x, y, w, h); + BufferedImage sub; + + sub = src.getSubimage(x, y, w, h); + g2d.drawImage(sub, null, x, y); + } + + repaint(x, y, w, h); + long current = System.currentTimeMillis(); + try { + long dt = current-last; + if (dt < tblock) + sleep(tblock-dt); + } catch (InterruptedException ie) { } + last = current; + } + + synchronized (Main.this) { + transitionThread = null; + Main.this.notifyAll(); + } + } + + } + + public void paint(Graphics g) { + Graphics2D g2d = (Graphics2D)g; + if (display == null) return; + // System.out.println("Drawing Image: " + display); + g2d.drawImage(display, null, 0, 0); + } + + public static void readFileList(String file, List fileVec) { + BufferedReader br; + try { + br = new BufferedReader(new FileReader(file)); + } catch(FileNotFoundException fnfe) { + System.err.println("Unable to open file-list: " + file); + return; + } + try { + URL flURL = new File(file).toURL(); + String line; + while ((line = br.readLine()) != null) { + String str = line; + int idx = str.indexOf('#'); + if (idx != -1) + str = str.substring(0, idx); + str = str.trim(); + if (str.length() == 0) + continue; + try { + URL imgURL = new URL(flURL, str); + fileVec.add(imgURL.getFile()); + } catch (MalformedURLException mue) { + System.err.println("Can't make sense of line:\n " + line); + } + } + } catch (IOException ioe) { + System.err.println("Error while reading file-list: " + file); + } finally { + try { br.close(); } catch (IOException ioe) { } + } + } + + public static void main(String []args) { + + List fileVec = new ArrayList(); + + Dimension d = null; + + if (args.length == 0) { + showUsage(); + return; + } + + for (int i=0; i\n" + + " --file-list : file contains list of images to\n" + + " show one per line\n" + + " -ws [,]\n" + + " -window-size [,] : Set the size of slideshow window\n" + + " defaults to full screen\n" + + " -ft \n" + + " --frame-time : Amount of time in millisecs to\n" + + " show each frame.\n" + + " Includes transition time.\n" + + " -tt \n" + + " --transition-time : Amount of time in millisecs to\n" + + " transition between frames.\n" + + " : SVG file to display"); + } + +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/AboutDialog.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/AboutDialog.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/AboutDialog.java 8 Apr 2013 10:55:08 -0000 1.1 @@ -0,0 +1,148 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.net.URL; + +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JLayeredPane; +import javax.swing.JWindow; +import javax.swing.border.BevelBorder; + +import org.apache.batik.Version; + +/** + * A dialog showing the revision of the Batik viewer as well + * as the list of contributors. + * The dialog can be dismissed by click or by escaping. + * + * @author Vincent Hardy + * @version $Id: AboutDialog.java,v 1.1 2013/04/08 10:55:08 marcin Exp $ + */ +public class AboutDialog extends JWindow { + + public static final String ICON_BATIK_SPLASH + = "AboutDialog.icon.batik.splash"; + + /** + * Creates a new AboutDialog. + */ + public AboutDialog() { + buildGUI(); + } + + /** + * Creates a new AboutDialog with a given owner. + */ + public AboutDialog(Frame owner) { + super(owner); + buildGUI(); + + addKeyListener(new KeyAdapter(){ + public void keyPressed(KeyEvent e){ + if(e.getKeyCode() == KeyEvent.VK_ESCAPE){ + setVisible(false); + dispose(); + } + } + }); + + addMouseListener(new MouseAdapter(){ + public void mousePressed(MouseEvent e){ + setVisible(false); + dispose(); + } + }); + } + + public void setLocationRelativeTo(Frame f) { + Dimension invokerSize = f.getSize(); + Point loc = f.getLocation(); + Point invokerScreenLocation = new Point(loc.x, loc.y); + + Rectangle bounds = getBounds(); + int dx = invokerScreenLocation.x+((invokerSize.width-bounds.width)/2); + int dy = invokerScreenLocation.y+((invokerSize.height - bounds.height)/2); + Dimension screenSize = getToolkit().getScreenSize(); + + if (dy+bounds.height>screenSize.height) { + dy = screenSize.height-bounds.height; + dx = invokerScreenLocation.x<(screenSize.width>>1) ? invokerScreenLocation.x+invokerSize.width : + invokerScreenLocation.x-bounds.width; + } + if (dx+bounds.width>screenSize.width) { + dx = screenSize.width-bounds.width; + } + + if (dx<0) dx = 0; + if (dy<0) dy = 0; + setLocation(dx, dy); + } + + /** + * Populates this window. + */ + protected void buildGUI() { + getContentPane().setBackground(Color.white); + + ClassLoader cl = this.getClass().getClassLoader(); + URL url = cl.getResource(Resources.getString(ICON_BATIK_SPLASH)); + ImageIcon icon = new ImageIcon(url); + int w = icon.getIconWidth(); + int h = icon.getIconHeight(); + + JLayeredPane p = new JLayeredPane(); + p.setSize(600, 425); + getContentPane().add(p); + + JLabel l = new JLabel(icon); + l.setBounds(0, 0, w, h); + p.add(l, new Integer(0)); + + JLabel l2 = new JLabel("Batik " + Version.getVersion()); + l2.setForeground(new Color(232, 232, 232, 255)); + l2.setOpaque(false); + l2.setBackground(new Color(0, 0, 0, 0)); + l2.setHorizontalAlignment(JLabel.RIGHT); + l2.setVerticalAlignment(JLabel.BOTTOM); + l2.setBounds(w - 320, h - 117, 300, 100); + p.add(l2, new Integer(2)); + + ((JComponent)getContentPane()).setBorder + (BorderFactory.createCompoundBorder + (BorderFactory.createBevelBorder(BevelBorder.RAISED, Color.gray, Color.black), + BorderFactory.createCompoundBorder + (BorderFactory.createCompoundBorder + (BorderFactory.createEmptyBorder(3, 3, 3, 3), + BorderFactory.createLineBorder(Color.black)), + BorderFactory.createEmptyBorder(10, 10, 10, 10)))); + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/AbstractCompoundCommand.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/AbstractCompoundCommand.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/AbstractCompoundCommand.java 8 Apr 2013 10:55:08 -0000 1.1 @@ -0,0 +1,100 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.util.ArrayList; + +/** + * Abstract compound command. Supports the execute / undo / redo of more than + * one command + * + * @version $Id: AbstractCompoundCommand.java,v 1.1 2013/04/08 10:55:08 marcin Exp $ + */ +public abstract class AbstractCompoundCommand extends AbstractUndoableCommand { + + /** + * The atom UndoableCommand command list. + */ + protected ArrayList atomCommands; + + /** + * Constructor. + */ + public AbstractCompoundCommand() { + this.atomCommands = new ArrayList(); + } + + /** + * Adds the given command to the atomCommand list. + * + * @param command + * The given command + */ + public void addCommand(UndoableCommand command) { + if (command.shouldExecute()) { + atomCommands.add(command); + } + } + + public void execute() { + int n = atomCommands.size(); + for (int i = 0; i < n; i++) { + UndoableCommand cmd = (UndoableCommand) atomCommands.get(i); + cmd.execute(); + } + } + + public void undo() { + int size = atomCommands.size(); + for (int i = size - 1; i >= 0; i--) { + UndoableCommand command = (UndoableCommand) atomCommands.get(i); + command.undo(); + } + } + + public void redo() { + int n = atomCommands.size(); + for (int i = 0; i < n; i++) { + UndoableCommand cmd = (UndoableCommand) atomCommands.get(i); + cmd.redo(); + } + } + + public boolean shouldExecute() { + boolean shouldExecute = true; + if (atomCommands.size() == 0) { + shouldExecute = false; + } + int n = atomCommands.size(); + for (int i = 0; i < n && shouldExecute; i++) { + UndoableCommand command = (UndoableCommand) atomCommands.get(i); + shouldExecute = command.shouldExecute() && shouldExecute; + } + return shouldExecute; + } + + /** + * Returns the command number that this compound command contains. + * + * @return The atom command number + */ + public int getCommandNumber() { + return atomCommands.size(); + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/AbstractUndoableCommand.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/AbstractUndoableCommand.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/AbstractUndoableCommand.java 8 Apr 2013 10:55:08 -0000 1.1 @@ -0,0 +1,60 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +/** + * Represents abstract undoable/redoable command. Concrete commands should + * extend this class + * + * @version $Id: AbstractUndoableCommand.java,v 1.1 2013/04/08 10:55:08 marcin Exp $ + */ +public abstract class AbstractUndoableCommand implements UndoableCommand { + + /** + * The command name. + */ + protected String name; + + public void execute() { + } + + public void undo() { + } + + public void redo() { + } + + public String getName() { + return name; + } + + /** + * Sets the command name. + * + * @param name + * Name to set + */ + public void setName(String name) { + this.name = name; + } + + public boolean shouldExecute() { + return true; + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/Application.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/Application.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/Application.java 8 Apr 2013 10:55:08 -0000 1.1 @@ -0,0 +1,130 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import javax.swing.Action; + +/** + * This interface represents a SVG viewer application. + * + * @author Stephane Hillion + * @version $Id: Application.java,v 1.1 2013/04/08 10:55:08 marcin Exp $ + */ +public interface Application { + + /** + * Creates and shows a new viewer frame. + */ + JSVGViewerFrame createAndShowJSVGViewerFrame(); + + /** + * Closes the given viewer frame. + */ + void closeJSVGViewerFrame(JSVGViewerFrame f); + + /** + * Creates an action to exit the application. + */ + Action createExitAction(JSVGViewerFrame vf); + + /** + * Opens the given link in a new window. + */ + void openLink(String url); + + /** + * Returns the XML parser class name. + */ + String getXMLParserClassName(); + + /** + * Returns true if the XML parser must be in validation mode, false + * otherwise. + */ + boolean isXMLParserValidating(); + + /** + * Shows the preference dialog. + */ + void showPreferenceDialog(JSVGViewerFrame f); + + /** + * Returns the user languages. + */ + String getLanguages(); + + /** + * Returns the user stylesheet uri. + * @return null if no user style sheet was specified. + */ + String getUserStyleSheetURI(); + + /** + * Returns the default value for the CSS + * "font-family" property + */ + String getDefaultFontFamily(); + + /** + * Returns the CSS media to use. + * @return empty string if no CSS media was specified. + */ + String getMedia(); + + /** + * Returns true if the selection overlay is painted in XOR mode, false + * otherwise. + */ + boolean isSelectionOverlayXORMode(); + + /** + * Returns true if the input scriptType can be loaded in + * this application. + */ + boolean canLoadScriptType(String scriptType); + + /** + * Returns the allowed origins for scripts. + * @see ResourceOrigin + */ + int getAllowedScriptOrigin(); + + /** + * Returns the allowed origins for external + * resources. + * + * @see ResourceOrigin + */ + int getAllowedExternalResourceOrigin(); + + /** + * Notifies Application of recently visited URI + */ + void addVisitedURI(String uri); + + /** + * Asks Application for a list of recently visited URI + */ + String[] getVisitedURIs(); + + /** + * Returns the UI resource specialization to use. + */ + String getUISpecialization(); +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DOMDocumentTree.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DOMDocumentTree.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DOMDocumentTree.java 8 Apr 2013 10:55:09 -0000 1.1 @@ -0,0 +1,1013 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.Autoscroll; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragGestureRecognizer; +import java.awt.dnd.DragSource; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.DragSourceListener; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetContext; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.dnd.DropTargetEvent; +import java.awt.dnd.DropTargetListener; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.IOException; +import java.util.ArrayList; +import java.util.EventListener; +import java.util.EventObject; +import java.util.Iterator; + +import javax.swing.JPanel; +import javax.swing.JRootPane; +import javax.swing.JTree; +import javax.swing.JViewport; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.UIManager; +import javax.swing.event.EventListenerList; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; + +import org.apache.batik.dom.util.DOMUtilities; +import org.apache.batik.apps.svgbrowser.DOMViewer.NodeInfo; + +import org.w3c.dom.Node; + +/** + * A swing tree to represent DOM Document. + */ +public class DOMDocumentTree extends JTree implements Autoscroll { + + /** + * Listeners list. + */ + protected EventListenerList eventListeners = new EventListenerList(); + + /** + * The insets where autoscrolling is active. + */ + protected Insets autoscrollInsets = new Insets(20, 20, 20, 20); + + /** + * How much to scroll. + */ + protected Insets scrollUnits = new Insets(25, 25, 25, 25); + + /** + * The controller for this tree. + */ + protected DOMDocumentTreeController controller; + + /** + * Creates the DOMDocumentTree. + * + * @param root + * Root node + * @param controller + * The tree controller + */ + public DOMDocumentTree(TreeNode root, DOMDocumentTreeController controller) { + super(root); + this.controller = controller; + new TreeDragSource(this, DnDConstants.ACTION_COPY_OR_MOVE); + new DropTarget(this, new TreeDropTargetListener(this)); + } + + // DND Support + + /** + * The JTree drag source wrapper. + */ + public class TreeDragSource implements DragSourceListener, + DragGestureListener { + + /** + * The drag source. + */ + protected DragSource source; + + /** + * The drag gesture recognizer. + */ + protected DragGestureRecognizer recognizer; + + /** + * The transferable tree node(s). + */ + protected TransferableTreeNode transferable; + + /** + * The sourceTree. + */ + protected DOMDocumentTree sourceTree; + + /** + * Constructor. + * + * @param tree + * The source tree + * @param actions + * The permitted action + */ + public TreeDragSource(DOMDocumentTree tree, int actions) { + sourceTree = tree; + source = new DragSource(); + recognizer = + source.createDefaultDragGestureRecognizer(sourceTree, actions, + this); + } + + public void dragGestureRecognized(DragGestureEvent dge) { + if (!controller.isDNDSupported()) { + return; + } + TreePath[] paths = sourceTree.getSelectionPaths(); + // If an empty selection is 'being dragged' + if (paths == null) { + return; + } + ArrayList nodeList = new ArrayList(); + for (int i = 0; i < paths.length; i++) { + TreePath path = paths[i]; + // If the root node 'being dragged' + if (path.getPathCount() > 1) { + DefaultMutableTreeNode node = + (DefaultMutableTreeNode) path.getLastPathComponent(); + Node associatedNode = getDomNodeFromTreeNode(node); + if (associatedNode != null) { + nodeList.add(associatedNode); + } + } + } + if (nodeList.isEmpty()) { + return; + } + transferable = new TransferableTreeNode(new TransferData(nodeList)); + + // Sets the default cursor behavior + source.startDrag(dge, null, transferable, this); + } + + public void dragEnter(DragSourceDragEvent dsde) { + } + + public void dragExit(DragSourceEvent dse) { + } + + public void dragOver(DragSourceDragEvent dsde) { + } + + public void dropActionChanged(DragSourceDragEvent dsde) { + } + + public void dragDropEnd(DragSourceDropEvent dsde) { + } + } + + /** + * Tree as a drop target listener. + */ + public class TreeDropTargetListener implements DropTargetListener { + + /** + * Insert node before the current node. + */ + private static final int BEFORE = 1; + + /** + * Insert node after the current node. + */ + private static final int AFTER = 2; + + /** + * Insert node as a child of the current node. + */ + private static final int CURRENT = 3; + + /** + * The associated transfer data. + */ + private TransferData transferData; + + /** + * The original glass pane of the tree is stored here. + */ + private Component originalGlassPane; + + /** + * The vertical offset where to catch the 'visual tips' of the tree node + * items rectangle. + */ + private int visualTipOffset = 5; + + /** + * The thickness of the visual tip. + */ + private int visualTipThickness = 2; + + /** + * Indicates the potential drop position relative to the current node + * where the dragged nodes are to be inserted. + */ + private int positionIndicator; + + /** + * The start point of the 'visual tip' line. + */ + private Point startPoint; + + /** + * The end point of the 'visual tip' line. + */ + private Point endPoint; + + /** + * Glasspane where 'visual tip' line is drawn + */ + protected JPanel visualTipGlassPane = new JPanel() { + public void paint(Graphics g) { + g.setColor(UIManager.getColor("Tree.selectionBackground")); + if (startPoint == null || endPoint == null) { + return; + } + int x1 = startPoint.x; + int x2 = endPoint.x; + int y1 = startPoint.y; + + // Draws the visualTipThickness number of lines + int start = -visualTipThickness / 2; + start += visualTipThickness % 2 == 0 ? 1 : 0; + for (int i = start; i <= visualTipThickness / 2; i++) { + g.drawLine(x1 + 2, y1 + i, x2 - 2, y1 + i); + } + } + }; + + /** + * The timer that controls the delay of expanding the tree path that is + * being dragged over. + */ + private Timer expandControlTimer; + + /** + * The delay for expanding. + */ + private int expandTimeout = 1500; + + /** + * The tree path that is being dragged over. + */ + private TreePath dragOverTreePath; + + /** + * The tree path that is scheduled for expand. + */ + private TreePath treePathToExpand; + + /** + * Constructor. + */ + public TreeDropTargetListener(DOMDocumentTree tree) { + addOnAutoscrollListener(tree); + } + + public void dragEnter(DropTargetDragEvent dtde) { + JTree tree = (JTree) dtde.getDropTargetContext().getComponent(); + JRootPane rootPane = tree.getRootPane(); + // Set glass pane + originalGlassPane = rootPane.getGlassPane(); + rootPane.setGlassPane(visualTipGlassPane); + visualTipGlassPane.setOpaque(false); + visualTipGlassPane.setVisible(true); + updateVisualTipLine(tree, null); + // Set transferable + try { + // XXX Java 1.3 and 1.4 workaround for: + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4378091 + Transferable transferable = + new DropTargetDropEvent(dtde.getDropTargetContext(), + dtde.getLocation(), 0, 0) + .getTransferable(); + // Transferable transferable = dtde.getTransferable(); + DataFlavor[] flavors = transferable.getTransferDataFlavors(); + for (int i = 0; i < flavors.length; i++) { + if (transferable.isDataFlavorSupported(flavors[i])) { + transferData = (TransferData) transferable + .getTransferData(flavors[i]); + return; + } + } + } catch (UnsupportedFlavorException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void dragOver(DropTargetDragEvent dtde) { + JTree tree = (JTree) dtde.getDropTargetContext().getComponent(); + TreeNode targetTreeNode = getNode(dtde); + if (targetTreeNode != null) { + // Get the parent and sibling paths and nodes + updatePositionIndicator(dtde); + Point p = dtde.getLocation(); + TreePath currentPath = tree.getPathForLocation(p.x, p.y); + TreePath parentPath = getParentPathForPosition(currentPath); + TreeNode parentNode = getNodeForPath(parentPath); + TreePath nextSiblingPath = + getSiblingPathForPosition(currentPath); + TreeNode nextSiblingNode = getNodeForPath(nextSiblingPath); + Node potentialParent = + getDomNodeFromTreeNode((DefaultMutableTreeNode) parentNode); + Node potentialSibling = + getDomNodeFromTreeNode + ((DefaultMutableTreeNode) nextSiblingNode); + // Check the drop target: + // - Checks if any node from the dragged nodes can be appended + // to the parent node + // - Checks whether the sibling node is among the nodes being + // dragged + if (DOMUtilities.canAppendAny(transferData.getNodeList(), + potentialParent) + && !transferData.getNodeList() + .contains(potentialSibling)) { + dtde.acceptDrag(dtde.getDropAction()); + // Draw the 'visual tip' line + updateVisualTipLine(tree, currentPath); + // Expand the path + dragOverTreePath = currentPath; + if (!tree.isExpanded(currentPath)) { + scheduleExpand(currentPath, tree); + } + } else { + dtde.rejectDrag(); + } + } else { + dtde.rejectDrag(); + } + } + + public void dropActionChanged(DropTargetDragEvent dtde) { + } + + public void drop(DropTargetDropEvent dtde) { + Point p = dtde.getLocation(); + DropTargetContext dtc = dtde.getDropTargetContext(); + JTree tree = (JTree) dtc.getComponent(); + // Sets the original glass pane + setOriginalGlassPane(tree); + // Cancel tree item expanding + dragOverTreePath = null; + // Get the parent and sibling paths and nodes + TreePath currentPath = tree.getPathForLocation(p.x, p.y); + DefaultMutableTreeNode parent = + (DefaultMutableTreeNode) getNodeForPath + (getParentPathForPosition(currentPath)); + Node dropTargetNode = getDomNodeFromTreeNode(parent); + DefaultMutableTreeNode sibling = + (DefaultMutableTreeNode) + getNodeForPath(getSiblingPathForPosition(currentPath)); + Node siblingNode = getDomNodeFromTreeNode(sibling); + if (this.transferData != null) { + ArrayList nodelist = + getNodeListForParent(this.transferData.getNodeList(), + dropTargetNode); + fireDropCompleted + (new DOMDocumentTreeEvent + (new DropCompletedInfo + (dropTargetNode, siblingNode, nodelist))); + dtde.dropComplete(true); + return; + } + dtde.rejectDrop(); + } + + public void dragExit(DropTargetEvent dte) { + setOriginalGlassPane + ((JTree) dte.getDropTargetContext().getComponent()); + // Set the current dragover path + dragOverTreePath = null; + } + + /** + * Sets the position indicator according to the current cursor location. + * + * @param dtde + * DropTargetDragEvent + */ + private void updatePositionIndicator(DropTargetDragEvent dtde) { + Point p = dtde.getLocation(); + DropTargetContext dtc = dtde.getDropTargetContext(); + JTree tree = (JTree) dtc.getComponent(); + // Current path + TreePath currentPath = tree.getPathForLocation(p.x, p.y); + Rectangle bounds = tree.getPathBounds(currentPath); + // Upper area of the tree node + if (p.y <= bounds.y + visualTipOffset) { + positionIndicator = BEFORE; + } + // Lower area of the tree node + else if (p.y >= bounds.y + bounds.height - visualTipOffset) { + positionIndicator = AFTER; + } + // Somewhere between the upper and the lower area of the tree node + else { + positionIndicator = CURRENT; + } + } + + /** + * Finds the parent TreePath of the given current path, according to the + * position indicator, where the dragged nodes should be appended. + * + * @param currentPath + * The current path (the items are dragged over this path) + * @param positionIndicator + * AFTER or BEFORE - nodes should be appended to the parent + * path of the given path, as siblings of the current path + * CURRENT - nodes should be appended to the current path, as + * its children + * @return TreePath where dragged nodes are to be inserted + */ + private TreePath getParentPathForPosition(TreePath currentPath) { + if (currentPath == null) { + return null; + } + TreePath parentPath = null; + if (positionIndicator == AFTER) { + parentPath = currentPath.getParentPath(); + } else if (positionIndicator == BEFORE) { + parentPath = currentPath.getParentPath(); + } else if (positionIndicator == CURRENT) { + parentPath = currentPath; + } + return parentPath; + } + + /** + * Finds the TreePath that is going to be next sibling to the nodes that + * are being dragged. + * + * @param currentPath + * The current path (the items are dragged over this path) + * @return sibling TreePath + */ + private TreePath getSiblingPathForPosition(TreePath currentPath) { + TreePath parentPath = getParentPathForPosition(currentPath); + TreePath nextSiblingPath = null; + if (positionIndicator == AFTER) { + TreeNode parentNode = getNodeForPath(parentPath); + TreeNode currentNode = getNodeForPath(currentPath); + if (parentPath != null && parentNode != null + && currentNode != null) { + int siblingIndex = parentNode.getIndex(currentNode) + 1; + if (parentNode.getChildCount() > siblingIndex) { + nextSiblingPath = + parentPath.pathByAddingChild + (parentNode.getChildAt(siblingIndex)); + } + } + } else if (positionIndicator == BEFORE) { + nextSiblingPath = currentPath; + } else if (positionIndicator == CURRENT) { + nextSiblingPath = null; + } + return nextSiblingPath; + } + + /** + * Gets the TreeNode from the given TreePath. + * + * @param path + * The given TreePath + * @return The TreeNode + */ + private TreeNode getNodeForPath(TreePath path) { + if (path == null || path.getLastPathComponent() == null) { + return null; + } + return (TreeNode) path.getLastPathComponent(); + } + + /** + * Gets the TreeNode from the DropTargetDragEvent + * + * @param dtde + * The DropTargetDragEvent + * @return Associated TreeNode or null + */ + private TreeNode getNode(DropTargetDragEvent dtde) { + Point p = dtde.getLocation(); + DropTargetContext dtc = dtde.getDropTargetContext(); + JTree tree = (JTree) dtc.getComponent(); + TreePath path = tree.getPathForLocation(p.x, p.y); + if (path == null || path.getLastPathComponent() == null) { + return null; + } + return (TreeNode) path.getLastPathComponent(); + } + + // Visual tips + /** + * Draws the 'visual tip' line on the glass pane. + * + * @param tree + * The tree + * @param path + * The path to get the bounds + */ + private void updateVisualTipLine(JTree tree, TreePath path) { + if (path == null) { + startPoint = null; + endPoint = null; + } else { + Rectangle bounds = tree.getPathBounds(path); + if (positionIndicator == BEFORE) { + startPoint = bounds.getLocation(); + endPoint = new Point(startPoint.x + bounds.width, + startPoint.y); + } else if (positionIndicator == AFTER) { + startPoint = new Point(bounds.x, bounds.y + bounds.height); + endPoint = new Point(startPoint.x + bounds.width, + startPoint.y); + positionIndicator = AFTER; + } else if (positionIndicator == CURRENT) { + startPoint = null; + endPoint = null; + } + if (startPoint != null && endPoint != null) { + startPoint = SwingUtilities.convertPoint(tree, startPoint, + visualTipGlassPane); + endPoint = SwingUtilities.convertPoint(tree, endPoint, + visualTipGlassPane); + } + } + visualTipGlassPane.getRootPane().repaint(); + } + + /** + * Adds the onAutoscroll listener. + * + * @param tree + * The DOMDocumentTree + */ + private void addOnAutoscrollListener(DOMDocumentTree tree) { + tree.addListener(new DOMDocumentTreeAdapter() { + public void onAutoscroll(DOMDocumentTreeEvent event) { + // Whenever autoscroll is triggered, + // the 'visual tip' line should be hidden + startPoint = null; + endPoint = null; + } + }); + } + + /** + * Sets the original glass pane. + * + * @param dte + * DropTargetEvent to get the tree + */ + private void setOriginalGlassPane(JTree tree) { + JRootPane rootPane = tree.getRootPane(); + rootPane.setGlassPane(originalGlassPane); + originalGlassPane.setVisible(false); + rootPane.repaint(); + } + + // Expand scheduling + /** + * Schedules the expand of the given treePath on a tree. + * + * @param treePath + * The treePath to expand + * @param tree + * The JTree + */ + private void scheduleExpand(TreePath treePath, JTree tree) { + // If the treepath to schedule for expand isn't already scheduled + if (treePath != treePathToExpand) { + getExpandTreeTimer(tree).stop(); + treePathToExpand = treePath; + getExpandTreeTimer(tree).start(); + } + } + + /** + * Gets the timer for treepath expand. + * + * @param tree + * The JTree + * @return Timer + */ + private Timer getExpandTreeTimer(final JTree tree) { + if (expandControlTimer == null) { + expandControlTimer = new Timer(expandTimeout, + new ActionListener() { + public void actionPerformed(ActionEvent arg0) { + // If the treepath scheduled for expand is the + // same one that is being dragged over + if (treePathToExpand != null + && treePathToExpand == dragOverTreePath) { + tree.expandPath(treePathToExpand); + } + getExpandTreeTimer(tree).stop(); + } + }); + } + return expandControlTimer; + } + } + + /** + * Transferable tree node. + */ + public static class TransferableTreeNode implements Transferable { + + /** + * A flavor that supports the node transfer. + */ + protected static final DataFlavor NODE_FLAVOR = + new DataFlavor(TransferData.class, "TransferData"); + + /** + * The supported flavors. + */ + protected static final DataFlavor[] FLAVORS = + new DataFlavor[] { NODE_FLAVOR, DataFlavor.stringFlavor }; + + /** + * The data being transfered. + */ + protected TransferData data; + + public TransferableTreeNode(TransferData data) { + this.data = data; + } + + public synchronized DataFlavor[] getTransferDataFlavors() { + return FLAVORS; + } + + /** + * Checks if the given date flavor is supported. + * + * @param flavor + * DataFlavor + * @return boolean + */ + public boolean isDataFlavorSupported(DataFlavor flavor) { + for (int i = 0; i < FLAVORS.length; i++) { + if (flavor.equals(FLAVORS[i])) { + return true; + } + } + return false; + } + + /** + * Data that is being transfered. + * + * @param flavor + * DataFlavor + * @return (TransferData data, String xmlString) + */ + public synchronized Object getTransferData(DataFlavor flavor) { + if (!isDataFlavorSupported(flavor)) { + return null; + } + if (flavor.equals(NODE_FLAVOR)) { + return data; + } else if (flavor.equals(DataFlavor.stringFlavor)) { + return data.getNodesAsXML(); + } else { + return null; + } + } + } + + /** + * The data being transfered on dnd. + */ + public static class TransferData { + + /** + * The nodes to transfer. + */ + protected ArrayList nodeList; + + /** + * Creates the TransferData. + * + * @param nodeList + * the nodeList + */ + public TransferData(ArrayList nodeList) { + this.nodeList = nodeList; + } + + /** + * Gets the nodeList. + * + * @return the nodeList + */ + public ArrayList getNodeList() { + return nodeList; + } + + /** + * Gets the concatenated string representation of the nodes in the node + * list. (To support string data flavor) + */ + public String getNodesAsXML() { + String toReturn = ""; + Iterator iterator = nodeList.iterator(); + while (iterator.hasNext()) { + Node node = (Node) iterator.next(); + toReturn += DOMUtilities.getXML(node); + } + return toReturn; + } + } + + // Autoscroll support + + public void autoscroll(Point point) { + JViewport viewport = + (JViewport) SwingUtilities.getAncestorOfClass(JViewport.class, + this); + if (viewport == null) { + return; + } + + Point viewportPos = viewport.getViewPosition(); + int viewHeight = viewport.getExtentSize().height; + int viewWidth = viewport.getExtentSize().width; + + // Scroll + if ((point.y - viewportPos.y) < autoscrollInsets.top) { + // Up + viewport.setViewPosition + (new Point(viewportPos.x, + Math.max(viewportPos.y - scrollUnits.top, 0))); + fireOnAutoscroll(new DOMDocumentTreeEvent(this)); + } else if ((viewportPos.y + viewHeight - point.y) + < autoscrollInsets.bottom) { + // Down + viewport.setViewPosition + (new Point(viewportPos.x, + Math.min(viewportPos.y + scrollUnits.bottom, + getHeight() - viewHeight))); + fireOnAutoscroll(new DOMDocumentTreeEvent(this)); + } else if ((point.x - viewportPos.x) < autoscrollInsets.left) { + // Left + viewport.setViewPosition + (new Point(Math.max(viewportPos.x - scrollUnits.left, 0), + viewportPos.y)); + fireOnAutoscroll(new DOMDocumentTreeEvent(this)); + } else if ((viewportPos.x + viewWidth - point.x) + < autoscrollInsets.right) { + // Right + viewport.setViewPosition + (new Point(Math.min(viewportPos.x + scrollUnits.right, + getWidth() - viewWidth), + viewportPos.y)); + fireOnAutoscroll(new DOMDocumentTreeEvent(this)); + } + } + + public Insets getAutoscrollInsets() { + int topAndBottom = getHeight(); + int leftAndRight = getWidth(); + return new Insets + (topAndBottom, leftAndRight, topAndBottom, leftAndRight); + } + + // Custom event support + + /** + * Event to pass to listener. + */ + public static class DOMDocumentTreeEvent extends EventObject { + + public DOMDocumentTreeEvent(Object source) { + super(source); + } + } + + /** + * The DOMDocumentTreeListener. + */ + public static interface DOMDocumentTreeListener extends EventListener { + + /** + * Fired after successfully completed drop. + * + * @param event + * the DOMDocumentTreeEvent + */ + void dropCompleted(DOMDocumentTreeEvent event); + + /** + * Fired when autoscroll is invoked + * + * @param event + * the DOMDocumentTreeEvent + */ + void onAutoscroll(DOMDocumentTreeEvent event); + } + + /** + * The adapter for the DOMDocumentTreeListener. + */ + public static class DOMDocumentTreeAdapter + implements DOMDocumentTreeListener { + + public void dropCompleted(DOMDocumentTreeEvent event) { + } + + public void onAutoscroll(DOMDocumentTreeEvent event) { + } + } + + /** + * Adds the listener to the listener list. + * + * @param listener + * The listener to add + */ + public void addListener(DOMDocumentTreeListener listener) { + eventListeners.add(DOMDocumentTreeListener.class, listener); + } + + /** + * Fires the dropCompleted event. + * + * @param event + * The associated DndTreeSupportEvent event + */ + public void fireDropCompleted(DOMDocumentTreeEvent event) { + Object[] listeners = eventListeners.getListenerList(); + int length = listeners.length; + for (int i = 0; i < length; i += 2) { + if (listeners[i] == DOMDocumentTreeListener.class) { + ((DOMDocumentTreeListener) listeners[i + 1]) + .dropCompleted(event); + } + } + } + + /** + * Fires the dropCompleted event. + * + * @param event + * The associated DndTreeSupportEvent event + */ + public void fireOnAutoscroll(DOMDocumentTreeEvent event) { + Object[] listeners = eventListeners.getListenerList(); + int length = listeners.length; + for (int i = 0; i < length; i += 2) { + if (listeners[i] == DOMDocumentTreeListener.class) { + ((DOMDocumentTreeListener) listeners[i + 1]) + .onAutoscroll(event); + } + } + } + + /** + * Contains the info for the 'dropCompleted' Event. + */ + public static class DropCompletedInfo { + + /** + * Parent node. + */ + protected Node parent; + + /** + * Nodes to be appended. + */ + protected ArrayList children; + + /** + * Next sibling node. + */ + protected Node sibling; + + /** + * @param parent + * Parent node + * @param children + * Nodes to be appended + */ + public DropCompletedInfo(Node parent, Node sibling, + ArrayList children) { + this.parent = parent; + this.sibling = sibling; + this.children = children; + } + + /** + * Gets the children. + * + * @return the children + */ + public ArrayList getChildren() { + return children; + } + + /** + * Getter for the parent. + * + * @return the parent + */ + public Node getParent() { + return parent; + } + + /** + * Getter for the sibling. + * + * @return the sibling + */ + public Node getSibling() { + return sibling; + } + } + + // Utility methods + + /** + * Gets the associated org.w3c.dom.Node from the DefaultMutableTreeNode + * + * @param treeNode + * The given DefaultMutableTreeNode + * @return the associated Node + */ + protected Node getDomNodeFromTreeNode(DefaultMutableTreeNode treeNode) { + if (treeNode == null) { + return null; + } + if (treeNode.getUserObject() instanceof NodeInfo) { + return ((NodeInfo) treeNode.getUserObject()).getNode(); + } + return null; + } + + /** + * Finds and returns a group of nodes that can be appended to the given + * parent node. + * + * @param potentialChildren + * The given potential children + * @param parentNode + * The given parent node + * @return list of nodes that can be appended to the given parent + */ + protected ArrayList getNodeListForParent(ArrayList potentialChildren, + Node parentNode) { + ArrayList children = new ArrayList(); + int n = potentialChildren.size(); + for (int i = 0; i < n; i++) { + Node node = (Node) potentialChildren.get(i); + if (DOMUtilities.canAppend(node, parentNode)) { + children.add(node); + } + } + return children; + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DOMDocumentTreeController.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DOMDocumentTreeController.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DOMDocumentTreeController.java 8 Apr 2013 10:55:09 -0000 1.1 @@ -0,0 +1,30 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +/** + * Provides the information to control the DOMDocumentTree behaviour. + */ +public interface DOMDocumentTreeController { + + /** + * Returns whether the DOMDocumentTree supports drag-and-drop. + */ + boolean isDNDSupported(); +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DOMViewer.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DOMViewer.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DOMViewer.java 8 Apr 2013 10:55:08 -0000 1.1 @@ -0,0 +1,2109 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; +import javax.swing.JTree; +import javax.swing.SwingUtilities; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.table.AbstractTableModel; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.DefaultTreeModel; +import javax.swing.tree.MutableTreeNode; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; + +import org.apache.batik.apps.svgbrowser.DOMDocumentTree.DOMDocumentTreeAdapter; +import org.apache.batik.apps.svgbrowser.DOMDocumentTree.DOMDocumentTreeEvent; +import org.apache.batik.apps.svgbrowser.DOMDocumentTree.DropCompletedInfo; +import org.apache.batik.apps.svgbrowser.DropDownHistoryModel.RedoPopUpMenuModel; +import org.apache.batik.apps.svgbrowser.DropDownHistoryModel.UndoPopUpMenuModel; +import org.apache.batik.apps.svgbrowser.HistoryBrowser.DocumentCommandController; +import org.apache.batik.apps.svgbrowser.NodePickerPanel.NameEditorDialog; +import org.apache.batik.apps.svgbrowser.NodePickerPanel.NodePickerAdapter; +import org.apache.batik.apps.svgbrowser.NodePickerPanel.NodePickerEvent; +import org.apache.batik.apps.svgbrowser.NodeTemplates.NodeTemplateDescriptor; +import org.apache.batik.bridge.svg12.ContentManager; +import org.apache.batik.bridge.svg12.DefaultXBLManager; +import org.apache.batik.dom.AbstractDocument; +import org.apache.batik.dom.svg.SVGOMDocument; +import org.apache.batik.dom.svg12.XBLOMContentElement; +import org.apache.batik.dom.util.DOMUtilities; +import org.apache.batik.dom.util.SAXDocumentFactory; +import org.apache.batik.dom.xbl.NodeXBL; +import org.apache.batik.dom.xbl.XBLManager; +import org.apache.batik.util.SVGConstants; +import org.apache.batik.util.XMLResourceDescriptor; +import org.apache.batik.util.gui.DropDownComponent; +import org.apache.batik.util.gui.resource.ActionMap; +import org.apache.batik.util.gui.resource.ButtonFactory; +import org.apache.batik.util.gui.resource.MissingListenerException; +import org.apache.batik.util.resources.ResourceManager; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.css.CSSStyleDeclaration; +import org.w3c.dom.css.ViewCSS; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.MutationEvent; + +/** + * The components of this class are used to view a DOM tree. + * + * @author Stephane Hillion + * @version $Id: DOMViewer.java,v 1.1 2013/04/08 10:55:08 marcin Exp $ + */ +public class DOMViewer extends JFrame implements ActionMap { + + /** + * The resource file name + */ + protected static final String RESOURCE = + "org.apache.batik.apps.svgbrowser.resources.DOMViewerMessages"; + + /** + * The resource bundle + */ + protected static ResourceBundle bundle; + + /** + * The resource manager + */ + protected static ResourceManager resources; + + static { + bundle = ResourceBundle.getBundle(RESOURCE, Locale.getDefault()); + resources = new ResourceManager(bundle); + } + + /** + * The map that contains the listeners + */ + protected Map listeners = new HashMap(); + + /** + * The button factory. + */ + protected ButtonFactory buttonFactory; + + /** + * The panel. + */ + protected Panel panel; + + /** + * Whether to show text nodes that contain only whitespace in the tree. + */ + protected boolean showWhitespace = true; + + /** + * Whether "capturing click" tool is enabled. If enabled, the element being + * clicked on is found and selected in the DOMViewer's document tree + */ + protected boolean isCapturingClickEnabled; + + /** + * The DOMViewer controller. + */ + protected DOMViewerController domViewerController; + + /** + * Manages the element selection on the canvas. + */ + protected ElementOverlayManager elementOverlayManager; + + /** + * Whether painting the overlay on the canvas is enabled. + */ + protected boolean isElementOverlayEnabled; + + /** + * The history browsing manager. Manages undo / redo. + */ + protected HistoryBrowserInterface historyBrowserInterface; + + /** + * Whether the DOMViewer can be used for editing the document. + */ + protected boolean canEdit = true; + + /** + * The button for enabling and disabling the overlay. + */ + protected JToggleButton overlayButton; + + /** + * Creates a new DOMViewer panel. + */ + public DOMViewer(DOMViewerController controller) { + super(resources.getString("Frame.title")); + setSize(resources.getInteger("Frame.width"), + resources.getInteger("Frame.height")); + + domViewerController = controller; + + elementOverlayManager = domViewerController.createSelectionManager(); + if (elementOverlayManager != null) { + elementOverlayManager + .setController(new DOMViewerElementOverlayController()); + } + historyBrowserInterface = + new HistoryBrowserInterface + (new DocumentCommandController(controller)); + + listeners.put("CloseButtonAction", new CloseButtonAction()); + listeners.put("UndoButtonAction", new UndoButtonAction()); + listeners.put("RedoButtonAction", new RedoButtonAction()); + listeners.put("CapturingClickButtonAction", + new CapturingClickButtonAction()); + listeners.put("OverlayButtonAction", new OverlayButtonAction()); + + // Create the main panel + panel = new Panel(); + getContentPane().add(panel); + + JPanel p = new JPanel(new BorderLayout()); + JCheckBox cb = + new JCheckBox(resources.getString("ShowWhitespaceCheckbox.text")); + cb.setSelected(showWhitespace); + cb.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent ie) { + setShowWhitespace(ie.getStateChange() == ItemEvent.SELECTED); + } + }); + p.add(cb, BorderLayout.WEST); + p.add(getButtonFactory().createJButton("CloseButton"), + BorderLayout.EAST); + getContentPane().add(p, BorderLayout.SOUTH); + + // Set the document + Document document = domViewerController.getDocument(); + if (document != null) { +// panel +// .setDocument(document, (ViewCSS) document +// .getDocumentElement()); + panel.setDocument(document, null); + } + } + + /** + * Sets whether to show text nodes that contain only whitespace in the tree. + */ + public void setShowWhitespace(boolean state) { + showWhitespace = state; + if (panel.document != null) + panel.setDocument(panel.document); + } + + /** + * Sets the document to display. + */ + public void setDocument(Document doc) { + panel.setDocument(doc); + } + + /** + * Sets the document to display and its ViewCSS. + */ + public void setDocument(Document doc, ViewCSS view) { + panel.setDocument(doc, view); + } + + /** + * Whether the document can be edited using the DOMViewer. + * + * @return True if the document can be edited throught the DOMViewer + */ + public boolean canEdit() { + return domViewerController.canEdit() && canEdit; + } + + /** + * Enables / disables the DOMViewer to be used to edit the documents. + * + * @param canEdit + * True - The DOMViewer can be used to edit the documents + */ + public void setEditable(boolean canEdit) { + this.canEdit = canEdit; + } + + /** + * Selects and scrolls to the given node in the document tree. + * + * @param node + * The node to be selected + */ + public void selectNode(Node node) { + panel.selectNode(node); + } + + /** + * Resets the history. + */ + public void resetHistory() { + historyBrowserInterface.getHistoryBrowser().resetHistory(); + } + + /** + * Gets buttonFactory. + */ + private ButtonFactory getButtonFactory() { + if (buttonFactory == null) { + buttonFactory = new ButtonFactory(bundle, this); + } + return buttonFactory; + } + + // ActionMap + + /** + * Returns the action associated with the given string or null on error + * + * @param key + * the key mapped with the action to get + * @throws MissingListenerException + * if the action is not found + */ + public Action getAction(String key) throws MissingListenerException { + return (Action)listeners.get(key); + } + + /** + * Groups the document changes that were made out of the document into a + * single change and adds this change to the history browser. + */ + private void addChangesToHistory() { + historyBrowserInterface.performCurrentCompoundCommand(); + } + + /** + * The action associated with the 'Close' button of the viewer panel + */ + protected class CloseButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + if (panel.attributePanel.panelHiding()) { + panel.tree.setSelectionRow(0); + DOMViewer.this.dispose(); + } + } + } + + /** + * The action associated with the 'Undo' dropdown button of the viewer panel + */ + protected class UndoButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + addChangesToHistory(); + historyBrowserInterface.getHistoryBrowser().undo(); + } + } + + /** + * The action associated with the 'Redo' dropdown button of the viewer panel + */ + protected class RedoButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + addChangesToHistory(); + historyBrowserInterface.getHistoryBrowser().redo(); + } + } + + /** + * The action associated with the 'Capturing-click' toggle button of the + * viewer panel. + */ + protected class CapturingClickButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + JToggleButton btn = (JToggleButton) e.getSource(); + isCapturingClickEnabled = btn.isSelected(); + if (!isCapturingClickEnabled) { + btn.setToolTipText + (resources.getString("CapturingClickButton.tooltip")); + } else { + btn.setToolTipText + (resources.getString("CapturingClickButton.disableText")); + } + } + } + + /** + * Toggles the element highlighting overlay. + */ + protected void toggleOverlay() { + isElementOverlayEnabled = overlayButton.isSelected(); + if (!isElementOverlayEnabled) { + overlayButton.setToolTipText + (resources.getString("OverlayButton.tooltip")); + } else { + overlayButton.setToolTipText + (resources.getString("OverlayButton.disableText")); + } + // Refresh overlay + if (elementOverlayManager != null) { + elementOverlayManager.setOverlayEnabled(isElementOverlayEnabled); + elementOverlayManager.repaint(); + } + } + + /** + * The action associated with the 'overlay' toggle button of the viewer + * panel. + */ + protected class OverlayButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + toggleOverlay(); + } + } + + /** + * NodePickerController implementation. + */ + protected class DOMViewerNodePickerController + implements NodePickerController { + + public boolean isEditable() { + return DOMViewer.this.canEdit(); + } + + public boolean canEdit(Element el) { + if (panel == null || panel.document == null || true + /*|| panel.document.getDocumentElement() != el*/) { + return true; + } + return false; + } + } + + /** + * DOMDocumentTreeController implementation. + */ + protected class DOMViewerDOMDocumentTreeController + implements DOMDocumentTreeController { + + public boolean isDNDSupported() { + return canEdit(); + } + } + + /** + * ElementOverlayController implementation. + */ + protected class DOMViewerElementOverlayController + implements ElementOverlayController { + + public boolean isOverlayEnabled() { + return canEdit() && isElementOverlayEnabled; + } + } + + /** + * The panel that contains the viewer. + */ + public class Panel extends JPanel { + + // DOM Mutation event names. + public static final String NODE_INSERTED = "DOMNodeInserted"; + public static final String NODE_REMOVED = "DOMNodeRemoved"; + public static final String ATTRIBUTE_MODIFIED = "DOMAttrModified"; + public static final String CHAR_DATA_MODIFIED = "DOMCharacterDataModified"; + + /** + * The DOM document. + */ + protected Document document; + + /** + * "Node inserted" DOM Mutation Listener. + */ + protected EventListener nodeInsertion; + + /** + * "Node removed" DOM Mutation Listener. + */ + protected EventListener nodeRemoval; + + /** + * "Attribute modified" DOM Mutation Listener. + */ + protected EventListener attrModification; + + /** + * "Character data modified" DOM Mutation Listener. + */ + protected EventListener charDataModification; + + /** + * Capturing "click" event type listener. Allows the "capturing click" + * option + */ + protected EventListener capturingListener; + + /** + * The ViewCSS object associated with the document. + */ + protected ViewCSS viewCSS; + + /** + * The tree. + */ + protected DOMDocumentTree tree; + + /** + * The split pane. + */ + protected JSplitPane splitPane; + + /** + * The right panel. + */ + protected JPanel rightPanel = new JPanel(new BorderLayout()); + + /** + * The properties table. + */ + protected JTable propertiesTable = new JTable(); + + /** + * The panel to show the nodes attributes. + */ + protected NodePickerPanel attributePanel = + new NodePickerPanel(new DOMViewerNodePickerController()); + { + attributePanel.addListener(new NodePickerAdapter() { + + public void updateElement(NodePickerEvent event) { + String result = event.getResult(); + Element targetElement = (Element) event.getContextNode(); + Element newElem = wrapAndParse(result, targetElement); + + addChangesToHistory(); + + AbstractCompoundCommand cmd = historyBrowserInterface + .createNodeChangedCommand(newElem); + Node parent = targetElement.getParentNode(); + Node nextSibling = targetElement.getNextSibling(); + cmd.addCommand(historyBrowserInterface + .createRemoveChildCommand(parent, targetElement)); + cmd.addCommand(historyBrowserInterface + .createInsertChildCommand(parent, nextSibling, + newElem)); + historyBrowserInterface.performCompoundUpdateCommand(cmd); + + attributePanel.setPreviewElement(newElem); + //selectNewNode(newElem); + } + + public void addNewElement(NodePickerEvent event) { + String result = event.getResult(); + Element targetElement = (Element) event.getContextNode(); + Element newElem = wrapAndParse(result, targetElement); + + addChangesToHistory(); + + historyBrowserInterface.appendChild(targetElement, + newElem); + + attributePanel.setPreviewElement(newElem); + //selectNewNode(newElem); + } + + /** + * Parses the given string into an element after editing, or + * adding new element. The element that should be parsed has to + * have all the active prefixes set, so it has to be wrapped + * with the wrapper element that has all the mentioned prefixes + * bound to the appopriate namespaces. Wrapper element string + * has all the active prefixes set using the parentNode. + * + * @param toParse + * The string that should be parsed into svg element + * @param startingNode + * The node from where to start looking the prefixes + * @return The parsed element + */ + private Element wrapAndParse(String toParse, Node startingNode) { + // Fill the prefix map + Map prefixMap = new HashMap(); + int j = 0; + for (Node currentNode = startingNode; + currentNode != null; + currentNode = currentNode.getParentNode()) { + NamedNodeMap nMap = currentNode.getAttributes(); + for (int i = 0; nMap != null && i < nMap.getLength(); i++) { + Attr atr = (Attr) nMap.item(i); + String prefix = atr.getPrefix(); + String localName = atr.getLocalName(); + String namespaceURI = atr.getValue(); + if (prefix != null + && prefix.equals(SVGConstants.XMLNS_PREFIX)) { + String attrName = SVGConstants.XMLNS_PREFIX + + ":" + localName; + if (!prefixMap.containsKey(attrName)) { + prefixMap.put(attrName, namespaceURI); + } + } + // Start from parentNode searching for the xmlns + if ((j != 0 || currentNode == document + .getDocumentElement()) + && atr.getNodeName().equals( + SVGConstants.XMLNS_PREFIX) + && !prefixMap + .containsKey(SVGConstants.XMLNS_PREFIX)) { + prefixMap.put(SVGConstants.XMLNS_PREFIX, atr + .getNodeValue()); + } + } + j++; + } + Document doc = panel.document; + SAXDocumentFactory df = new SAXDocumentFactory( + doc.getImplementation(), + XMLResourceDescriptor.getXMLParserClassName()); + URL urlObj = null; + if (doc instanceof SVGOMDocument) { + urlObj = ((SVGOMDocument) doc).getURLObject(); + } + String uri = (urlObj == null) ? "" : urlObj.toString(); + Node node = DOMUtilities.parseXML(toParse, doc, uri, + prefixMap, SVGConstants.SVG_SVG_TAG, df); + return (Element) node.getFirstChild(); + } + + /** + * Selects the given element. Needs to be wrapped with the + * UpdateManager to wait for the previous command to be executed + * by HistoryBrowser + * + * @param elem + * The element to select + */ + private void selectNewNode(final Element elem) { + domViewerController.performUpdate(new Runnable() { + public void run() { + selectNode(elem); + }; + }); + } + }); + } + + /** + * The layout for the attribute panel. + */ + protected GridBagConstraints attributePanelLayout = + new GridBagConstraints(); + { + attributePanelLayout.gridx = 1; + attributePanelLayout.gridy = 1; + attributePanelLayout.gridheight = 2; + attributePanelLayout.weightx = 1.0; + attributePanelLayout.weighty = 1.0; + attributePanelLayout.fill = GridBagConstraints.BOTH; + } + + /** + * The layout for the properties table. + */ + protected GridBagConstraints propertiesTableLayout = + new GridBagConstraints(); + { + propertiesTableLayout.gridx = 1; + propertiesTableLayout.gridy = 3; + propertiesTableLayout.weightx = 1.0; + propertiesTableLayout.weighty = 1.0; + propertiesTableLayout.fill = GridBagConstraints.BOTH; + } + + /** + * The element panel. + */ + protected JPanel elementPanel = new JPanel(new GridBagLayout()); + { + JScrollPane pane2 = new JScrollPane(); + pane2.setBorder(BorderFactory.createCompoundBorder(BorderFactory + .createEmptyBorder(2, 0, 2, 2), BorderFactory + .createCompoundBorder(BorderFactory.createTitledBorder( + BorderFactory.createEmptyBorder(), resources + .getString("CSSValuesPanel.title")), + BorderFactory.createLoweredBevelBorder()))); + pane2.getViewport().add(propertiesTable); + + // 2/3 attributePanel, 1/3 propertiesTable + elementPanel.add(attributePanel, attributePanelLayout); + elementPanel.add(pane2, propertiesTableLayout); + } + + /** + * The CharacterData panel text area. + */ + protected class CharacterPanel extends JPanel { + + /** + * Associated node. + */ + protected Node node; + + /** + * The text area. + */ + protected JTextArea textArea = new JTextArea(); + + /** + * Constructor. + * @param layout The LayoutManager + */ + public CharacterPanel(BorderLayout layout) { + super(layout); + } + + /** + * Gets the textArea. + * + * @return textArea + */ + public JTextArea getTextArea() { + return textArea; + } + + /** + * Sets the textArea. + * + * @param textArea + * the text area to set + */ + public void setTextArea(JTextArea textArea) { + this.textArea = textArea; + } + + /** + * Gets the node. + * + * @return node + */ + public Node getNode() { + return node; + } + + /** + * Sets the node. + * + * @param node + * the node to set + */ + public void setNode(Node node) { + this.node = node; + } + } + + /** + * The CharacterData node panel. + */ + protected CharacterPanel characterDataPanel = new CharacterPanel(new BorderLayout()); + { + characterDataPanel.setBorder + (BorderFactory.createCompoundBorder + (BorderFactory.createEmptyBorder(2, 0, 2, 2), + BorderFactory.createCompoundBorder + (BorderFactory.createTitledBorder + (BorderFactory.createEmptyBorder(), + resources.getString("CDataPanel.title")), + BorderFactory.createLoweredBevelBorder()))); + JScrollPane pane = new JScrollPane(); + JTextArea textArea = new JTextArea(); + characterDataPanel.setTextArea(textArea); + pane.getViewport().add(textArea); + characterDataPanel.add(pane); + + textArea.setEditable(true); + textArea.addFocusListener(new FocusAdapter() { + public void focusLost(FocusEvent e) { + if (canEdit()) { + Node contextNode = characterDataPanel.getNode(); + String newValue = characterDataPanel.getTextArea() + .getText(); + switch (contextNode.getNodeType()) { + case Node.COMMENT_NODE: + case Node.TEXT_NODE: + case Node.CDATA_SECTION_NODE: + addChangesToHistory(); + historyBrowserInterface.setNodeValue(contextNode, + newValue); + break; + } + } + } + }); + } + + /** + * The documentInfo panel text area. + */ + protected JTextArea documentInfo = new JTextArea(); + + /** + * The documentInfo node panel. + */ + protected JPanel documentInfoPanel = new JPanel(new BorderLayout()); + { + documentInfoPanel.setBorder + (BorderFactory.createCompoundBorder + (BorderFactory.createEmptyBorder(2, 0, 2, 2), + BorderFactory.createCompoundBorder + (BorderFactory.createTitledBorder + (BorderFactory.createEmptyBorder(), + resources.getString("DocumentInfoPanel.title")), + BorderFactory.createLoweredBevelBorder()))); + JScrollPane pane = new JScrollPane(); + pane.getViewport().add(documentInfo); + documentInfoPanel.add(pane); + documentInfo.setEditable(false); + } + + /** + * Creates a new Panel object. + */ + public Panel() { + super(new BorderLayout()); + setBorder(BorderFactory.createTitledBorder + (BorderFactory.createEmptyBorder(), + resources.getString("DOMViewerPanel.title"))); + + JToolBar tb = + new JToolBar(resources.getString("DOMViewerToolbar.name")); + tb.setFloatable(false); + + // Undo + JButton undoButton = getButtonFactory().createJToolbarButton("UndoButton"); + undoButton.setDisabledIcon + (new ImageIcon + (getClass().getResource(resources.getString("UndoButton.disabledIcon")))); + DropDownComponent undoDD = new DropDownComponent(undoButton); + undoDD.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 2)); + undoDD.setMaximumSize(new Dimension(44, 25)); + undoDD.setPreferredSize(new Dimension(44, 25)); + tb.add(undoDD); + UndoPopUpMenuModel undoModel = new UndoPopUpMenuModel(undoDD + .getPopupMenu(), historyBrowserInterface); + undoDD.getPopupMenu().setModel(undoModel); + + // Redo + JButton redoButton = getButtonFactory().createJToolbarButton("RedoButton"); + redoButton.setDisabledIcon + (new ImageIcon + (getClass().getResource(resources.getString("RedoButton.disabledIcon")))); + DropDownComponent redoDD = new DropDownComponent(redoButton); + redoDD.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 2)); + redoDD.setMaximumSize(new Dimension(44, 25)); + redoDD.setPreferredSize(new Dimension(44, 25)); + tb.add(redoDD); + RedoPopUpMenuModel redoModel = new RedoPopUpMenuModel(redoDD + .getPopupMenu(), historyBrowserInterface); + redoDD.getPopupMenu().setModel(redoModel); + + // Capturing click toggle button + JToggleButton capturingClickButton = getButtonFactory() + .createJToolbarToggleButton("CapturingClickButton"); + capturingClickButton.setEnabled(true); + capturingClickButton.setPreferredSize(new Dimension(32, 25)); + tb.add(capturingClickButton); + + // Overlay toggle button + overlayButton = + getButtonFactory().createJToolbarToggleButton("OverlayButton"); + overlayButton.setEnabled(true); + overlayButton.setPreferredSize(new Dimension(32, 25)); + tb.add(overlayButton); + + // Add toolbar + add(tb, BorderLayout.NORTH); + + // DOMDocumentTree + TreeNode root; + root = new DefaultMutableTreeNode + (resources.getString("EmptyDocument.text")); + tree = new DOMDocumentTree + (root, new DOMViewerDOMDocumentTreeController()); + tree.setCellRenderer(new NodeRenderer()); + tree.putClientProperty("JTree.lineStyle", "Angled"); + // Add the listeners to DOMDocumentTree + tree.addListener(new DOMDocumentTreeAdapter() { + + public void dropCompleted(DOMDocumentTreeEvent event) { + DropCompletedInfo info = (DropCompletedInfo) event + .getSource(); + + addChangesToHistory(); + + AbstractCompoundCommand cmd = historyBrowserInterface + .createNodesDroppedCommand(info.getChildren()); + + int n = info.getChildren().size(); + for (int i = 0; i < n; i++) { + Node node = (Node) info.getChildren().get(i); + // If the node has its ancestor in selected nodes, + // it should stay as it's child + if (!DOMUtilities.isAnyNodeAncestorOf(info + .getChildren(), node)) { + cmd.addCommand(historyBrowserInterface + .createInsertChildCommand(info.getParent(), + info.getSibling(), node)); + } + } + historyBrowserInterface.performCompoundUpdateCommand(cmd); + } + }); + tree.addTreeSelectionListener(new DOMTreeSelectionListener()); + tree.addMouseListener(new TreePopUpListener()); + JScrollPane treePane = new JScrollPane(); + treePane.setBorder(BorderFactory.createCompoundBorder + (BorderFactory.createEmptyBorder(2, 2, 2, 0), + BorderFactory.createCompoundBorder + (BorderFactory.createTitledBorder + (BorderFactory.createEmptyBorder(), + resources.getString("DOMViewer.title")), + BorderFactory.createLoweredBevelBorder()))); + treePane.getViewport().add(tree); + splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, + true, // Continuous layout + treePane, + rightPanel); + int loc = resources.getInteger("SplitPane.dividerLocation"); + splitPane.setDividerLocation(loc); + add(splitPane); + } + + /** + * Sets the document to display. + */ + public void setDocument(Document doc) { + setDocument(doc, null); + } + + /** + * Sets the document to display and its ViewCSS. + */ + public void setDocument(Document doc, ViewCSS view) { + if (document != null) { + if (document != doc) { + removeDomMutationListeners(document); + addDomMutationListeners(doc); + removeCapturingListener(document); + addCapturingListener(doc); + } + } + else { + addDomMutationListeners(doc); + addCapturingListener(doc); + } + resetHistory(); + document = doc; + viewCSS = view; + TreeNode root = createTree(doc, showWhitespace); + ((DefaultTreeModel) tree.getModel()).setRoot(root); + if (rightPanel.getComponentCount() != 0) { + rightPanel.remove(0); + splitPane.revalidate(); + splitPane.repaint(); + } + } + + /** + * Registers DOM Mutation Listener on the given document. + * + * @param doc + * The given document + */ + protected void addDomMutationListeners(Document doc) { + EventTarget target = (EventTarget) doc; + nodeInsertion = new NodeInsertionHandler(); + target.addEventListener(NODE_INSERTED, nodeInsertion, true); + nodeRemoval = new NodeRemovalHandler(); + target.addEventListener(NODE_REMOVED, nodeRemoval, true); + attrModification = new AttributeModificationHandler(); + target.addEventListener(ATTRIBUTE_MODIFIED, attrModification, + true); + charDataModification = new CharDataModificationHandler(); + target.addEventListener(CHAR_DATA_MODIFIED, + charDataModification, true); + } + + /** + * Removes previously registered mutation listeners from the document. + * + * @param doc + * The document + */ + protected void removeDomMutationListeners(Document doc) { + if (doc != null) { + EventTarget target = (EventTarget) doc; + target.removeEventListener(NODE_INSERTED, nodeInsertion, true); + target.removeEventListener(NODE_REMOVED, nodeRemoval, true); + target.removeEventListener(ATTRIBUTE_MODIFIED, + attrModification, true); + target.removeEventListener(CHAR_DATA_MODIFIED, + charDataModification, true); + } + } + + /** + * Registers capturing "click" listener on the document element of the + * given document. + * + * @param doc + * The given document + */ + protected void addCapturingListener(Document doc) { + EventTarget target = (EventTarget) doc.getDocumentElement(); + capturingListener = new CapturingClickHandler(); + target.addEventListener(SVGConstants.SVG_CLICK_EVENT_TYPE, + capturingListener, true); + } + + /** + * Removes previously registered capturing "click" event listener from + * the document element of the given document. + * + * @param doc + * The given document + */ + protected void removeCapturingListener(Document doc) { + if (doc != null) { + EventTarget target = (EventTarget) doc.getDocumentElement(); + target.removeEventListener(SVGConstants.SVG_CLICK_EVENT_TYPE, + capturingListener, true); + } + } + + /** + * Handles "DOMNodeInserted" event. + */ + protected class NodeInsertionHandler implements EventListener { + + public void handleEvent(final Event evt) { + Runnable runnable = new Runnable() { + public void run() { + MutationEvent mevt = (MutationEvent) evt; + Node targetNode = (Node) mevt.getTarget(); + DefaultMutableTreeNode parentNode = findNode(tree, + targetNode.getParentNode()); + DefaultMutableTreeNode insertedNode = + (DefaultMutableTreeNode) + createTree(targetNode, showWhitespace); + DefaultTreeModel model = + (DefaultTreeModel) tree.getModel(); + DefaultMutableTreeNode newParentNode = + (DefaultMutableTreeNode) + createTree(targetNode.getParentNode(), + showWhitespace); + // Finds where to insert the node in the tree + int index = findIndexToInsert(parentNode, newParentNode); + if (index != -1) { + model.insertNodeInto + (insertedNode, parentNode, index); + } + attributePanel.updateOnDocumentChange(mevt.getType(), + targetNode); + } + }; + refreshGUI(runnable); + registerDocumentChange((MutationEvent)evt); + } + + /** + * Compares the children of the two tree nodes and returns the index + * of the first difference. + * + * @param parentNode + * The old tree node + * @param newParentNode + * The new tree node + * @return first child that differs + */ + protected int findIndexToInsert + (DefaultMutableTreeNode parentNode, + DefaultMutableTreeNode newParentNode) { + int index = -1; + if (parentNode == null || newParentNode == null) { + return index; + } + // Finds the index where to insert new node + Enumeration oldChildren = parentNode.children(); + Enumeration newChildren = newParentNode.children(); + int count = 0; + while (oldChildren.hasMoreElements()) { + // Current DefaultMutableTreeNode node being processed + DefaultMutableTreeNode currentOldChild = + (DefaultMutableTreeNode) oldChildren.nextElement(); + DefaultMutableTreeNode currentNewChild = + (DefaultMutableTreeNode) newChildren.nextElement(); + Node oldChild = + ((NodeInfo) currentOldChild.getUserObject()).getNode(); + Node newChild = + ((NodeInfo) currentNewChild.getUserObject()).getNode(); + if (oldChild != newChild) { + return count; + } + count++; + } + return count; + } + } + + /** + * Handles "DOMNodeRemoved" event. + */ + protected class NodeRemovalHandler implements EventListener { + + public void handleEvent(final Event evt) { + Runnable runnable = new Runnable() { + public void run() { + MutationEvent mevt = (MutationEvent) evt; + Node targetNode = (Node) mevt.getTarget(); + DefaultMutableTreeNode treeNode = findNode(tree, + targetNode); + DefaultTreeModel model = (DefaultTreeModel) tree + .getModel(); + if (treeNode != null) { + model.removeNodeFromParent(treeNode); + } + attributePanel.updateOnDocumentChange(mevt.getType(), + targetNode); + } + }; + refreshGUI(runnable); + registerDocumentChange((MutationEvent)evt); + } + } + + /** + * Handles "DOMAttrModified" event. + */ + protected class AttributeModificationHandler implements EventListener { + + public void handleEvent(final Event evt) { + Runnable runnable = new Runnable() { + public void run() { + MutationEvent mevt = (MutationEvent) evt; + Element targetElement = (Element) mevt.getTarget(); + // Repaint the target node + DefaultTreeModel model = (DefaultTreeModel) tree + .getModel(); + + model.nodeChanged(findNode(tree, targetElement)); + attributePanel.updateOnDocumentChange(mevt.getType(), + targetElement); + } + }; + refreshGUI(runnable); + registerDocumentChange((MutationEvent) evt); + } + } + + /** + * Handles "DOMCharacterDataModified" event. + */ + protected class CharDataModificationHandler implements EventListener { + public void handleEvent(final Event evt) { + Runnable runnable = new Runnable() { + public void run() { + MutationEvent mevt = (MutationEvent) evt; + Node targetNode = (Node) mevt.getTarget(); + if (characterDataPanel.getNode() == targetNode) { + characterDataPanel.getTextArea().setText( + targetNode.getNodeValue()); + attributePanel.updateOnDocumentChange(mevt + .getType(), targetNode); + } + } + }; + refreshGUI(runnable); + if (characterDataPanel.getNode() == evt.getTarget()) { + registerDocumentChange((MutationEvent) evt); + } + } + } + + /** + * Checks whether the DOMViewer can be used to edit the document and if + * true refreshes the DOMViewer after the DOM Mutation event occured. + * + * @param runnable + * The runnable to invoke for refresh + */ + protected void refreshGUI(Runnable runnable) { + if (canEdit()) { + try { + SwingUtilities.invokeAndWait(runnable); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + } + + /** + * Adds the "DOMNodeInserted" Mutation event to current history + * browser's interface compound command + * + * @param mevt + * The Mutation Event + */ + protected void registerNodeInserted(MutationEvent mevt) { + Node targetNode = (Node) mevt.getTarget(); + historyBrowserInterface.addToCurrentCompoundCommand + (historyBrowserInterface.createNodeInsertedCommand + (targetNode.getParentNode(), + targetNode.getNextSibling(), + targetNode)); + } + + /** + * Adds the "DOMNodeRemoved" Mutation event to current history browser's + * interface compound command + * + * @param mevt + * The Mutation Event + */ + protected void registerNodeRemoved(MutationEvent mevt) { + Node targetNode = (Node) mevt.getTarget(); + historyBrowserInterface.addToCurrentCompoundCommand + (historyBrowserInterface.createNodeRemovedCommand + (mevt.getRelatedNode(), + targetNode.getNextSibling(), + targetNode)); + } + + /** + * Adds the "DOMAttrModified" Mutation event, of the + * MutationEvent.ADDITION type to current history browser's + * interface compound command + * + * @param mevt + * The Mutation Event + */ + protected void registerAttributeAdded(MutationEvent mevt) { + Element targetElement = (Element) mevt.getTarget(); + historyBrowserInterface.addToCurrentCompoundCommand + (historyBrowserInterface.createAttributeAddedCommand + (targetElement, + mevt.getAttrName(), + mevt.getNewValue(), + null)); + } + + /** + * Adds the "DOMAttrModified" Mutation event, of the + * MutationEvent.REMOVAL type to current history browser's + * interface compound command + * + * @param mevt + * The Mutation Event + */ + + protected void registerAttributeRemoved(MutationEvent mevt) { + Element targetElement = (Element) mevt.getTarget(); + historyBrowserInterface.addToCurrentCompoundCommand + (historyBrowserInterface.createAttributeRemovedCommand + (targetElement, + mevt.getAttrName(), + mevt.getPrevValue(), + null)); + } + + /** + * Adds the "DOMAttrModified" Mutation event, of the + * MutationEvent.MODIFICATION type to current history browser's + * interface compound command + * + * @param mevt + * The Mutation Event + */ + protected void registerAttributeModified(MutationEvent mevt) { + Element targetElement = (Element) mevt.getTarget(); + historyBrowserInterface.addToCurrentCompoundCommand + (historyBrowserInterface.createAttributeModifiedCommand + (targetElement, + mevt.getAttrName(), + mevt.getPrevValue(), + mevt.getNewValue(), + null)); + } + + /** + * Checks what type of the "DOMAttrModified" mutation event occured, and + * invokes the appropriate method to register the change. + * + * @param mevt + * The Mutation Event + */ + protected void registerAttributeChanged(MutationEvent mevt) { + switch (mevt.getAttrChange()) { + case MutationEvent.ADDITION: + registerAttributeAdded(mevt); + break; + case MutationEvent.REMOVAL: + registerAttributeRemoved(mevt); + break; + case MutationEvent.MODIFICATION: + registerAttributeModified(mevt); + break; + default: + registerAttributeModified(mevt); + break; + } + } + + /** + * Adds the "DOMCharDataModified" Mutation event to current history + * browser's interface compound command + * + * @param mevt + * The Mutation Event + */ + protected void registerCharDataModified(MutationEvent mevt) { + Node targetNode = (Node) mevt.getTarget(); + historyBrowserInterface.addToCurrentCompoundCommand + (historyBrowserInterface.createCharDataModifiedCommand + (targetNode, + mevt.getPrevValue(), + mevt.getNewValue())); + } + + /** + * Checks if the document change that occured should be registered. If + * the document change has occured out of the DOMViewer, the state of + * the history browser should be HistoryBrowserState.IDLE. Otherwise, if + * the DOMViewer caused the change, one of the following states is + * active: HistoryBrowserState.EXECUTING, HistoryBrowserState.UNDOING, + * HistoryBrowserState.REDOING. This method should be invoked while the + * document change is occuring (in mutation event handlers), otherwise, + * if put in another thread, the state flag becomes invalid. Also checks + * if the DOMViewer can be used to edit the document. If not, then the + * change shouldn't be registered by the HistoryBrowser + * + * @return True if the DOMViewer can edit the document and the history + * browser state is IDLE at the moment + */ + protected boolean shouldRegisterDocumentChange() { + return canEdit() && + historyBrowserInterface.getHistoryBrowser().getState() + == HistoryBrowser.IDLE; + } + + /** + * Puts the document change in the current history browser's interface + * compound command if the document change occured outside of the + * DOMViewer. + * + * @param mevt + * The info on the event. Use to describe the document change + * to the history browser + */ + protected void registerDocumentChange(MutationEvent mevt) { + if (shouldRegisterDocumentChange()) { + String type = mevt.getType(); + if (type.equals(NODE_INSERTED)) { + registerNodeInserted(mevt); + } else if (type.equals(NODE_REMOVED)) { + registerNodeRemoved(mevt); + } else if (type.equals(ATTRIBUTE_MODIFIED)) { + registerAttributeChanged(mevt); + } else if (type.equals(CHAR_DATA_MODIFIED)) { + registerCharDataModified(mevt); + } + } + } + + /** + * Handles the capturing "mouseclick" event. + */ + protected class CapturingClickHandler implements EventListener { + public void handleEvent(Event evt) { + if (isCapturingClickEnabled) { + Element targetElement = (Element) evt.getTarget(); + selectNode(targetElement); + } + } + } + + /** + * Creates a swing tree from a DOM document. + */ + protected MutableTreeNode createTree(Node node, + boolean showWhitespace) { + DefaultMutableTreeNode result; + result = new DefaultMutableTreeNode(new NodeInfo(node)); + for (Node n = node.getFirstChild(); + n != null; + n = n.getNextSibling()) { + if (!showWhitespace && (n instanceof org.w3c.dom.Text)) { + String txt = n.getNodeValue(); + if (txt.trim().length() == 0) + continue; + } + result.add(createTree(n, showWhitespace)); + } + if (node instanceof NodeXBL) { + Element shadowTree = ((NodeXBL) node).getXblShadowTree(); + if (shadowTree != null) { + DefaultMutableTreeNode shadowNode + = new DefaultMutableTreeNode + (new ShadowNodeInfo(shadowTree)); + shadowNode.add(createTree(shadowTree, showWhitespace)); + result.add(shadowNode); + } + } + if (node instanceof XBLOMContentElement) { + AbstractDocument doc + = (AbstractDocument) node.getOwnerDocument(); + XBLManager xm = doc.getXBLManager(); + if (xm instanceof DefaultXBLManager) { + DefaultMutableTreeNode selectedContentNode + = new DefaultMutableTreeNode(new ContentNodeInfo(node)); + DefaultXBLManager dxm = (DefaultXBLManager) xm; + ContentManager cm = dxm.getContentManager(node); + if (cm != null) { + NodeList nl + = cm.getSelectedContent((XBLOMContentElement) node); + for (int i = 0; i < nl.getLength(); i++) { + selectedContentNode.add(createTree(nl.item(i), + showWhitespace)); + } + result.add(selectedContentNode); + } + } + } + return result; + } + + /** + * Finds and returns the node in the tree that represents the given node + * in the document. + * + * @param theTree + * The given JTree + * @param node + * The given org.w3c.dom.Node + * @return Node or null if not found + */ + protected DefaultMutableTreeNode findNode(JTree theTree, Node node) { + DefaultMutableTreeNode root = (DefaultMutableTreeNode) theTree + .getModel().getRoot(); + Enumeration treeNodes = root.breadthFirstEnumeration(); + while (treeNodes.hasMoreElements()) { + DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) treeNodes + .nextElement(); + NodeInfo userObject = (NodeInfo) currentNode.getUserObject(); + if (userObject.getNode() == node) { + return currentNode; + } + } + return null; + } + + /** + * Finds and selects the given node in the document tree. + * + * @param targetNode + * The node to be selected + */ + public void selectNode(final Node targetNode) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + DefaultMutableTreeNode node = findNode(tree, targetNode); + if (node != null) { + TreeNode[] path = node.getPath(); + TreePath tp = new TreePath(path); + // Changes the selection + tree.setSelectionPath(tp); + // Expands and scrolls the TreePath to visible if + // needed + tree.scrollPathToVisible(tp); + } + } + }); + } + + /** + * Tree popup listener. + */ + protected class TreePopUpListener extends MouseAdapter { + + /** + * The actual pop-up menu. + */ + protected JPopupMenu treePopupMenu; + + /** + * Creates new pop up listener. + */ + public TreePopUpListener() { + treePopupMenu = new JPopupMenu(); + + // "Insert new node" menu + treePopupMenu.add(createTemplatesMenu(resources + .getString("ContextMenuItem.insertNewNode"))); + + // "Create new element..." item + JMenuItem item = new JMenuItem(resources + .getString("ContextMenuItem.createNewElement")); + treePopupMenu.add(item); + item.addActionListener(new TreeNodeAdder()); + + // "Remove selection" item + item = new JMenuItem(resources + .getString("ContextMenuItem.removeSelection")); + item.addActionListener(new TreeNodeRemover()); + treePopupMenu.add(item); + } + + public void mouseReleased(MouseEvent e) { + // Show the pop-up component + if (e.isPopupTrigger() && e.getClickCount() == 1) { + if (tree.getSelectionPaths() != null) { + showPopUp(e); + } + } + } + + // Handles selection on the tree + public void mousePressed(MouseEvent e) { + JTree sourceTree = (JTree) e.getSource(); + TreePath targetPath = sourceTree.getPathForLocation(e.getX(), e + .getY()); + if (!e.isControlDown() && !e.isShiftDown()) { + sourceTree.setSelectionPath(targetPath); + } else { + sourceTree.addSelectionPath(targetPath); + } + // Show the pop-up component + if (e.isPopupTrigger() && e.getClickCount() == 1) { + showPopUp(e); + } + } + + /** + * Shows this popup menu if the DOMViewer can be used to edti the + * document. + */ + private void showPopUp(MouseEvent e) { + if (canEdit()) { + TreePath path = tree.getPathForLocation(e.getX(), e.getY()); + // Don't show the pop up menu for the root element + if (path != null && path.getPathCount() > 1) { + treePopupMenu.show((Component) e.getSource(), e.getX(), + e.getY()); + } + } + } + } + + /** + * Handles tree pop-up menu action for adding new node. + */ + protected class TreeNodeAdder implements ActionListener { + + public void actionPerformed(ActionEvent e) { + // Prompt for the node name + NameEditorDialog nameEditorDialog = new NameEditorDialog( + DOMViewer.this); + nameEditorDialog.setLocationRelativeTo(DOMViewer.this); + int results = nameEditorDialog.showDialog(); + if (results == NameEditorDialog.OK_OPTION) { + Element elementToAdd = document.createElementNS( + SVGConstants.SVG_NAMESPACE_URI, nameEditorDialog + .getResults()); + if (rightPanel.getComponentCount() != 0) { + rightPanel.remove(0); + } + rightPanel.add(elementPanel); + + // Pass the parent node as the selected one + TreePath[] treePaths = tree.getSelectionPaths(); + if (treePaths != null) { + TreePath treePath = treePaths[treePaths.length - 1]; + DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath + .getLastPathComponent(); + NodeInfo nodeInfo = (NodeInfo) node.getUserObject(); + // Enter the attributePanel 'add new element' mode + attributePanel.enterAddNewElementMode(elementToAdd, + nodeInfo.getNode()); + } + } + } + } + + /** + * Parser for the Element template. + */ + protected class NodeTemplateParser implements ActionListener { + + /** + * The string to parse. + */ + protected String toParse; + + /** + * The node type. + */ + protected short nodeType; + + /** + * Constructor. + * + * @param toParse + * The string to parse + */ + public NodeTemplateParser(String toParse, short nodeType) { + this.toParse = toParse; + this.nodeType = nodeType; + } + + public void actionPerformed(ActionEvent e) { + Node nodeToAdd = null; + switch (nodeType) { + case Node.ELEMENT_NODE: + URL urlObj = null; + if (document instanceof SVGOMDocument) { + urlObj = ((SVGOMDocument) document).getURLObject(); + } + String uri = (urlObj == null) ? "" : urlObj.toString(); + Map prefixes = new HashMap(); + prefixes.put(SVGConstants.XMLNS_PREFIX, + SVGConstants.SVG_NAMESPACE_URI); + prefixes.put(SVGConstants.XMLNS_PREFIX + ":" + + SVGConstants.XLINK_PREFIX, + SVGConstants.XLINK_NAMESPACE_URI); + SAXDocumentFactory df = new SAXDocumentFactory(document + .getImplementation(), XMLResourceDescriptor + .getXMLParserClassName()); + DocumentFragment documentFragment = (DocumentFragment) DOMUtilities + .parseXML(toParse, document, uri, prefixes, + SVGConstants.SVG_SVG_TAG, df); + nodeToAdd = documentFragment.getFirstChild(); + break; + case Node.TEXT_NODE: + nodeToAdd = document.createTextNode(toParse); + break; + case Node.COMMENT_NODE: + nodeToAdd = document.createComment(toParse); + break; + case Node.CDATA_SECTION_NODE: + nodeToAdd = document.createCDATASection(toParse); + } + + // Append the new node to the parentNode + TreePath[] treePaths = tree.getSelectionPaths(); + if (treePaths != null) { + TreePath treePath = treePaths[treePaths.length - 1]; + DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath + .getLastPathComponent(); + NodeInfo nodeInfo = (NodeInfo) node.getUserObject(); + + addChangesToHistory(); + + historyBrowserInterface.appendChild(nodeInfo.getNode(), + nodeToAdd); + } + } + } + + /** + * Creates JMenu menu using {@link NodeTemplates}. + * + * @param name + * The name of the submenu + * @return The JMenu submenu + */ + protected JMenu createTemplatesMenu(String name) { + NodeTemplates templates = new NodeTemplates(); + JMenu submenu = new JMenu(name); + + // Create submenus + HashMap menuMap = new HashMap(); + ArrayList categoriesList = templates.getCategories(); + int n = categoriesList.size(); + for (int i = 0; i < n; i++) { + String category = categoriesList.get(i).toString(); + JMenu currentMenu = new JMenu(category); + submenu.add(currentMenu); + // Add submenus to the map + menuMap.put(category, currentMenu); + } + + // Sort the value list and then iterate through node templates + ArrayList values = + new ArrayList(templates.getNodeTemplatesMap().values()); + Collections.sort(values, new Comparator() { + public int compare(Object o1, Object o2) { + NodeTemplateDescriptor n1 = (NodeTemplateDescriptor) o1; + NodeTemplateDescriptor n2 = (NodeTemplateDescriptor) o2; + return n1.getName().compareTo(n2.getName()); + } + }); + Iterator iter = values.iterator(); + while (iter.hasNext()) { + NodeTemplateDescriptor desc = + (NodeTemplateDescriptor) iter .next(); + String toParse = desc.getXmlValue(); + short nodeType = desc.getType(); + String nodeCategory = desc.getCategory(); + JMenuItem currentItem = new JMenuItem(desc.getName()); + currentItem.addActionListener + (new NodeTemplateParser(toParse, nodeType)); + JMenu currentSubmenu = (JMenu)menuMap.get(nodeCategory); + currentSubmenu.add(currentItem); + } + return submenu; + } + + /** + * Handles tree pop-up menu action for removing nodes. + */ + protected class TreeNodeRemover implements ActionListener { + + public void actionPerformed(ActionEvent e) { + addChangesToHistory(); + + AbstractCompoundCommand cmd = historyBrowserInterface + .createRemoveSelectedTreeNodesCommand(null); + TreePath[] treePaths = tree.getSelectionPaths(); + for (int i = 0; treePaths != null && i < treePaths.length; i++) { + TreePath treePath = treePaths[i]; + DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath + .getLastPathComponent(); + NodeInfo nodeInfo = (NodeInfo) node.getUserObject(); + if (DOMUtilities.isParentOf(nodeInfo.getNode(), + nodeInfo.getNode().getParentNode())) { + cmd.addCommand(historyBrowserInterface + .createRemoveChildCommand(nodeInfo.getNode() + .getParentNode(), nodeInfo.getNode())); + } + } + historyBrowserInterface.performCompoundUpdateCommand(cmd); + } + } + + /** + * To listen to the tree selection. + */ + protected class DOMTreeSelectionListener + implements TreeSelectionListener { + + /** + * Called when the selection changes. + */ + public void valueChanged(TreeSelectionEvent ev) { + // Manages the selection overlay + if (elementOverlayManager != null) { + handleElementSelection(ev); + } + + DefaultMutableTreeNode mtn; + mtn = (DefaultMutableTreeNode) + tree.getLastSelectedPathComponent(); + + if (mtn == null) { + return; + } + + if (rightPanel.getComponentCount() != 0) { + rightPanel.remove(0); + } + + Object nodeInfo = mtn.getUserObject(); + if (nodeInfo instanceof NodeInfo) { + Node node = ((NodeInfo) nodeInfo).getNode(); + switch (node.getNodeType()) { + case Node.DOCUMENT_NODE: + documentInfo.setText + (createDocumentText((Document) node)); + rightPanel.add(documentInfoPanel); + break; + case Node.ELEMENT_NODE: + propertiesTable.setModel(new NodeCSSValuesModel(node)); + attributePanel.promptForChanges(); + attributePanel.setPreviewElement((Element) node); + rightPanel.add(elementPanel); + break; + case Node.COMMENT_NODE: + case Node.TEXT_NODE: + case Node.CDATA_SECTION_NODE: + characterDataPanel.setNode(node); + characterDataPanel.getTextArea().setText + (node.getNodeValue()); + rightPanel.add(characterDataPanel); + } + } + + splitPane.revalidate(); + splitPane.repaint(); + } + + protected String createDocumentText(Document doc) { + StringBuffer sb = new StringBuffer(); + sb.append("Nodes: "); + sb.append(nodeCount(doc)); + return sb.toString(); + } + + protected int nodeCount(Node node) { + int result = 1; + for (Node n = node.getFirstChild(); + n != null; + n = n.getNextSibling()) { + result += nodeCount(n); + } + return result; + } + + /** + * Processes element selection overlay. + * + * @param ev + * Tree selection event + */ + protected void handleElementSelection(TreeSelectionEvent ev) { + TreePath[] paths = ev.getPaths(); + for (int i = 0; i < paths.length; i++) { + TreePath path = paths[i]; + DefaultMutableTreeNode mtn = + (DefaultMutableTreeNode) path.getLastPathComponent(); + Object nodeInfo = mtn.getUserObject(); + if (nodeInfo instanceof NodeInfo) { + Node node = ((NodeInfo) nodeInfo).getNode(); + if (node.getNodeType() == Node.ELEMENT_NODE) { + if (ev.isAddedPath(path)) { + elementOverlayManager.addElement + ((Element) node); + } else { + elementOverlayManager.removeElement + ((Element) node); + } + } + } + } + elementOverlayManager.repaint(); + } + } + + /** + * To render the tree nodes. + */ + protected class NodeRenderer extends DefaultTreeCellRenderer { + + /** + * The icon used to represent elements. + */ + protected ImageIcon elementIcon; + + /** + * The icon used to represent comments. + */ + protected ImageIcon commentIcon; + + /** + * The icon used to represent processing instructions. + */ + protected ImageIcon piIcon; + + /** + * The icon used to represent text. + */ + protected ImageIcon textIcon; + + /** + * Creates a new NodeRenderer object. + */ + public NodeRenderer() { + String s; + s = resources.getString("Element.icon"); + elementIcon = new ImageIcon(getClass().getResource(s)); + s = resources.getString("Comment.icon"); + commentIcon = new ImageIcon(getClass().getResource(s)); + s = resources.getString("PI.icon"); + piIcon = new ImageIcon(getClass().getResource(s)); + s = resources.getString("Text.icon"); + textIcon = new ImageIcon(getClass().getResource(s)); + } + + /** + * Sets the value of the current tree cell. + */ + public Component getTreeCellRendererComponent(JTree tree, + Object value, + boolean sel, + boolean expanded, + boolean leaf, + int row, + boolean hasFocus) { + super.getTreeCellRendererComponent(tree, value, sel, expanded, + leaf, row, hasFocus); + switch (getNodeType(value)) { + case Node.ELEMENT_NODE: + setIcon(elementIcon); + break; + case Node.COMMENT_NODE: + setIcon(commentIcon); + break; + case Node.PROCESSING_INSTRUCTION_NODE: + setIcon(piIcon); + break; + case Node.TEXT_NODE: + case Node.CDATA_SECTION_NODE: + setIcon(textIcon); + break; + } + return this; + } + + /** + * Returns the DOM type of the given object. + * @return the type or -1. + */ + protected short getNodeType(Object value) { + DefaultMutableTreeNode mtn = (DefaultMutableTreeNode)value; + Object obj = mtn.getUserObject(); + if (obj instanceof NodeInfo) { + Node node = ((NodeInfo)obj).getNode(); + return node.getNodeType(); + } + return -1; + } + } + + /** + * To display the CSS properties of a DOM node in a table. + */ + protected class NodeCSSValuesModel extends AbstractTableModel { + + /** + * The node. + */ + protected Node node; + + /** + * The computed style. + */ + protected CSSStyleDeclaration style; + + /** + * The property names. + */ + protected List propertyNames; + + /** + * Creates a new NodeAttributesModel object. + */ + public NodeCSSValuesModel(Node n) { + node = n; + if (viewCSS != null) { + style = viewCSS.getComputedStyle((Element)n, null); + propertyNames = new ArrayList(); + if (style != null) { + for (int i = 0; i < style.getLength(); i++) { + propertyNames.add(style.item(i)); + } + Collections.sort(propertyNames); + } + } + } + + /** + * Returns the name to give to a column. + */ + public String getColumnName(int col) { + if (col == 0) { + return resources.getString("CSSValuesTable.column1"); + } else { + return resources.getString("CSSValuesTable.column2"); + } + } + + /** + * Returns the number of columns in the table. + */ + public int getColumnCount() { + return 2; + } + + /** + * Returns the number of rows in the table. + */ + public int getRowCount() { + if (style == null) { + return 0; + } + return style.getLength(); + } + + /** + * Whether the given cell is editable. + */ + public boolean isCellEditable(int row, int col) { + return false; + } + + /** + * Returns the value of the given cell. + */ + public Object getValueAt(int row, int col) { + String prop = (String)propertyNames.get(row); + if (col == 0) { + return prop; + } else { + return style.getPropertyValue(prop); + } + } + } + + } // class Panel + + /** + * To store the nodes informations + */ + protected static class NodeInfo { + /** + * The DOM node. + */ + protected Node node; + + /** + * Creates a new NodeInfo object. + */ + public NodeInfo(Node n) { + node = n; + } + + /** + * Returns the DOM Node associated with this node info. + */ + public Node getNode() { + return node; + } + + /** + * Returns a printable representation of the object. + */ + public String toString() { + if (node instanceof Element) { + Element e = (Element) node; + String id = e.getAttribute(SVGConstants.SVG_ID_ATTRIBUTE); + if (id.length() != 0) { + return node.getNodeName() + " \"" + id + "\""; + } + } + return node.getNodeName(); + } + } + + /** + * To store the node information for a shadow tree. + */ + protected static class ShadowNodeInfo extends NodeInfo { + + /** + * Creates a new ShadowNodeInfo object. + */ + public ShadowNodeInfo(Node n) { + super(n); + } + + /** + * Returns a printable representation of the object. + */ + public String toString() { + return "shadow tree"; + } + } + + /** + * To store the node information for an xbl:content node's + * selected content. + */ + protected static class ContentNodeInfo extends NodeInfo { + + /** + * Creates a new ContentNodeInfo object. + */ + public ContentNodeInfo(Node n) { + super(n); + } + + /** + * Returns a printable representation of the object. + */ + public String toString() { + return "selected content"; + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DOMViewerController.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DOMViewerController.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DOMViewerController.java 8 Apr 2013 10:55:07 -0000 1.1 @@ -0,0 +1,78 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import org.apache.batik.swing.gvt.Overlay; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +/** + * Provides the information needed for the DOMViewer to show and edit the + * document. + * + * @version $Id: DOMViewerController.java,v 1.1 2013/04/08 10:55:07 marcin Exp $ + */ +public interface DOMViewerController { + + /** + * Performs the document update. + * + * @param r The runnable that contains the update + */ + void performUpdate(Runnable r); + + /** + * Creates the ElementSelectionManager to manage the selection overlay on + * the canvas. + * + * @return ElementSelectionManager + */ + ElementOverlayManager createSelectionManager(); + + /** + * Removes the given selection overlay from the canvas. + * + * @param selectionOverlay + * The given selection overlay + */ + void removeSelectionOverlay(Overlay selectionOverlay); + + /** + * Gets the document for the DOMViewer to show. + * + * @return the document + */ + Document getDocument(); + + /** + * Selects the given node in the DOMViewer's document tree. + * + * @param node + * The node to select + */ + void selectNode(Node node); + + /** + * Checks whether the DOMViewer should be allowed to edit the document. + * + * @return True for non static documents, when UpdateManager is available + */ + boolean canEdit(); +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DropDownHistoryModel.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DropDownHistoryModel.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/DropDownHistoryModel.java 8 Apr 2013 10:55:09 -0000 1.1 @@ -0,0 +1,395 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.util.ArrayList; +import java.util.Locale; +import java.util.ResourceBundle; + +import org.apache.batik.util.gui.DropDownComponent.DefaultScrollablePopupMenuItem; +import org.apache.batik.util.gui.DropDownComponent.ScrollablePopupMenu; +import org.apache.batik.util.gui.DropDownComponent.ScrollablePopupMenuEvent; +import org.apache.batik.util.gui.DropDownComponent.ScrollablePopupMenuItem; +import org.apache.batik.util.gui.DropDownComponent.ScrollablePopupMenuModel; +import org.apache.batik.apps.svgbrowser.HistoryBrowser.CommandNamesInfo; +import org.apache.batik.apps.svgbrowser.HistoryBrowser.HistoryBrowserAdapter; +import org.apache.batik.apps.svgbrowser.HistoryBrowser.HistoryBrowserEvent; +import org.apache.batik.util.resources.ResourceManager; + +/** + * The history scrollable popup menu model. Used for undo / redo drop down + * components. + * + * @version $Id: DropDownHistoryModel.java,v 1.1 2013/04/08 10:55:09 marcin Exp $ + */ +public class DropDownHistoryModel implements ScrollablePopupMenuModel { + + /** + * The resource file name. + */ + private static final String RESOURCES = + "org.apache.batik.apps.svgbrowser.resources.DropDownHistoryModelMessages"; + + /** + * The resource bundle. + */ + private static ResourceBundle bundle; + + /** + * The resource manager. + */ + private static ResourceManager resources; + static { + bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault()); + resources = new ResourceManager(bundle); + } + + /** + * Scrollable popup menu items. + */ + protected ArrayList items = new ArrayList(); + + /** + * The history browser interface. + */ + protected HistoryBrowserInterface historyBrowserInterface; + + /** + * The parent scrollable popup menu. + */ + protected ScrollablePopupMenu parent; + + /** + * Creates the history pop up menu model. + * + * @param parent + * The parent ScrollablePopupMenu + * @param historyBrowserInterface + * The historyBrowserInterface. Used to update the parent pop + * up menu when the HistoryBrowser fires the events + */ + public DropDownHistoryModel(ScrollablePopupMenu parent, + HistoryBrowserInterface historyBrowserInterface) { + this.parent = parent; + this.historyBrowserInterface = historyBrowserInterface; + + // Handle the history reset event + historyBrowserInterface.getHistoryBrowser().addListener + (new HistoryBrowserAdapter() { + public void historyReset(HistoryBrowserEvent event) { + clearAllScrollablePopupMenuItems(""); + } + }); + } + + /** + * Gets the footer text. + * + * @return footer text + */ + public String getFooterText() { + return ""; + } + + /** + * Creates the ScrollablePopupMenuItem with the specific name. + * + * @param itemName + * the name of the item + * @return the item + */ + public ScrollablePopupMenuItem createItem(String itemName) { + return new DefaultScrollablePopupMenuItem(parent, itemName); + } + + /** + * Adds the ScrollablePopupMenuItem to the item list and to the parent. + * Fires the event 'itemsWereAdded' on the parent pop up menu + * + * @param item + * The item to add + * @param details + * The details for the 'itemsWereAdded' event + */ + protected void addItem(ScrollablePopupMenuItem item, String details) { + int oldSize = items.size(); + items.add(0, item); + parent.add(item, 0, oldSize, items.size()); + parent.fireItemsWereAdded + (new ScrollablePopupMenuEvent(parent, + ScrollablePopupMenuEvent.ITEMS_ADDED, + 1, + details)); + } + + /** + * Removes the ScrollablePopupMenuItem from the item list and from the + * parent. Fires the event 'itemsWereRemoved' on the parent pop up menu + * + * @param item + * The item to remove + * @param details + * The details for the 'itemsWereRemoved' event + */ + protected void removeItem(ScrollablePopupMenuItem item, String details) { + int oldSize = items.size(); + items.remove(item); + parent.remove(item, oldSize, items.size()); + parent.fireItemsWereRemoved + (new ScrollablePopupMenuEvent(parent, + ScrollablePopupMenuEvent.ITEMS_REMOVED, + 1, + details)); + } + + /** + * Removes the last scrollable popup menu item from the items list and + * from the parent pop up menu. + * + * @param details + * The details for the 'itemsWereRemoved' event + * @return True if item was successfully removed + */ + protected boolean removeLastScrollablePopupMenuItem(String details) { + for (int i = items.size() - 1; i >= 0; i--) { + ScrollablePopupMenuItem item = + (ScrollablePopupMenuItem) items.get(i); + removeItem(item, details); + return true; + } + return false; + } + + /** + * Removes the first scrollable popup menu item from the items list and + * from the parent pop up menu. + * + * @param details + * The details for the 'itemsWereRemoved' event + * @return True if item was successfully removed + */ + protected boolean removeFirstScrollablePopupMenuItem(String details) { + for (int i = 0; i < items.size(); i++) { + ScrollablePopupMenuItem item = + (ScrollablePopupMenuItem) items.get(i); + removeItem(item, details); + return true; + } + return false; + } + + /** + * Removes all scrollable popup menu items from the items list and from + * the parent pop up menu. + * + * @param details + * The details for the event + */ + protected void clearAllScrollablePopupMenuItems(String details) { + while (removeLastScrollablePopupMenuItem(details)) { + } + } + + /** + * Processes click on the pop up menu item. + */ + public void processItemClicked() { + } + + public void processBeforeShowed() { + // Performs current command from the history browser + historyBrowserInterface.performCurrentCompoundCommand(); + } + + public void processAfterShowed() { + } + + /** + * The undo pop up menu model. + */ + public static class UndoPopUpMenuModel extends DropDownHistoryModel { + + /** + * The undo footer text. Used for the footer item. + */ + protected static String UNDO_FOOTER_TEXT = + resources.getString("UndoModel.footerText"); + + /** + * The prefix for the last undoable command. E.g. (Undo change + * selection) + */ + protected static String UNDO_TOOLTIP_PREFIX = + resources.getString("UndoModel.tooltipPrefix"); + + /** + * Creates the unod pop up menu model + * + * @param parent + * The parent scrollable popup menu + * @param historyBrowserInterface + * the historyBrowserInterface + */ + public UndoPopUpMenuModel + (ScrollablePopupMenu parent, + HistoryBrowserInterface historyBrowserInterface) { + + super(parent, historyBrowserInterface); + init(); + } + + /** + * Initializes this model. Adds the listeners to the history browser. + */ + private void init() { + historyBrowserInterface.getHistoryBrowser().addListener + (new HistoryBrowserAdapter() { + public void executePerformed(HistoryBrowserEvent event) { + CommandNamesInfo info = + (CommandNamesInfo) event.getSource(); + String details = UNDO_TOOLTIP_PREFIX + + info.getLastUndoableCommandName(); + addItem(createItem(info.getCommandName()), details); + } + + public void undoPerformed(HistoryBrowserEvent event) { + CommandNamesInfo info = + (CommandNamesInfo) event.getSource(); + String details = UNDO_TOOLTIP_PREFIX + + info.getLastUndoableCommandName(); + removeFirstScrollablePopupMenuItem(details); + } + + public void redoPerformed(HistoryBrowserEvent event) { + CommandNamesInfo info = + (CommandNamesInfo) event.getSource(); + String details = UNDO_TOOLTIP_PREFIX + + info.getLastUndoableCommandName(); + addItem(createItem(info.getCommandName()), details); + } + + public void doCompoundEdit(HistoryBrowserEvent event) { + if (!parent.isEnabled()) { + parent.setEnabled(true); + } + } + + public void compoundEditPerformed + (HistoryBrowserEvent event) { + } + }); + } + + public String getFooterText() { + return UNDO_FOOTER_TEXT; + } + + public void processItemClicked() { + historyBrowserInterface.getHistoryBrowser().compoundUndo + (parent.getSelectedItemsCount()); + } + } + + /** + * The redo pop up menu model. + */ + public static class RedoPopUpMenuModel extends DropDownHistoryModel { + + /** + * The redo footer text. Used for the footer item. + */ + protected static String REDO_FOOTER_TEXT = + resources.getString("RedoModel.footerText"); + + /** + * The prefix for the last redoable command. E.g. (Redo change + * selection) + */ + protected static String REDO_TOOLTIP_PREFIX = + resources.getString("RedoModel.tooltipPrefix"); + + /** + * Creates the redo pop up menu model + * + * @param parent + * The parent scrollable popup menu + * @param historyBrowserInterface + * the historyBrowserInterface + */ + public RedoPopUpMenuModel + (ScrollablePopupMenu parent, + HistoryBrowserInterface historyBrowserInterface) { + + super(parent, historyBrowserInterface); + init(); + } + + /** + * Initializes this model. Adds the listeners to the history browser. + */ + private void init() { + historyBrowserInterface.getHistoryBrowser().addListener + (new HistoryBrowserAdapter() { + + public void executePerformed(HistoryBrowserEvent event) { + CommandNamesInfo info = + (CommandNamesInfo) event.getSource(); + String details = REDO_TOOLTIP_PREFIX + + info.getLastRedoableCommandName(); + clearAllScrollablePopupMenuItems(details); + } + + public void undoPerformed(HistoryBrowserEvent event) { + CommandNamesInfo info = + (CommandNamesInfo) event.getSource(); + String details = REDO_TOOLTIP_PREFIX + + info.getLastRedoableCommandName(); + addItem(createItem(info.getCommandName()), details); + } + + public void redoPerformed(HistoryBrowserEvent event) { + CommandNamesInfo info = + (CommandNamesInfo) event.getSource(); + String details = REDO_TOOLTIP_PREFIX + + info.getLastRedoableCommandName(); + removeFirstScrollablePopupMenuItem(details); + } + + public void doCompoundEdit(HistoryBrowserEvent event) { + if (parent.isEnabled()) { + parent.setEnabled(false); + } + } + + public void compoundEditPerformed + (HistoryBrowserEvent event) { + } + }); + } + + public String getFooterText() { + return REDO_FOOTER_TEXT; + } + + public void processItemClicked() { + historyBrowserInterface.getHistoryBrowser().compoundRedo + (parent.getSelectedItemsCount()); + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/ElementOverlayController.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/ElementOverlayController.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/ElementOverlayController.java 8 Apr 2013 10:55:07 -0000 1.1 @@ -0,0 +1,32 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +/** + * Provides the information to control the ElementOverlay. + * + * @version $Id: ElementOverlayController.java,v 1.1 2013/04/08 10:55:07 marcin Exp $ + */ +public interface ElementOverlayController { + + /** + * Returns whether the ElementOverlay is enabled. + */ + boolean isOverlayEnabled(); +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/ElementOverlayManager.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/ElementOverlayManager.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/ElementOverlayManager.java 8 Apr 2013 10:55:08 -0000 1.1 @@ -0,0 +1,346 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.util.ArrayList; + +import org.apache.batik.gvt.GraphicsNode; +import org.apache.batik.swing.JSVGCanvas; +import org.apache.batik.swing.gvt.Overlay; + +import org.w3c.dom.Element; + +/** + * Manages element overlay on the canvas. + * + * @version $Id: ElementOverlayManager.java,v 1.1 2013/04/08 10:55:08 marcin Exp $ + */ +public class ElementOverlayManager { + + /** + * The color of the outline of the element overlay. + */ + protected Color elementOverlayStrokeColor = Color.black; + + /** + * The color of the element overlay. + */ + protected Color elementOverlayColor = Color.white; + + /** + * The xor mode. + */ + protected boolean xorMode = true; + + /** + * The canvas. + */ + protected JSVGCanvas canvas; + + /** + * The element overlay. + */ + protected Overlay elementOverlay = new ElementOverlay(); + + /** + * Elements to paint. + */ + protected ArrayList elements; + + /** + * The controller for the element overlay. + */ + protected ElementOverlayController controller; + + /** + * Whether the ElementOverlay is enabled. + */ + protected boolean isOverlayEnabled = true; + + /** + * Constructor. + * + * @param canvas + * The parent canvas + */ + public ElementOverlayManager(JSVGCanvas canvas) { + this.canvas = canvas; + elements = new ArrayList(); + canvas.getOverlays().add(elementOverlay); + } + + /** + * Adds an element to the element selection. + * + * @param elem + * The element to add + */ + public void addElement(Element elem) { + elements.add(elem); + } + + /** + * Removes the element from the element selection and adds its bound to the + * 'dirty' region. + * + * @param elem + * The element to remove + */ + public void removeElement(Element elem) { + if (elements.remove(elem)) { +// // Gets the area that should be repainted +// Rectangle currentElementBounds = getElementBounds(elem); +// if (dirtyArea == null) { +// dirtyArea = currentElementBounds; +// } else if (currentElementBounds != null) { +// dirtyArea.add(currentElementBounds); +// } + } + } + + /** + * Removes all elements from the element selection list. + */ + public void removeElements() { + elements.clear(); + repaint(); + } + + /** + * Get the current selection bounds. + * + * @return the current selection bounds + */ + protected Rectangle getAllElementsBounds() { + Rectangle resultBound = null; + int n = elements.size(); + for (int i = 0; i < n; i++) { + Element currentElement = (Element) elements.get(i); + Rectangle currentBound = getElementBounds(currentElement); + if (resultBound == null) { + resultBound = currentBound; + } else { + resultBound.add(currentBound); + } + } + return resultBound; + } + + /** + * The bounds of a given element. + * + * @param elem + * The given element + * @return Rectangle bounds + */ + protected Rectangle getElementBounds(Element elem) { + return getElementBounds(canvas.getUpdateManager().getBridgeContext() + .getGraphicsNode(elem)); + } + + /** + * The bounds of a given graphics node. + * + * @param node + * The given graphics node + * @return the bounds + */ + protected Rectangle getElementBounds(GraphicsNode node) { + if (node == null) { + return null; + } + AffineTransform at = canvas.getRenderingTransform(); + Shape s = at.createTransformedShape(node.getOutline()); + return outset(s.getBounds(), 1); + } + + /** + * Increases the given rectangle area for a given amount of units in a + * rectangle increasement manner. + * + * @param r + * The given rectangle + * @param amount + * The given amount of units + * @return r + */ + protected Rectangle outset(Rectangle r, int amount) { + r.x -= amount; + r.y -= amount; + r.width += 2 * amount; + r.height += 2 * amount; + return r; + } + + /** + * Repaints the canvas. + */ + public void repaint() { + canvas.repaint(); + } + + /** + * The element overlay. + */ + public class ElementOverlay implements Overlay { + + /** + * Paints this overlay. + */ + public void paint(Graphics g) { + if (controller.isOverlayEnabled() && isOverlayEnabled()) { + int n = elements.size(); + for (int i = 0; i < n; i++) { + Element currentElement = (Element) elements.get(i); + GraphicsNode nodeToPaint = canvas.getUpdateManager() + .getBridgeContext().getGraphicsNode(currentElement); + if (nodeToPaint != null) { + AffineTransform elementsAt = + nodeToPaint.getGlobalTransform(); + Shape selectionHighlight = nodeToPaint.getOutline(); + AffineTransform at = canvas.getRenderingTransform(); + at.concatenate(elementsAt); + Shape s = at.createTransformedShape(selectionHighlight); + if (s == null) { + break; + } + Graphics2D g2d = (Graphics2D) g; + if (xorMode) { + g2d.setColor(Color.black); + g2d.setXORMode(Color.yellow); + g2d.fill(s); + g2d.draw(s); + } else { + g2d.setColor(elementOverlayColor); + g2d.setStroke(new BasicStroke(1.8f)); + g2d.setColor(elementOverlayStrokeColor); + g2d.draw(s); + } + } + } + } + } + } + + /** + * Gets the elementOverlayColor. + * + * @return the elementOverlayColor + */ + public Color getElementOverlayColor() { + return elementOverlayColor; + } + + /** + * Sets the color to use for the element overlay. + * + * @param selectionOverlayColor The new element overlay color. + */ + public void setElementOverlayColor(Color selectionOverlayColor) { + this.elementOverlayColor = selectionOverlayColor; + } + + /** + * Gets the elementOverlayStrokeColor. + * + * @return the elementOverlayStrokeColor + */ + public Color getElementOverlayStrokeColor() { + return elementOverlayStrokeColor; + } + + /** + * Sets the color to use for stroking the element overlay. + * + * @param selectionOverlayStrokeColor + * The new element overlay stroking color. + */ + public void setElementOverlayStrokeColor + (Color selectionOverlayStrokeColor) { + this.elementOverlayStrokeColor = selectionOverlayStrokeColor; + } + + /** + * Gets the xorMode. + * + * @return the xorMode + */ + public boolean isXorMode() { + return xorMode; + } + + /** + * Sets the xor mode. + * + * @param xorMode + * the xorMode to set + */ + public void setXorMode(boolean xorMode) { + this.xorMode = xorMode; + } + + /** + * Gets the elementOverlay. + * + * @return the elementOverlay + */ + public Overlay getElementOverlay() { + return elementOverlay; + } + + /** + * Removes the elementOverlay. + */ + public void removeOverlay() { + canvas.getOverlays().remove(elementOverlay); + } + + /** + * Sets the element overlay controller. + * + * @param controller + * The element overlay controller + */ + public void setController(ElementOverlayController controller) { + this.controller = controller; + } + + /** + * If the element overlay is enabled. + * + * @return isOverlayEnabled + */ + public boolean isOverlayEnabled() { + return isOverlayEnabled; + } + + /** + * Enables / disables the Element overlay. + */ + public void setOverlayEnabled(boolean isOverlayEnabled) { + this.isOverlayEnabled = isOverlayEnabled; + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/FindDialog.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/FindDialog.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/FindDialog.java 8 Apr 2013 10:55:09 -0000 1.1 @@ -0,0 +1,452 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.awt.Shape; +import java.awt.event.ActionEvent; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.text.AttributedCharacterIterator; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JTextField; + +import org.apache.batik.gvt.GVTTreeWalker; +import org.apache.batik.gvt.GraphicsNode; +import org.apache.batik.gvt.TextNode; +import org.apache.batik.gvt.text.Mark; +import org.apache.batik.swing.JSVGCanvas; +import org.apache.batik.util.resources.ResourceManager; +import org.apache.batik.util.gui.ExtendedGridBagConstraints; +import org.apache.batik.util.gui.resource.ActionMap; +import org.apache.batik.util.gui.resource.ButtonFactory; +import org.apache.batik.util.gui.resource.MissingListenerException; + +/** + * This class represents a Dialog that lets the user searching for text inside + * an SVG document. + * + * @author Thierry Kormann + * @version $Id: FindDialog.java,v 1.1 2013/04/08 10:55:09 marcin Exp $ + */ +public class FindDialog extends JDialog implements ActionMap { + + /** + * The resource file name + */ + protected static final String RESOURCES = + "org.apache.batik.apps.svgbrowser.resources.FindDialog"; + + // action names + public static final String FIND_ACTION = "FindButtonAction"; + + public static final String CLEAR_ACTION = "ClearButtonAction"; + + public static final String CLOSE_ACTION = "CloseButtonAction"; + + /** + * The resource bundle + */ + protected static ResourceBundle bundle; + + /** + * The resource manager + */ + protected static ResourceManager resources; + + static { + bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault()); + resources = new ResourceManager(bundle); + } + + /** The button factory */ + protected ButtonFactory buttonFactory; + + /** The GVT root into which text is searched. */ + protected GraphicsNode gvtRoot; + + /** The GVTTreeWalker used to scan the GVT Tree. */ + protected GVTTreeWalker walker; + + /** The current index in the TextNode's string. */ + protected int currentIndex; + + /** The TextField that owns the text to search. */ + protected JTextField search; + + /** The next button. */ + protected JButton findButton; + + /** The next button. */ + protected JButton clearButton; + + /** The cancel button. */ + protected JButton closeButton; + + /** The case sensitive button. */ + protected JCheckBox caseSensitive; + + /** The canvas. */ + protected JSVGCanvas svgCanvas; + + /** The highlight button. */ + protected JRadioButton highlightButton; + + /** The highlight and center button. */ + protected JRadioButton highlightCenterButton; + + /** The highlight center and zoom button. */ + protected JRadioButton highlightCenterZoomButton; + /** + * Constructs a new FindDialog. + */ + public FindDialog(JSVGCanvas svgCanvas) { + this(null, svgCanvas); + } + + /** + * Constructs a new FindDialog. + */ + public FindDialog(Frame owner, JSVGCanvas svgCanvas) { + super(owner, resources.getString("Dialog.title")); + this.svgCanvas = svgCanvas; + + buttonFactory = new ButtonFactory(bundle, this); + + listeners.put(FIND_ACTION, + new FindButtonAction()); + + listeners.put(CLEAR_ACTION, + new ClearButtonAction()); + + listeners.put(CLOSE_ACTION, + new CloseButtonAction()); + + JPanel p = new JPanel(new BorderLayout()); + p.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); + p.add(createFindPanel(), BorderLayout.CENTER); + p.add(createShowResultPanel(), BorderLayout.SOUTH); + + getContentPane().add(p, BorderLayout.CENTER); + getContentPane().add(createButtonsPanel(), BorderLayout.SOUTH); + } + + /** + * Creates the Find panel. + */ + protected JPanel createFindPanel() { + JPanel panel = new JPanel(new GridBagLayout()); + + panel.setBorder(BorderFactory.createTitledBorder + (BorderFactory.createEtchedBorder(), + resources.getString("Panel.title"))); + + ExtendedGridBagConstraints gbc = new ExtendedGridBagConstraints(); + gbc.insets = new Insets(2, 2, 2, 2); + + gbc.anchor = ExtendedGridBagConstraints.EAST; + gbc.fill = ExtendedGridBagConstraints.NONE; + gbc.setWeight(0, 0); + gbc.setGridBounds(0, 0, 1, 1); + panel.add(new JLabel(resources.getString("FindLabel.text")), gbc); + + gbc.fill = ExtendedGridBagConstraints.HORIZONTAL; + gbc.setWeight(1.0, 0); + gbc.setGridBounds(1, 0, 2, 1); + panel.add(search = new JTextField(20), gbc); + + gbc.fill = ExtendedGridBagConstraints.NONE; + gbc.anchor = ExtendedGridBagConstraints.WEST; + gbc.setWeight(0, 0); + gbc.setGridBounds(1, 1, 1, 1); + caseSensitive = buttonFactory.createJCheckBox("CaseSensitiveCheckBox"); + panel.add(caseSensitive, gbc); + + return panel; + } + + protected JPanel createShowResultPanel() { + JPanel panel = new JPanel(new GridBagLayout()); + + panel.setBorder(BorderFactory.createTitledBorder + (BorderFactory.createEtchedBorder(), + resources.getString("ShowResultPanel.title"))); + + ExtendedGridBagConstraints gbc = new ExtendedGridBagConstraints(); + gbc.insets = new Insets(2, 2, 2, 2); + + gbc.anchor = ExtendedGridBagConstraints.WEST; + gbc.fill = ExtendedGridBagConstraints.NONE; + gbc.setWeight(0, 0); + + ButtonGroup grp = new ButtonGroup(); + + highlightButton = buttonFactory.createJRadioButton("Highlight"); + highlightButton.setSelected(true); + grp.add(highlightButton); + gbc.setGridBounds(0, 0, 1, 1); + panel.add(highlightButton, gbc); + + highlightCenterButton = + buttonFactory.createJRadioButton("HighlightAndCenter"); + grp.add(highlightCenterButton); + gbc.setGridBounds(0, 1, 1, 1); + panel.add(highlightCenterButton, gbc); + + highlightCenterZoomButton = + buttonFactory.createJRadioButton("HighlightCenterAndZoom"); + grp.add(highlightCenterZoomButton); + gbc.setGridBounds(0, 2, 1, 1); + panel.add(highlightCenterZoomButton, gbc); + + return panel; + } + + /** + * Creates the buttons panel + */ + protected JPanel createButtonsPanel() { + JPanel panel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); + panel.add(findButton = buttonFactory.createJButton("FindButton")); + panel.add(clearButton = buttonFactory.createJButton("ClearButton")); + panel.add(closeButton = buttonFactory.createJButton("CloseButton")); + return panel; + } + + + /** + * Sets the graphics node into which text is searched. + * @param gvtRoot the GVT root node + */ + public void setGraphicsNode(GraphicsNode gvtRoot) { + this.gvtRoot = gvtRoot; + if (gvtRoot != null) { + this.walker = new GVTTreeWalker(gvtRoot); + } else { + this.walker = null; + } + } + + /** + * Returns the next GraphicsNode that matches the specified string or null + * if any. + * + * @param text the text to match + */ + protected GraphicsNode getNext(String text) { + if (walker == null && gvtRoot != null) { + walker = new GVTTreeWalker(gvtRoot); + } + GraphicsNode gn = walker.getCurrentGraphicsNode(); + int index = match(gn, text, currentIndex+text.length()); + if (index >= 0) { + currentIndex = index; + } else { + currentIndex = 0; + gn = walker.nextGraphicsNode(); + while (gn != null && + ((currentIndex = match(gn, text, currentIndex)) < 0)) { + currentIndex = 0; + gn = walker.nextGraphicsNode(); + } + } + return gn; + } + + /** + * Returns the index inside the specified TextNode of the + * specified text, or -1 if not found. + * + * @param node the graphics node to check + * @param text the text use to match + * @param index the index from which to start */ + protected int match(GraphicsNode node, String text, int index) { + if (!(node instanceof TextNode) + || !node.isVisible() + || text == null || text.length() == 0) { + return -1; + } + String s = ((TextNode)node).getText(); + if (!caseSensitive.isSelected()) { + s = s.toLowerCase(); + text = text.toLowerCase(); + } + return s.indexOf(text, index); + } + + /** + * Shows the current selected TextNode. + */ + protected void showSelectedGraphicsNode() { + GraphicsNode gn = walker.getCurrentGraphicsNode(); + if (!(gn instanceof TextNode)) { + return; + } + TextNode textNode = (TextNode)gn; + // mark the selection of the substring found + String text = textNode.getText(); + String pattern = search.getText(); + if (!caseSensitive.isSelected()) { + text = text.toLowerCase(); + pattern = pattern.toLowerCase(); + } + int end = text.indexOf(pattern, currentIndex); + + AttributedCharacterIterator aci = + textNode.getAttributedCharacterIterator(); + aci.first(); + for (int i=0; i < end; ++i) { + aci.next(); + } + Mark startMark = textNode.getMarkerForChar(aci.getIndex(), true); + + for (int i = 0; i < pattern.length()-1; ++i) { + aci.next(); + } + Mark endMark = textNode.getMarkerForChar(aci.getIndex(), false); + svgCanvas.select(startMark, endMark); + + // zoom on the TextNode if needed + if (highlightButton.isSelected()) { + return; + } + + // get the highlight shape in GVT root (global) coordinate sytem + Shape s = textNode.getHighlightShape(); + AffineTransform at; + if (highlightCenterZoomButton.isSelected()) { + at = svgCanvas.getInitialTransform(); + } else { + at = svgCanvas.getRenderingTransform(); + } + // get the bounds of the highlight shape in the canvas coordinate system + Rectangle2D gnb = at.createTransformedShape(s).getBounds(); + + Dimension canvasSize = svgCanvas.getSize(); + // translate the highlight region to (0, 0) in the canvas coordinate + // system + AffineTransform Tx = AffineTransform.getTranslateInstance + (-gnb.getX()-gnb.getWidth()/2, + -gnb.getY()-gnb.getHeight()/2); + + if (highlightCenterZoomButton.isSelected()) { + // zoom on the highlight shape such as the shape takes x% of the + // canvas size + double sx = canvasSize.width/gnb.getWidth(); + double sy = canvasSize.height/gnb.getHeight(); + double scale = Math.min(sx, sy) / 8; + if (scale > 1) { + Tx.preConcatenate + (AffineTransform.getScaleInstance(scale, scale)); + } + } + Tx.preConcatenate(AffineTransform.getTranslateInstance + (canvasSize.width/2, canvasSize.height/2)); + // take into account the initial transform + AffineTransform newRT = new AffineTransform(at); + newRT.preConcatenate(Tx); + // change the rendering transform + svgCanvas.setRenderingTransform(newRT); + } + + // ActionMap implementation + + /** + * The map that contains the listeners + */ + protected Map listeners = new HashMap(10); + + /** + * Returns the action associated with the given string + * or null on error + * @param key the key mapped with the action to get + * @throws MissingListenerException if the action is not found + */ + public Action getAction(String key) throws MissingListenerException { + return (Action)listeners.get(key); + } + + ////////////////////////////////////////////////////////////////////////// + // Action implementation + ////////////////////////////////////////////////////////////////////////// + + /** + * The action associated to the 'find' button. + */ + protected class FindButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + String text = search.getText(); + if (text == null || text.length() == 0) { + return; + } + GraphicsNode gn = getNext(text); + if (gn != null) { + showSelectedGraphicsNode(); + } else { + // end of document reached + walker = null; + JOptionPane.showMessageDialog(FindDialog.this, + resources.getString("End.text"), + resources.getString("End.title"), + JOptionPane.INFORMATION_MESSAGE); + } + } + } + + /** + * The action associated to the 'clear' button. + */ + protected class ClearButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + search.setText(null); + walker = null; + } + } + + /** + * The action associated to the 'close' button. + */ + protected class CloseButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + dispose(); + } + } +} + + Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/HistoryBrowser.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/HistoryBrowser.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/HistoryBrowser.java 8 Apr 2013 10:55:08 -0000 1.1 @@ -0,0 +1,624 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.util.ArrayList; +import java.util.EventListener; +import java.util.EventObject; + +import javax.swing.event.EventListenerList; + +/** + * History browser. Manages perform of execute, undo and redo actions. + */ +public class HistoryBrowser { + + // The history browser states. Show whether the history browser is busy + // performing execute, undo or redo, or whether is idle. + /** + * The history browser is executing the command(s). + */ + public static final int EXECUTING = 1; + + /** + * The history browser is undoing the command(s). + */ + public static final int UNDOING = 2; + + /** + * The history browser is redoing the command(s). + */ + public static final int REDOING = 3; + + /** + * The history browser is in idle state - no command is being executed, + * undone or redone. + */ + public static final int IDLE = 4; + + /** + * Listeners list. + */ + protected EventListenerList eventListeners = + new EventListenerList(); + + /** + * Command history. + */ + protected ArrayList history; + + /** + * Current command pointer in history array. + */ + protected int currentCommandIndex = -1; + + /** + * History size. + */ + protected int historySize = 1000; + + /** + * The current state of the history browser. + */ + protected int state = IDLE; + + /** + * Tells the history browser how to execute, undo and redo the commands. + * Wraps the execute, undo and redo methods + */ + protected CommandController commandController; + + /** + * Constructor. + */ + public HistoryBrowser(CommandController commandController) { + this.history = new ArrayList(); + this.commandController = commandController; + } + + /** + * Constructor. + * @param historySize History size + */ + public HistoryBrowser(int historySize) { + this.history = new ArrayList(); + setHistorySize(historySize); + } + + /** + * Setter for the history size. + * + * @param size + * New history size + */ + protected void setHistorySize(int size) { + historySize = size; + } + + /** + * Sets the commandController. + * + * @param newCommandController + * The newCommandController to set + */ + public void setCommandController(CommandController newCommandController) { + this.commandController = newCommandController; + } + + /** + * Adds the given command to history array and executes it. + * + * @param command + * The given command + */ + public void addCommand(UndoableCommand command) { + // When the command is added to history array, the commands from the + // current position to the end of the list are removed from history + int n = history.size(); + for (int i = n - 1; i > currentCommandIndex; i--) { + history.remove(i); + } + // Executes the command + if (commandController != null) { + commandController.execute(command); + } else { + state = EXECUTING; + command.execute(); + state = IDLE; + } + // Adds it to the history array + history.add(command); + + // Updates the pointer to the current command + currentCommandIndex = history.size() - 1; + if (currentCommandIndex >= historySize) { + history.remove(0); + currentCommandIndex--; + } + fireExecutePerformed(new HistoryBrowserEvent(new CommandNamesInfo( + command.getName(), getLastUndoableCommandName(), + getLastRedoableCommandName()))); + } + + /** + * Undoes the last executed or 'redone' command. + */ + public void undo() { + // If history is empty, or the current command index is out of bounds + if (history.isEmpty() || currentCommandIndex < 0) { + return; + } + // Gets the command and performs undo + UndoableCommand command = (UndoableCommand) history + .get(currentCommandIndex); + if (commandController != null) { + commandController.undo(command); + } else { + state = UNDOING; + command.undo(); + state = IDLE; + } + // Updates the current command index + currentCommandIndex--; + fireUndoPerformed(new HistoryBrowserEvent(new CommandNamesInfo(command + .getName(), getLastUndoableCommandName(), + getLastRedoableCommandName()))); + } + + /** + * Redoes the last 'undone' command. + */ + public void redo() { + // If history is empty, or the current command index is out of bounds + if (history.isEmpty() || currentCommandIndex == history.size() - 1) { + return; + } + // Increases the current command index and redoes the command + UndoableCommand command = (UndoableCommand) history + .get(++currentCommandIndex); + if (commandController != null) { + commandController.redo(command); + } else { + state = REDOING; + command.redo(); + state = IDLE; + } + fireRedoPerformed(new HistoryBrowserEvent(new CommandNamesInfo(command + .getName(), getLastUndoableCommandName(), + getLastRedoableCommandName()))); + } + + /** + * Performs undo action the given number of times. + * + * @param undoNumber + * The given number of undo actions to perform + */ + public void compoundUndo(int undoNumber) { + for (int i = 0; i < undoNumber; i++) { + undo(); + } + } + + /** + * Performs redo action the given number of times. + * + * @param redoNumber + * The given number of redo actions to perform + */ + public void compoundRedo(int redoNumber) { + for (int i = 0; i < redoNumber; i++) { + redo(); + } + } + + /** + * Gets the last undoable command name. + * + * @return String or "" if there's no any + */ + public String getLastUndoableCommandName() { + if (history.isEmpty() || currentCommandIndex < 0) { + return ""; + } + return ((UndoableCommand) history.get(currentCommandIndex)).getName(); + } + + /** + * Gets the last redoable command name. + * + * @return String or "" if there's no any + */ + public String getLastRedoableCommandName() { + if (history.isEmpty() || currentCommandIndex == history.size() - 1) { + return ""; + } + return ((UndoableCommand) history.get(currentCommandIndex + 1)) + .getName(); + } + + /** + * Clears the history array. + */ + public void resetHistory() { + history.clear(); + currentCommandIndex = -1; + fireHistoryReset(new HistoryBrowserEvent(new Object())); + } + + /** + * Gets the state of this history browser. + * + * @return the state + */ + public int getState() { + if (commandController != null) { + return commandController.getState(); + } else { + return state; + } + } + + // Custom event support + + /** + * Event to pass to listener. + */ + public static class HistoryBrowserEvent extends EventObject { + + /** + * @param source + */ + public HistoryBrowserEvent(Object source) { + super(source); + } + } + + /** + * The HistoryBrowserListener. + */ + public static interface HistoryBrowserListener extends EventListener { + + /** + * The command has been executed. + */ + void executePerformed(HistoryBrowserEvent event); + + /** + * The undo has been performed on the command. + */ + void undoPerformed(HistoryBrowserEvent event); + + /** + * The redo has been performed on the command. + */ + void redoPerformed(HistoryBrowserEvent event); + + /** + * History has been reset, and all commands have been removed from the + * history. + */ + void historyReset(HistoryBrowserEvent event); + + /** + * The the atom command that should be wrapped with the compound command + * has been executed. + */ + void doCompoundEdit(HistoryBrowserEvent event); + + /** + * The compound command has been made from the atom commands that were + * executed and should be wrapped. + */ + void compoundEditPerformed(HistoryBrowserEvent event); + } + + /** + * The adapter to provide the default behavior. + */ + public static class HistoryBrowserAdapter implements HistoryBrowserListener { + + public void executePerformed(HistoryBrowserEvent event) { + } + + public void undoPerformed(HistoryBrowserEvent event) { + } + + public void redoPerformed(HistoryBrowserEvent event) { + } + + public void historyReset(HistoryBrowserEvent event) { + } + + public void compoundEditPerformed(HistoryBrowserEvent event) { + } + + public void doCompoundEdit(HistoryBrowserEvent event) { + } + } + + /** + * Adds the listener to the listener list. + * + * @param listener + * The listener to add + */ + public void addListener(HistoryBrowserListener listener) { + eventListeners.add(HistoryBrowserListener.class, listener); + } + + /** + * Fires the executePerformed event. + * + * @param event + * The associated HistoryBrowserEvent event + */ + public void fireExecutePerformed(HistoryBrowserEvent event) { + Object[] listeners = eventListeners.getListenerList(); + int length = listeners.length; + for (int i = 0; i < length; i += 2) { + if (listeners[i] == HistoryBrowserListener.class) { + ((HistoryBrowserListener) listeners[i + 1]) + .executePerformed(event); + } + } + } + + /** + * Fires the undoPerformed event. + * + * @param event + * The associated HistoryBrowserEvent event + */ + public void fireUndoPerformed(HistoryBrowserEvent event) { + Object[] listeners = eventListeners.getListenerList(); + int length = listeners.length; + for (int i = 0; i < length; i += 2) { + if (listeners[i] == HistoryBrowserListener.class) { + ((HistoryBrowserListener) listeners[i + 1]) + .undoPerformed(event); + } + } + } + + /** + * Fires the redoPerformed event. + * + * @param event + * The associated HistoryBrowserEvent event + */ + public void fireRedoPerformed(HistoryBrowserEvent event) { + Object[] listeners = eventListeners.getListenerList(); + int length = listeners.length; + for (int i = 0; i < length; i += 2) { + if (listeners[i] == HistoryBrowserListener.class) { + ((HistoryBrowserListener) listeners[i + 1]) + .redoPerformed(event); + } + } + } + + /** + * Fires the historyReset event. + * + * @param event + * The associated HistoryBrowserEvent event + */ + public void fireHistoryReset(HistoryBrowserEvent event) { + Object[] listeners = eventListeners.getListenerList(); + int length = listeners.length; + for (int i = 0; i < length; i += 2) { + if (listeners[i] == HistoryBrowserListener.class) { + ((HistoryBrowserListener) listeners[i + 1]) + .historyReset(event); + } + } + } + + /** + * Fires the doCompoundEdit event. + * + * @param event + * The associated HistoryBrowserEvent event + */ + public void fireDoCompoundEdit(HistoryBrowserEvent event) { + Object[] listeners = eventListeners.getListenerList(); + int length = listeners.length; + for (int i = 0; i < length; i += 2) { + if (listeners[i] == HistoryBrowserListener.class) { + ((HistoryBrowserListener) listeners[i + 1]) + .doCompoundEdit(event); + } + } + } + + /** + * Fires the compoundEditPerformed event. + * + * @param event + * The associated HistoryBrowserEvent event + */ + public void fireCompoundEditPerformed(HistoryBrowserEvent event) { + Object[] listeners = eventListeners.getListenerList(); + int length = listeners.length; + for (int i = 0; i < length; i += 2) { + if (listeners[i] == HistoryBrowserListener.class) { + ((HistoryBrowserListener) listeners[i + 1]) + .compoundEditPerformed(event); + } + } + } + + /** + * Contains the info on the command name being executed, undone or redone and + * last undoable and redoable command names. + */ + public static class CommandNamesInfo { + + /** + * The name of the last undoable command in the history. + */ + private String lastUndoableCommandName; + + /** + * The name of the last redoable command in the history. + */ + private String lastRedoableCommandName; + + /** + * The command name being executed, undone or redone. + */ + private String commandName; + + /** + * Constructor. + * + * @param commandName + * The current command name being executed/undone/redone + * @param lastUndoableCommandName + * The last undoable command name + * @param lastRedoableCommandName + * The last redoable command name + */ + public CommandNamesInfo(String commandName, + String lastUndoableCommandName, + String lastRedoableCommandName) { + this.lastUndoableCommandName = lastUndoableCommandName; + this.lastRedoableCommandName = lastRedoableCommandName; + this.commandName = commandName; + } + + /** + * Gets the name of the last undoable command. + * + * @return the lastUndoableCommandName + */ + public String getLastRedoableCommandName() { + return lastRedoableCommandName; + } + + /** + * Gets the name of the last redoable command. + * + * @return the lastRedoableCommandName + */ + public String getLastUndoableCommandName() { + return lastUndoableCommandName; + } + + /** + * Gets the command name. + * + * @return the command name + */ + public String getCommandName() { + return commandName; + } + } + + /** + * Wrapps the command's execute, undo and redo methods. + */ + public static interface CommandController { + + /** + * Wrapps the execute method. + */ + void execute(UndoableCommand command); + + /** + * Wrapps the undo method. + */ + void undo(UndoableCommand command); + + /** + * Wrapps the redo method. + */ + void redo(UndoableCommand command); + + /** + * Gets the state of the command controller. + * @return HistoryBrowserState + */ + int getState(); + } + + /** + * Lets the DOMViewerController wrap the commands. + */ + public static class DocumentCommandController implements CommandController { + + /** + * The DOMViewerController. + */ + protected DOMViewerController controller; + + /** + * The current state of the command controller. + */ + protected int state = HistoryBrowser.IDLE; + + /** + * The constructor. + * + * @param controller + * The DOMViewerController + */ + public DocumentCommandController(DOMViewerController controller) { + this.controller = controller; + } + + public void execute(final UndoableCommand command) { + Runnable r = new Runnable() { + public void run() { + state = HistoryBrowser.EXECUTING; + command.execute(); + state = HistoryBrowser.IDLE; + } + }; + controller.performUpdate(r); + } + + public void undo(final UndoableCommand command) { + Runnable r = new Runnable() { + public void run() { + state = HistoryBrowser.UNDOING; + command.undo(); + state = HistoryBrowser.IDLE; + } + }; + controller.performUpdate(r); + } + + public void redo(final UndoableCommand command) { + Runnable r = new Runnable() { + public void run() { + state = HistoryBrowser.REDOING; + command.redo(); + state = HistoryBrowser.IDLE; + } + }; + controller.performUpdate(r); + } + + public int getState() { + return state; + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/HistoryBrowserInterface.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/HistoryBrowserInterface.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/HistoryBrowserInterface.java 8 Apr 2013 10:55:07 -0000 1.1 @@ -0,0 +1,1427 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.util.ArrayList; + +import org.apache.batik.apps.svgbrowser.HistoryBrowser.CommandController; +import org.apache.batik.apps.svgbrowser.HistoryBrowser.HistoryBrowserEvent; +import org.apache.batik.dom.util.DOMUtilities; +import org.apache.batik.util.SVGConstants; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * The wrapper for the history browser. The commands for the historyBrowser + * are implemented here + * + * @version $Id: HistoryBrowserInterface.java,v 1.1 2013/04/08 10:55:07 marcin Exp $ + */ +public class HistoryBrowserInterface { + + // ATOM COMMANDS + private static final String ATTRIBUTE_ADDED_COMMAND = "Attribute added: "; + + private static final String ATTRIBUTE_REMOVED_COMMAND = "Attribute removed: "; + + private static final String ATTRIBUTE_MODIFIED_COMMAND = "Attribute modified: "; + + private static final String NODE_INSERTED_COMMAND = "Node inserted: "; + + private static final String NODE_REMOVED_COMMAND = "Node removed: "; + + private static final String CHAR_DATA_MODIFIED_COMMAND = "Node value changed: "; + + // OTHER COMMANDS + /** + * The changes being performed outside of the DOMViewer. + */ + private static final String OUTER_EDIT_COMMAND = "Document changed outside DOM Viewer"; + + /** + * Compound tree node dropped command name. + */ + private static final String COMPOUND_TREE_NODE_DROP = "Node moved"; + + /** + * Remove selected nodes command name. + */ + private static final String REMOVE_SELECTED_NODES = "Nodes removed"; + + /** + * The history browser. + */ + protected HistoryBrowser historyBrowser; + + /** + * Used to group custom number of changes into a single command. + */ + protected AbstractCompoundCommand currentCompoundCommand; + + /** + * Constructor. Creates the history browser. + */ + public HistoryBrowserInterface(CommandController commandController) { + historyBrowser = new HistoryBrowser(commandController); + } + + /** + * Sets the history browser's command controller. + * + * @param newCommandController + * The commandController to set + */ + public void setCommmandController(CommandController newCommandController) { + historyBrowser.setCommandController(newCommandController); + } + + /** + * Creates the compound update command, that consists of custom number of + * commands. + * + * @param commandName + * Compound command name + * @return CompoundUpdateCommand + */ + public CompoundUpdateCommand + createCompoundUpdateCommand(String commandName) { + CompoundUpdateCommand cmd = new CompoundUpdateCommand(commandName); + return cmd; + } + + /** + * Creates the compound NodeChangedCommand. Used to create the 'dynamic' + * NodeChangedCommand name + * + * @return the CompoundUpdateCommand + */ + public CompoundUpdateCommand createNodeChangedCommand(Node node) { + return new CompoundUpdateCommand(getNodeChangedCommandName(node)); + } + + /** + * Creates the compound NodesDroppedCommand. Used to create the 'dynamic' + * NodesDroppedCommand name + * + * @param nodes + * The list of the nodes that are being dropped + * @return the CompoundUpdateCommand + */ + public CompoundUpdateCommand createNodesDroppedCommand(ArrayList nodes) { + return new CompoundUpdateCommand(COMPOUND_TREE_NODE_DROP); + } + + /** + * Creates the compound RemoveSelectedTreeNodesCommand. Used to create the + * 'dynamic' RemoveSelectedTreeNodesCommand name + * + * @param nodes + * The list of the nodes that are selected and should be removed + * @return the RemoveSelectedTreeNodesCommand + */ + public CompoundUpdateCommand + createRemoveSelectedTreeNodesCommand(ArrayList nodes) { + return new CompoundUpdateCommand(REMOVE_SELECTED_NODES); + } + + /** + * Executes the given compound update command. + * + * @param command + * The given compound update command + */ + public void performCompoundUpdateCommand(UndoableCommand command) { + historyBrowser.addCommand(command); + } + + /** + * The compound command. + */ + public static class CompoundUpdateCommand extends AbstractCompoundCommand { + + /** + * Constructor. + * + * @param commandName + * The compound command name + */ + public CompoundUpdateCommand(String commandName) { + setName(commandName); + } + } + + /** + * Gets the history browser. + * + * @return the historyBrowser + */ + public HistoryBrowser getHistoryBrowser() { + return historyBrowser; + } + + + // ATOM COMMANDS + + /** + * Adds the NodeInsertedCommand to historyBrowser. + * + * @param newParent + * New parent node + * @param newSibling + * New (next) sibling node + * @param contextNode + * The node to be appended + */ + public void nodeInserted(Node newParent, Node newSibling, Node contextNode) { + historyBrowser.addCommand(createNodeInsertedCommand(newParent, + newSibling, contextNode)); + } + + /** + * Creates the NodeInserted command. + * + * @param newParent + * New parent node + * @param newSibling + * New (next) sibling node + * @param contextNode + * The node to be appended + */ + public NodeInsertedCommand createNodeInsertedCommand(Node newParent, + Node newSibling, + Node contextNode) { + return new NodeInsertedCommand + (NODE_INSERTED_COMMAND + getBracketedNodeName(contextNode), + newParent, newSibling, contextNode); + } + + /** + * Inserts the given node as a child of another. + */ + public static class NodeInsertedCommand extends AbstractUndoableCommand { + + /** + * The node's next sibling. + */ + protected Node newSibling; + + /** + * The node's new parent. + */ + protected Node newParent; + + /** + * The node to be appended. + */ + protected Node contextNode; + + /** + * Constructor. + */ + public NodeInsertedCommand(String commandName, Node parent, + Node sibling, Node contextNode) { + setName(commandName); + this.newParent = parent; + this.contextNode = contextNode; + this.newSibling = sibling; + } + + public void execute() { + } + + public void undo() { + newParent.removeChild(contextNode); + } + + public void redo() { + if (newSibling != null) { + newParent.insertBefore(contextNode, newSibling); + } else { + newParent.appendChild(contextNode); + } + } + + public boolean shouldExecute() { + if (newParent == null || contextNode == null) { + return false; + } + return true; + } + } + + /** + * Adds the NodeRemovedCommand to historyBrowser. + * + * @param oldParent + * The node's old parent + * @param oldSibling + * The node's old next sibling + * @param contextNode + * The node to be removed + */ + public void nodeRemoved(Node oldParent, Node oldSibling, Node contextNode) { + historyBrowser.addCommand + (createNodeRemovedCommand(oldParent, oldSibling, contextNode)); + } + + /** + * Creates the NodeRemoved command. + * + * @param oldParent + * The node's old parent + * @param oldSibling + * The node's old next sibling + * @param contextNode + * The node to be removed + */ + public NodeRemovedCommand createNodeRemovedCommand(Node oldParent, + Node oldSibling, + Node contextNode) { + return new NodeRemovedCommand + (NODE_REMOVED_COMMAND + getBracketedNodeName(contextNode), + oldParent, oldSibling, contextNode); + } + + /** + * Removes the node from its parent node. + */ + public static class NodeRemovedCommand extends AbstractUndoableCommand { + + /** + * The node's old sibling. + */ + protected Node oldSibling; + + /** + * The node's new parent. + */ + protected Node oldParent; + + /** + * The node to be appended. + */ + protected Node contextNode; + + /** + * Constructor. + */ + public NodeRemovedCommand(String commandName, Node oldParent, + Node oldSibling, Node contextNode) { + setName(commandName); + this.oldParent = oldParent; + this.contextNode = contextNode; + this.oldSibling = oldSibling; + } + + public void execute() { + } + + public void undo() { + if (oldSibling != null) { + oldParent.insertBefore(contextNode, oldSibling); + } else { + oldParent.appendChild(contextNode); + } + } + + public void redo() { + oldParent.removeChild(contextNode); + } + + public boolean shouldExecute() { + if (oldParent == null || contextNode == null) { + return false; + } + return true; + } + } + + /** + * Adds the AttributeAddedCommand to historyBrowser. + * + * @param contextElement + * The context element + * @param attributeName + * The attribute name + * @param newAttributeValue + * The attribute value + * @param namespaceURI + * The namespaceURI + */ + public void attributeAdded(Element contextElement, String attributeName, + String newAttributeValue, String namespaceURI) { + historyBrowser.addCommand + (createAttributeAddedCommand(contextElement, attributeName, + newAttributeValue, namespaceURI)); + } + + /** + * Creates the AttributeAdded command. + * + * @param contextElement + * The context element + * @param attributeName + * The attribute name + * @param newAttributeValue + * The attribute value + * @param namespaceURI + * The namespaceURI + */ + public AttributeAddedCommand + createAttributeAddedCommand(Element contextElement, + String attributeName, + String newAttributeValue, + String namespaceURI) { + return new AttributeAddedCommand + (ATTRIBUTE_ADDED_COMMAND + getBracketedNodeName(contextElement), + contextElement, attributeName, newAttributeValue, namespaceURI); + } + + /** + * Adds the attribute to an element (MutationEvent.ADDITION) + */ + public static class AttributeAddedCommand extends AbstractUndoableCommand { + + /** + * The context element. + */ + protected Element contextElement; + + /** + * The attribute name. + */ + protected String attributeName; + + /** + * The attribute value. + */ + protected String newValue; + + /** + * The namespaceURI. + */ + protected String namespaceURI; + + /** + * Constructor. + * + * @param commandName + * The name of this command. + * @param contextElement + * The context element + * @param attributeName + * The attribute name + * @param newAttributeValue + * The attribute value + * @param namespaceURI + * The namespaceURI + */ + public AttributeAddedCommand(String commandName, + Element contextElement, + String attributeName, + String newAttributeValue, + String namespaceURI) { + setName(commandName); + this.contextElement = contextElement; + this.attributeName = attributeName; + this.newValue = newAttributeValue; + this.namespaceURI = namespaceURI; + } + + public void execute() { + } + + public void undo() { + contextElement.removeAttributeNS(namespaceURI, attributeName); + } + + public void redo() { + contextElement.setAttributeNS + (namespaceURI, attributeName, newValue); + } + + public boolean shouldExecute() { + if (contextElement == null || attributeName.length() == 0) { + return false; + } + return true; + } + } + + /** + * Adds the AttributeRemovedCommand to historyBrowser. + * + * @param contextElement + * The context element + * @param attributeName + * The attribute name + * @param prevAttributeValue + * The previous attribute value + * @param namespaceURI + * The namespaceURI + */ + public void attributeRemoved(Element contextElement, + String attributeName, + String prevAttributeValue, + String namespaceURI) { + historyBrowser.addCommand + (createAttributeRemovedCommand(contextElement, attributeName, + prevAttributeValue, namespaceURI)); + } + + /** + * Creates the AttributeRemoved command. + * + * @param contextElement + * The context element + * @param attributeName + * The attribute name + * @param prevAttributeValue + * The previous attribute value + * @param namespaceURI + * The namespaceURI + */ + public AttributeRemovedCommand + createAttributeRemovedCommand(Element contextElement, + String attributeName, + String prevAttributeValue, + String namespaceURI) { + return new AttributeRemovedCommand + (ATTRIBUTE_REMOVED_COMMAND + getBracketedNodeName(contextElement), + contextElement, attributeName, prevAttributeValue, namespaceURI); + } + + /** + * Removes the attribute of an element (MutationEvent.REMOVAL) + */ + public static class AttributeRemovedCommand extends AbstractUndoableCommand { + + /** + * The context element. + */ + protected Element contextElement; + + /** + * The attribute name. + */ + protected String attributeName; + + /** + * The previous attribute value. + */ + protected String prevValue; + + /** + * The namespaceURI. + */ + protected String namespaceURI; + + /** + * Constructor. + * + * @param commandName + * The name of this command. + * @param contextElement + * The context element + * @param attributeName + * The attribute name + * @param prevAttributeValue + * The previous attribute value + * @param namespaceURI + * The namespaceURI + */ + public AttributeRemovedCommand(String commandName, + Element contextElement, + String attributeName, + String prevAttributeValue, + String namespaceURI) { + setName(commandName); + this.contextElement = contextElement; + this.attributeName = attributeName; + this.prevValue = prevAttributeValue; + this.namespaceURI = namespaceURI; + } + + public void execute() { + } + + public void undo() { + contextElement.setAttributeNS + (namespaceURI, attributeName, prevValue); + } + + public void redo() { + contextElement.removeAttributeNS(namespaceURI, attributeName); + } + + public boolean shouldExecute() { + if (contextElement == null || attributeName.length() == 0) { + return false; + } + return true; + } + } + + /** + * Adds the AttributeModifiedCommand to historyBrowser. + * + * @param contextElement + * The context element + * @param attributeName + * The attribute name + * @param prevAttributeValue + * The previous attribute value + * @param newAttributeValue + * The new attribute value + * @param namespaceURI + * The namespaceURI + */ + public void attributeModified(Element contextElement, + String attributeName, + String prevAttributeValue, + String newAttributeValue, + String namespaceURI) { + historyBrowser.addCommand + (createAttributeModifiedCommand(contextElement, attributeName, + prevAttributeValue, + newAttributeValue, namespaceURI)); + } + + /** + * Creates the AttributeModified command. + * + * @param contextElement + * The context element + * @param attributeName + * The attribute name + * @param prevAttributeValue + * The previous attribute value + * @param newAttributeValue + * The new attribute value + * @param namespaceURI + * The namespaceURI + */ + public AttributeModifiedCommand + createAttributeModifiedCommand(Element contextElement, + String attributeName, + String prevAttributeValue, + String newAttributeValue, + String namespaceURI) { + return new AttributeModifiedCommand + (ATTRIBUTE_MODIFIED_COMMAND + getBracketedNodeName(contextElement), + contextElement, attributeName, prevAttributeValue, + newAttributeValue, namespaceURI); + } + + /** + * Modifies the attribute of an element (MutationEvent.MODIFICATION) + */ + public static class AttributeModifiedCommand extends AbstractUndoableCommand { + + /** + * The context element. + */ + protected Element contextElement; + + /** + * The attribute name. + */ + protected String attributeName; + + /** + * Previous attribute value. + */ + protected String prevAttributeValue; + + /** + * New attribute value. + */ + protected String newAttributeValue; + + /** + * The namespaceURI. + */ + protected String namespaceURI; + + /** + * Constructor. + * + * @param commandName + * The name of this command. + * @param contextElement + * The context element + * @param attributeName + * The attribute name + * @param prevAttributeValue + * The previous attribute value + * @param newAttributeValue + * The new attribute value + * @param namespaceURI + * The namespaceURI + */ + public AttributeModifiedCommand(String commandName, + Element contextElement, + String attributeName, + String prevAttributeValue, + String newAttributeValue, + String namespaceURI) { + setName(commandName); + this.contextElement = contextElement; + this.attributeName = attributeName; + this.prevAttributeValue = prevAttributeValue; + this.newAttributeValue = newAttributeValue; + this.namespaceURI = namespaceURI; + } + + public void execute() { + } + + public void undo() { + contextElement.setAttributeNS + (namespaceURI, attributeName, prevAttributeValue); + } + + public void redo() { + contextElement.setAttributeNS + (namespaceURI, attributeName, newAttributeValue); + } + + public boolean shouldExecute() { + if (contextElement == null || attributeName.length() == 0) { + return false; + } + return true; + } + } + + /** + * Adds CharDataModifiedCommand to historyBrowser. + * + * @param contextNode + * The node whose nodeValue changed + * @param oldValue + * The old node value + * @param newValue + * The new node value + */ + public void charDataModified(Node contextNode, String oldValue, + String newValue) { + historyBrowser.addCommand + (createCharDataModifiedCommand(contextNode, oldValue, newValue)); + } + + /** + * Creates the CharDataModified command. + * + * @param contextNode + * The node whose nodeValue changed + * @param oldValue + * The old node value + * @param newValue + * The new node value + */ + public CharDataModifiedCommand + createCharDataModifiedCommand(Node contextNode, + String oldValue, + String newValue) { + return new CharDataModifiedCommand + (CHAR_DATA_MODIFIED_COMMAND + getBracketedNodeName(contextNode), + contextNode, oldValue, newValue); + } + + /** + * Sets the node value. + */ + public static class CharDataModifiedCommand extends AbstractUndoableCommand { + + /** + * The node whose value changed. + */ + protected Node contextNode; + + /** + * Old node value. + */ + protected String oldValue; + + /** + * New node value. + */ + protected String newValue; + + /** + * Constructor. + * + * @param commandName + * The command name + * @param contextNode + * Context node + * @param oldValue + * Old node value + * @param newValue + * New node value + */ + public CharDataModifiedCommand(String commandName, Node contextNode, + String oldValue, String newValue) { + setName(commandName); + this.contextNode = contextNode; + this.oldValue = oldValue; + this.newValue = newValue; + } + + public void execute() { + } + + public void undo() { + contextNode.setNodeValue(oldValue); + } + + public void redo() { + contextNode.setNodeValue(newValue); + } + + public boolean shouldExecute() { + if (contextNode == null) { + return false; + } + return true; + } + } + + // OTHER COMMANDS + + /** + * Adds and executes the AppendChildCommand to historyBrowser. + * + * @param parent + * The given parent + * @param child + * The node to be appended + */ + public void appendChild(Node parent, Node child) { + historyBrowser.addCommand(createAppendChildCommand(parent, child)); + } + + + /** + * Creates and return the AppendChild command. + * + * @param parent + * The given parent + * @param child + * The node to be appended + * @return the AppendChild command + */ + public AppendChildCommand createAppendChildCommand(Node parent, + Node child) { + return new AppendChildCommand + (getAppendChildCommandName(parent, child), parent, child); + } + + /** + * The AppendChild command. Appends the given node to the given parent node + * as a last child. + */ + public static class AppendChildCommand extends AbstractUndoableCommand { + + /** + * The node's previous parent. + */ + protected Node oldParentNode; + + /** + * The node's previous next sibling. + */ + protected Node oldNextSibling; + + /** + * The node's new parent. + */ + protected Node parentNode; + + /** + * The node to be appended. + */ + protected Node childNode; + + /** + * Constructor. + */ + public AppendChildCommand(String commandName, Node parentNode, + Node childNode) { + setName(commandName); + this.oldParentNode = childNode.getParentNode(); + this.oldNextSibling = childNode.getNextSibling(); + this.parentNode = parentNode; + this.childNode = childNode; + } + + public void execute() { + parentNode.appendChild(childNode); + } + + public void undo() { + if (oldParentNode != null) { + oldParentNode.insertBefore(childNode, oldNextSibling); + } else { + parentNode.removeChild(childNode); + } + } + + public void redo() { + execute(); + } + + public boolean shouldExecute() { + if (parentNode == null || childNode == null) { + return false; + } + return true; + } + } + + /** + * Adds and executes the InsertNodeBeforeCommand to historyBrowser. + * + * @param parent + * The given parent + * @param sibling + * Points where to be inserted + * @param child + * The node to insert + */ + public void insertChildBefore(Node parent, Node sibling, Node child) { + if (sibling == null) { + historyBrowser.addCommand(createAppendChildCommand(parent, child)); + } else { + historyBrowser.addCommand + (createInsertNodeBeforeCommand(parent, sibling, child)); + } + } + + /** + * Creates InsertChildBefore or AppendChild command, depending on the value + * of siblingNode. + * + * @param parent + * The parent node + * @param sibling + * The sibling node + * @param child + * The child node + * @return AppendChild command if sibling node is null, InsertChildBefore + * otherwise + */ + public UndoableCommand createInsertChildCommand(Node parent, + Node sibling, + Node child) { + if (sibling == null) { + return createAppendChildCommand(parent, child); + } else { + return createInsertNodeBeforeCommand(parent, sibling, child); + } + } + /** + * Creates and returns the InsertNodeBeforeCommand. + * + * @param parent + * The given parent + * @param sibling + * Points where to be inserted + * @param child + * The node to insert + * @return the InsertNodeBeforeCommand + */ + public InsertNodeBeforeCommand createInsertNodeBeforeCommand(Node parent, + Node sibling, + Node child) { + return new InsertNodeBeforeCommand + (getInsertBeforeCommandName(parent, child, sibling), + parent, sibling, child); + } + + /** + * Inserts the given node as a child to the given parent node before the + * specified sibling node, or as the last child of the given parent, if the + * sibling node is null. + */ + public static class InsertNodeBeforeCommand extends AbstractUndoableCommand { + + /** + * The node's previous parent. + */ + protected Node oldParent; + + /** + * The node's previous next sibling. + */ + protected Node oldNextSibling; + + /** + * The node's new next sibling. + */ + protected Node newNextSibling; + + /** + * The node's new parent. + */ + protected Node parent; + + /** + * The node to be appended. + */ + protected Node child; + + /** + * Constructor. + */ + public InsertNodeBeforeCommand(String commandName, Node parent, + Node sibling, Node child) { + setName(commandName); + this.oldParent = child.getParentNode(); + this.oldNextSibling = child.getNextSibling(); + this.parent = parent; + this.child = child; + this.newNextSibling = sibling; + } + + public void execute() { + if (newNextSibling != null) { + parent.insertBefore(child, newNextSibling); + } else { + parent.appendChild(child); + } + } + + /* (non-Javadoc) + * @see org.apache.batik.util.gui.AbstractUndoableCommand#undo() + */ + public void undo() { + if (oldParent != null) { + oldParent.insertBefore(child, oldNextSibling); + } else { + parent.removeChild(child); + } + } + + public void redo() { + execute(); + } + + public boolean shouldExecute() { + if (parent == null || child == null) { + return false; + } + return true; + } + } + + + /** + * Adds and executes the ReplaceChild command to historyBrowser. + * + * @param parent + * The parent node + * @param newChild + * Points where to be inserted + * @param oldChild + * The node to be appended + */ + public void replaceChild(Node parent, Node newChild, Node oldChild) { +// if (sibling == null) { +// historyBrowser.addCommand(new AppendChildCommand( +// APPEND_CHILD_COMMAND, parent, child)); +// } else { +// historyBrowser.addCommand(new InsertNodeBeforeCommand( +// REPLACE_CHILD_COMMAND, parent, sibling, child)); +// } + } + + /** + * insertBefore + */ + public static class ReplaceChildCommand extends AbstractUndoableCommand { + + /** + * The node's previous parent. + */ + protected Node oldParent; + + /** + * The node's previous next sibling. + */ + protected Node oldNextSibling; + + /** + * The node's new next sibling. + */ + protected Node newNextSibling; + + /** + * The node's new parent. + */ + protected Node parent; + + /** + * The node to be appended. + */ + protected Node child; + + /** + * Constructor. + */ + public ReplaceChildCommand(String commandName, Node parent, + Node sibling, Node child) { + setName(commandName); + this.oldParent = child.getParentNode(); + this.oldNextSibling = child.getNextSibling(); + this.parent = parent; + this.child = child; + this.newNextSibling = sibling; + } + + public void execute() { + if (newNextSibling != null) { + parent.insertBefore(child, newNextSibling); + } else { + parent.appendChild(child); + } + } + + public void undo() { + if (oldParent != null) { + oldParent.insertBefore(child, oldNextSibling); + } else { + parent.removeChild(child); + } + } + + public void redo() { + execute(); + } + + public boolean shouldExecute() { + if (parent == null || child == null) { + return false; + } + return true; + } + } + + /** + * Adds and executes the RemoveChild command to the History Browser. + * + * @param parent + * The given parent + * @param child + * The given child + */ + public void removeChild(Node parent, Node child) { + historyBrowser.addCommand(createRemoveChildCommand(parent, child)); + } + + /** + * Creates and returns the RemoveChild command. + * + * @param parent + * The parent node + * @param child + * The child node + * @return The RemoveChild command + */ + public RemoveChildCommand createRemoveChildCommand(Node parent, + Node child) { + return new RemoveChildCommand + (getRemoveChildCommandName(parent, child), parent, child); + } + + /** + * The RemoveChild command. Removes the given child node from its given + * parent node. + */ + public static class RemoveChildCommand extends AbstractUndoableCommand { + + /** + * Node's previous parent. + */ + protected Node parentNode; + + /** + * The node to be removed. + */ + protected Node childNode; + + /** + * Node's index in parent's children array. + */ + protected int indexInChildrenArray; + + /** + * Constructor. + */ + public RemoveChildCommand(String commandName, Node parentNode, + Node childNode) { + setName(commandName); + this.parentNode = parentNode; + this.childNode = childNode; + } + + public void execute() { + indexInChildrenArray = + DOMUtilities.getChildIndex(childNode, parentNode); + parentNode.removeChild(childNode); + } + + public void undo() { + Node refChild = + parentNode.getChildNodes().item(indexInChildrenArray); + parentNode.insertBefore(childNode, refChild); + } + + public void redo() { + parentNode.removeChild(childNode); + } + + public boolean shouldExecute() { + if (parentNode == null || childNode == null) { + return false; + } + return true; + } + } + + /** + * Adds and executes the ChangeNodeValueCommand to historyBrowser. + * + * @param contextNode + * The node whose nodeValue changed + * @param newValue + * The new node value + */ + public void setNodeValue(Node contextNode, String newValue) { + historyBrowser.addCommand + (createChangeNodeValueCommand(contextNode, newValue)); + } + + /** + * Creates and returns the ChangeNodeValue command. + * + * @param contextNode + * The node whose nodeValue changed + * @param newValue + * The new node value + * @return the ChangeNodeValue command + */ + public ChangeNodeValueCommand + createChangeNodeValueCommand(Node contextNode, String newValue) { + return new ChangeNodeValueCommand + (getChangeNodeValueCommandName(contextNode, newValue), + contextNode, newValue); + } + + /** + * The Change Node Value command. Sets the given node value to the given + * node. + */ + public static class ChangeNodeValueCommand extends AbstractUndoableCommand { + + /** + * The node whose value changed. + */ + protected Node contextNode; + + /** + * New node value. + */ + protected String newValue; + + /** + * Constructor. + */ + public ChangeNodeValueCommand(String commandName, Node contextNode, + String newValue) { + setName(commandName); + this.contextNode = contextNode; + this.newValue = newValue; + } + + public void execute() { + String oldNodeValue = contextNode.getNodeValue(); + contextNode.setNodeValue(newValue); + newValue = oldNodeValue; + } + + public void undo() { + execute(); + } + + public void redo() { + execute(); + } + + public boolean shouldExecute() { + if (contextNode == null) { + return false; + } + return true; + } + } + + /** + * Gets the current compound command. + * + * @return the currentCompoundCommand + */ + public AbstractCompoundCommand getCurrentCompoundCommand() { + if (currentCompoundCommand == null) { + currentCompoundCommand = + createCompoundUpdateCommand(OUTER_EDIT_COMMAND); + } + return currentCompoundCommand; + } + + /** + * Adds the given command to current compound command. + * + * @param cmd + * The command to add + */ + public void addToCurrentCompoundCommand(AbstractUndoableCommand cmd) { + getCurrentCompoundCommand().addCommand(cmd); + // Fire the 'doCompoundEdit' event + historyBrowser.fireDoCompoundEdit + (new HistoryBrowserEvent(getCurrentCompoundCommand())); + } + + /** + * Adds and executes the current compound command to history browser. + */ + public void performCurrentCompoundCommand() { + if (getCurrentCompoundCommand().getCommandNumber() > 0) { + historyBrowser.addCommand(getCurrentCompoundCommand()); + // Fire the 'compoundEditPerformed' event + historyBrowser.fireCompoundEditPerformed + (new HistoryBrowserEvent(currentCompoundCommand)); + // Reset the current compound command + currentCompoundCommand = null; + } + } + + // Command names + /** + * Gets the node name and the nodes id (nodeName + "nodeId"). + * + * @param node + * The given node + * @return e.g. node name with quoted node id or node name if id is empty + * String + */ + private String getNodeAsString(Node node) { + String id = ""; + if (node.getNodeType() == Node.ELEMENT_NODE) { + Element e = (Element) node; + id = e.getAttributeNS(null, SVGConstants.SVG_ID_ATTRIBUTE); + } + if (id.length() != 0) { + return node.getNodeName() + " \"" + id + "\""; + } + return node.getNodeName(); + } + + /** + * Gets the node info in brackets. + * + * @param node + * The given node + * @return e.g (rect "23") + */ + private String getBracketedNodeName(Node node) { + return "(" + getNodeAsString(node) + ")"; + } + + /** + * Generates the "Append Child" command name. + * + * @param parentNode + * The parent node + * @param childNode + * The child node + * @return The command name + */ + private String getAppendChildCommandName(Node parentNode, Node childNode) { + return "Append " + getNodeAsString(childNode) + " to " + + getNodeAsString(parentNode); + } + + /** + * Generates the "Insert Child Before" command name. + * + * @param parentNode + * The parentNode + * @param childNode + * The node being inserted + * @param siblingNode + * The new sibling node + * @return The command name + */ + private String getInsertBeforeCommandName(Node parentNode, Node childNode, + Node siblingNode) { + return "Insert " + getNodeAsString(childNode) + " to " + + getNodeAsString(parentNode) + " before " + + getNodeAsString(siblingNode); + } + + /** + * Generates the "Remove Child" command name. + * + * @param parent + * The parent node + * @param child + * The child node + * @return The command name + */ + private String getRemoveChildCommandName(Node parent, Node child) { + return "Remove " + getNodeAsString(child) + " from " + + getNodeAsString(parent); + } + + /** + * Generates the "Change Node Value" command name. + * + * @param contextNode + * The node whose value is to be changed + * @param newValue + * The new node value + * @return The command name + */ + private String getChangeNodeValueCommandName(Node contextNode, + String newValue) { + return "Change " + getNodeAsString(contextNode) + " value to " + + newValue; + } + + /** + * Generates the "Node Changed" command name. + * @return The command name + */ + private String getNodeChangedCommandName(Node node) { + return "Node " + getNodeAsString(node) + " changed"; + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/JAuthenticator.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/JAuthenticator.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/JAuthenticator.java 8 Apr 2013 10:55:08 -0000 1.1 @@ -0,0 +1,243 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.net.Authenticator; +import java.net.PasswordAuthentication; + +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JPasswordField; +import javax.swing.JTextField; +import javax.swing.SwingConstants; + +/** + * This class is resposible for providing authentication information + * when needed by network protocols. It does this by poping up a small + * window that asks for User ID and password for the system. + * + * @author Thomas DeWeese + * @version $Id: JAuthenticator.java,v 1.1 2013/04/08 10:55:08 marcin Exp $ + */ +public class JAuthenticator extends Authenticator { + + /** + * Internationalization message string + */ + public static final String TITLE + = "JAuthenticator.title"; + public static final String LABEL_SITE + = "JAuthenticator.label.site"; + public static final String LABEL_REQ + = "JAuthenticator.label.req"; + public static final String LABEL_USERID + = "JAuthenticator.label.userID"; + public static final String LABEL_PASSWORD + = "JAuthenticator.label.password"; + + public static final String LABEL_CANCEL + = "JAuthenticator.label.cancel"; + public static final String LABEL_OK + = "JAuthenticator.label.ok"; + + protected JDialog window; + protected JButton cancelButton; + protected JButton okButton; + + protected JLabel label1; + protected JLabel label2; + protected JTextField JUserID; + protected JPasswordField JPassword; + + final Object lock = new Object(); + + private boolean result; + private volatile boolean wasNotified; + private String userID; + private char [] password; + + public JAuthenticator() { + initWindow(); + } + + protected void initWindow() { + String title = Resources.getString(TITLE); + window = new JDialog((Frame)null, title, true); + + Container mainPanel = window.getContentPane(); + mainPanel.setLayout(new BorderLayout()); + mainPanel.add(buildAuthPanel(), BorderLayout.CENTER); + mainPanel.add(buildButtonPanel(), BorderLayout.SOUTH); + window.pack(); + + window.addWindowListener( new WindowAdapter() { + public void windowClosing(WindowEvent e) { + cancelListener.actionPerformed + (new ActionEvent(e.getWindow(), + ActionEvent.ACTION_PERFORMED, + "Close")); + } + }); + } + + protected JComponent buildAuthPanel() { + GridBagLayout gridBag = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + JPanel proxyPanel = new JPanel(gridBag); + c.fill = GridBagConstraints.BOTH; + c.weightx = 1.0; + + c.gridwidth = 1; + JLabel labelS = new JLabel(Resources.getString(LABEL_SITE)); + labelS.setHorizontalAlignment(SwingConstants.LEFT); + gridBag.setConstraints(labelS, c); + proxyPanel.add(labelS); + + c.gridwidth = GridBagConstraints.REMAINDER; + label1 = new JLabel(""); + label1.setHorizontalAlignment(SwingConstants.LEFT); + gridBag.setConstraints(label1, c); + proxyPanel.add(label1); + + c.gridwidth = 1; + JLabel labelR = new JLabel(Resources.getString(LABEL_REQ)); + labelR.setHorizontalAlignment(SwingConstants.LEFT); + gridBag.setConstraints(labelR, c); + proxyPanel.add(labelR); + + c.gridwidth = GridBagConstraints.REMAINDER; + label2 = new JLabel(""); + label2.setHorizontalAlignment(SwingConstants.LEFT); + gridBag.setConstraints(label2, c); + proxyPanel.add(label2); + + c.gridwidth = 1; + JLabel labelUserID = new JLabel(Resources.getString(LABEL_USERID)); + labelUserID.setHorizontalAlignment(SwingConstants.LEFT); + gridBag.setConstraints(labelUserID, c); + proxyPanel.add(labelUserID); + + c.gridwidth = GridBagConstraints.REMAINDER; + JUserID = new JTextField(20); + gridBag.setConstraints(JUserID, c); + proxyPanel.add(JUserID); + + c.gridwidth = 1; + JLabel labelPassword = new JLabel(Resources.getString(LABEL_PASSWORD)); + labelPassword.setHorizontalAlignment(SwingConstants.LEFT); + gridBag.setConstraints(labelPassword, c); + proxyPanel.add(labelPassword); + + c.gridwidth = GridBagConstraints.REMAINDER; + JPassword = new JPasswordField(20); + JPassword.setEchoChar('*'); + JPassword.addActionListener(okListener); + gridBag.setConstraints(JPassword, c); + proxyPanel.add(JPassword); + + return proxyPanel; + } + + + + protected JComponent buildButtonPanel() { + JPanel buttonPanel = new JPanel(); + cancelButton = new JButton(Resources.getString(LABEL_CANCEL)); + cancelButton.addActionListener(cancelListener); + buttonPanel.add(cancelButton); + + okButton = new JButton(Resources.getString(LABEL_OK)); + okButton.addActionListener( okListener); + buttonPanel.add(okButton); + + return buttonPanel; + } + + /** + * This is called by the protocol stack when authentication is + * required. We then show the dialog in the Swing event thread, + * and block waiting for the user to select either cancel or ok, + * at which point we get notified. + */ + public PasswordAuthentication getPasswordAuthentication() { + synchronized (lock) { + EventQueue.invokeLater(new Runnable() { + public void run() { + label1.setText(getRequestingSite().getHostName()); + label2.setText(getRequestingPrompt()); + window.setVisible(true); + } + }); + wasNotified = false; + while (!wasNotified) { + try { + lock.wait(); + } catch(InterruptedException ie) { } + } + if (!result) + return null; + + return new PasswordAuthentication(userID, password); + } + } + + ActionListener okListener = new ActionListener() { + public void actionPerformed(ActionEvent e) { + synchronized (lock) { + window.setVisible(false); + + userID = JUserID.getText(); + password = JPassword.getPassword(); + JPassword.setText(""); + result = true; + wasNotified = true; + lock.notifyAll(); + } + } + }; + + ActionListener cancelListener = new ActionListener() { + public void actionPerformed(ActionEvent e) { + synchronized (lock) { + window.setVisible(false); + + userID = null; + JUserID.setText(""); + password = null; + JPassword.setText(""); + result = false; + wasNotified = true; + lock.notifyAll(); + } + } + }; +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/JPEGOptionPanel.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/JPEGOptionPanel.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/JPEGOptionPanel.java 8 Apr 2013 10:55:07 -0000 1.1 @@ -0,0 +1,108 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Insets; +import java.util.Hashtable; + +import javax.swing.BorderFactory; +import javax.swing.JLabel; +import javax.swing.JSlider; + +import org.apache.batik.util.gui.ExtendedGridBagConstraints; + +/** + * This class represents a panel to control jpeg encoding quality. + * + * @author Thierry Kormann + * @version $Id: JPEGOptionPanel.java,v 1.1 2013/04/08 10:55:07 marcin Exp $ + */ +public class JPEGOptionPanel extends OptionPanel { + /** + * The jpeg encoding quality. + */ + protected JSlider quality; + + /** + * Creates a new panel. + */ + public JPEGOptionPanel() { + super(new GridBagLayout()); + + ExtendedGridBagConstraints constraints = + new ExtendedGridBagConstraints(); + + + constraints.insets = new Insets(5, 5, 5, 5); + + constraints.weightx = 0; + constraints.weighty = 0; + constraints.fill = GridBagConstraints.NONE; + constraints.setGridBounds(0, 0, 1, 1); + add(new JLabel(resources.getString("JPEGOptionPanel.label")), + constraints); + + quality = new JSlider(); + quality.setMinimum(0); + quality.setMaximum(100); + quality.setMajorTickSpacing(10); + quality.setMinorTickSpacing(5); + quality.setPaintTicks(true); + quality.setPaintLabels(true); + quality.setBorder(BorderFactory.createEmptyBorder(0,0,10,0)); + Hashtable labels = new Hashtable(); + for (int i=0; i < 100; i+=10) { + labels.put(new Integer(i), new JLabel("0."+i/10)); + } + labels.put(new Integer(100), new JLabel("1")); + quality.setLabelTable(labels); + + Dimension dim = quality.getPreferredSize(); + quality.setPreferredSize(new Dimension(350, dim.height)); + + constraints.weightx = 1.0; + constraints.fill = GridBagConstraints.HORIZONTAL; + constraints.setGridBounds(1, 0, 1, 1); + add(quality, constraints); + } + + /** + * Returns the jpeg quality. + */ + public float getQuality() { + return quality.getValue()/100f; + } + + /** + * Shows a dialog to choose the jpeg encoding quality and return + * the quality as a float. + */ + public static float showDialog(Component parent) { + String title = resources.getString("JPEGOptionPanel.dialog.title"); + JPEGOptionPanel panel = new JPEGOptionPanel(); + Dialog dialog = new Dialog(parent, title, panel); + dialog.pack(); + dialog.setVisible(true); + return panel.getQuality(); + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/JSVGViewerFrame.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/JSVGViewerFrame.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/JSVGViewerFrame.java 8 Apr 2013 10:55:08 -0000 1.1 @@ -0,0 +1,3137 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Event; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Point2D; +import java.awt.image.BufferedImage; +import java.awt.print.PrinterException; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FilenameFilter; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.Vector; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.ButtonGroup; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.JScrollPane; +import javax.swing.JToolBar; +import javax.swing.JWindow; +import javax.swing.KeyStroke; +import javax.swing.filechooser.FileFilter; +import javax.swing.text.Document; + +import org.apache.batik.bridge.DefaultExternalResourceSecurity; +import org.apache.batik.bridge.DefaultScriptSecurity; +import org.apache.batik.bridge.EmbededExternalResourceSecurity; +import org.apache.batik.bridge.EmbededScriptSecurity; +import org.apache.batik.bridge.ExternalResourceSecurity; +import org.apache.batik.bridge.NoLoadExternalResourceSecurity; +import org.apache.batik.bridge.NoLoadScriptSecurity; +import org.apache.batik.bridge.RelaxedExternalResourceSecurity; +import org.apache.batik.bridge.RelaxedScriptSecurity; +import org.apache.batik.bridge.ScriptSecurity; +import org.apache.batik.bridge.UpdateManager; +import org.apache.batik.bridge.UpdateManagerEvent; +import org.apache.batik.bridge.UpdateManagerListener; +import org.apache.batik.dom.StyleSheetProcessingInstruction; +import org.apache.batik.dom.svg.SVGOMDocument; +import org.apache.batik.dom.util.HashTable; +import org.apache.batik.dom.util.DOMUtilities; +import org.apache.batik.ext.swing.JAffineTransformChooser; +import org.apache.batik.swing.JSVGCanvas; +import org.apache.batik.swing.gvt.GVTTreeRendererEvent; +import org.apache.batik.swing.gvt.GVTTreeRendererListener; +import org.apache.batik.swing.gvt.Overlay; +import org.apache.batik.swing.svg.GVTTreeBuilderEvent; +import org.apache.batik.swing.svg.GVTTreeBuilderListener; +import org.apache.batik.swing.svg.LinkActivationEvent; +import org.apache.batik.swing.svg.LinkActivationListener; +import org.apache.batik.swing.svg.SVGDocumentLoaderEvent; +import org.apache.batik.swing.svg.SVGDocumentLoaderListener; +import org.apache.batik.swing.svg.SVGFileFilter; +import org.apache.batik.swing.svg.SVGLoadEventDispatcherEvent; +import org.apache.batik.swing.svg.SVGLoadEventDispatcherListener; +import org.apache.batik.swing.svg.SVGUserAgent; +import org.apache.batik.transcoder.TranscoderInput; +import org.apache.batik.transcoder.TranscoderOutput; +import org.apache.batik.transcoder.image.ImageTranscoder; +import org.apache.batik.transcoder.image.JPEGTranscoder; +import org.apache.batik.transcoder.image.PNGTranscoder; +import org.apache.batik.transcoder.image.TIFFTranscoder; +import org.apache.batik.transcoder.print.PrintTranscoder; +import org.apache.batik.transcoder.svg2svg.SVGTranscoder; +import org.apache.batik.util.ParsedURL; +import org.apache.batik.util.Platform; +import org.apache.batik.util.Service; +import org.apache.batik.util.SVGConstants; +import org.apache.batik.util.XMLConstants; +import org.apache.batik.util.gui.JErrorPane; +import org.apache.batik.util.gui.LocationBar; +import org.apache.batik.util.gui.MemoryMonitor; +import org.apache.batik.util.gui.URIChooser; +import org.apache.batik.util.gui.resource.ActionMap; +import org.apache.batik.util.gui.resource.JComponentModifier; +import org.apache.batik.util.gui.resource.MenuFactory; +import org.apache.batik.util.gui.resource.MissingListenerException; +import org.apache.batik.util.gui.resource.ToolBarFactory; +import org.apache.batik.util.gui.xmleditor.XMLDocument; +import org.apache.batik.util.gui.xmleditor.XMLTextEditor; +import org.apache.batik.util.resources.ResourceManager; +import org.apache.batik.xml.XMLUtilities; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.css.ViewCSS; +import org.w3c.dom.svg.SVGDocument; + +/** + * This class represents a SVG viewer swing frame. + * + * @author Stephane Hillion + * @version $Id: JSVGViewerFrame.java,v 1.1 2013/04/08 10:55:08 marcin Exp $ + */ +public class JSVGViewerFrame + extends JFrame + implements ActionMap, + SVGDocumentLoaderListener, + GVTTreeBuilderListener, + SVGLoadEventDispatcherListener, + GVTTreeRendererListener, + LinkActivationListener, + UpdateManagerListener { + + private static String EOL; + static { + try { + EOL = System.getProperty("line.separator", "\n"); + } catch (SecurityException e) { + EOL = "\n"; + } + } + + /** + * Kind of ugly, but we need to know if we are running before + * or after 1.4... + */ + protected static boolean priorJDK1_4 = true; + + /** + * If the following class can be found (it appeared in JDK 1.4), + * then we know we are post JDK 1.4. + */ + protected static final String JDK_1_4_PRESENCE_TEST_CLASS + = "java.util.logging.LoggingPermission"; + + static { + try { + Class.forName(JDK_1_4_PRESENCE_TEST_CLASS); + priorJDK1_4 = false; + } catch (ClassNotFoundException e) { + } + } + + /** + * The gui resources file name + */ + public static final String RESOURCES = + "org.apache.batik.apps.svgbrowser.resources.GUI"; + + // The actions names. + public static final String ABOUT_ACTION = "AboutAction"; + public static final String OPEN_ACTION = "OpenAction"; + public static final String OPEN_LOCATION_ACTION = "OpenLocationAction"; + public static final String NEW_WINDOW_ACTION = "NewWindowAction"; + public static final String RELOAD_ACTION = "ReloadAction"; + public static final String SAVE_AS_ACTION = "SaveAsAction"; + public static final String BACK_ACTION = "BackAction"; + public static final String FORWARD_ACTION = "ForwardAction"; + public static final String FULL_SCREEN_ACTION = "FullScreenAction"; + public static final String PRINT_ACTION = "PrintAction"; + public static final String EXPORT_AS_JPG_ACTION = "ExportAsJPGAction"; + public static final String EXPORT_AS_PNG_ACTION = "ExportAsPNGAction"; + public static final String EXPORT_AS_TIFF_ACTION = "ExportAsTIFFAction"; + public static final String PREFERENCES_ACTION = "PreferencesAction"; + public static final String CLOSE_ACTION = "CloseAction"; + public static final String VIEW_SOURCE_ACTION = "ViewSourceAction"; + public static final String EXIT_ACTION = "ExitAction"; + public static final String RESET_TRANSFORM_ACTION = "ResetTransformAction"; + public static final String ZOOM_IN_ACTION = "ZoomInAction"; + public static final String ZOOM_OUT_ACTION = "ZoomOutAction"; + public static final String PREVIOUS_TRANSFORM_ACTION = "PreviousTransformAction"; + public static final String NEXT_TRANSFORM_ACTION = "NextTransformAction"; + public static final String USE_STYLESHEET_ACTION = "UseStylesheetAction"; + public static final String PLAY_ACTION = "PlayAction"; + public static final String PAUSE_ACTION = "PauseAction"; + public static final String STOP_ACTION = "StopAction"; + public static final String MONITOR_ACTION = "MonitorAction"; + public static final String DOM_VIEWER_ACTION = "DOMViewerAction"; + public static final String SET_TRANSFORM_ACTION = "SetTransformAction"; + public static final String FIND_DIALOG_ACTION = "FindDialogAction"; + public static final String THUMBNAIL_DIALOG_ACTION = "ThumbnailDialogAction"; + public static final String FLUSH_ACTION = "FlushAction"; + public static final String TOGGLE_DEBUGGER_ACTION = "ToggleDebuggerAction"; + + /** + * The cursor indicating that an operation is pending. + */ + public static final Cursor WAIT_CURSOR = + new Cursor(Cursor.WAIT_CURSOR); + + /** + * The default cursor. + */ + public static final Cursor DEFAULT_CURSOR = + new Cursor(Cursor.DEFAULT_CURSOR); + + /** + * Name for the os-name property + */ + public static final String PROPERTY_OS_NAME + = Resources.getString("JSVGViewerFrame.property.os.name"); + + /** + * Name for the os.name default + */ + public static final String PROPERTY_OS_NAME_DEFAULT + = Resources.getString("JSVGViewerFrame.property.os.name.default"); + + /** + * Name for the os.name property prefix we are looking + * for in OpenAction to work around JFileChooser bug + */ + public static final String PROPERTY_OS_WINDOWS_PREFIX + = Resources.getString("JSVGViewerFrame.property.os.windows.prefix"); + + /** + * Resource string name for the Open dialog. + */ + protected static final String OPEN_TITLE = "Open.title"; + + /** + * The input handlers + */ + protected static Vector handlers; + + /** + * The default input handler + */ + protected static SquiggleInputHandler defaultHandler = new SVGInputHandler(); + + /** + * The resource bundle + */ + protected static ResourceBundle bundle; + + /** + * The resource manager + */ + protected static ResourceManager resources; + static { + bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault()); + resources = new ResourceManager(bundle); + } + + /** + * The current application. + */ + protected Application application; + + /** + * The JSVGCanvas. + */ + protected Canvas svgCanvas; + + /** + * An extension of JSVGCanvas that exposes the Rhino interpreter. + */ + protected class Canvas extends JSVGCanvas { + + /** + * Creates a new Canvas. + */ + public Canvas(SVGUserAgent ua, boolean eventsEnabled, + boolean selectableText) { + super(ua, eventsEnabled, selectableText); + } + + /** + * Returns the Rhino interpreter for this canvas. + */ + public Object getRhinoInterpreter() { + if (bridgeContext == null) { + return null; + } + return bridgeContext.getInterpreter("text/ecmascript"); + } + + /** + * JSVGViewerFrame DOMViewerController implementation. + */ + protected class JSVGViewerDOMViewerController + // extends CanvasDOMViewerController { + implements DOMViewerController { + + public boolean canEdit() { + return getUpdateManager() != null; + } + + public ElementOverlayManager createSelectionManager() { + if (canEdit()) { + return new ElementOverlayManager(Canvas.this); + } + return null; + } + + public org.w3c.dom.Document getDocument() { + return Canvas.this.svgDocument; + } + + public void performUpdate(Runnable r) { + if (canEdit()) { + getUpdateManager().getUpdateRunnableQueue().invokeLater(r); + } else { + r.run(); + } + } + + public void removeSelectionOverlay(Overlay selectionOverlay) { + getOverlays().remove(selectionOverlay); + } + + public void selectNode(Node node) { + DOMViewerAction dViewerAction = + (DOMViewerAction) getAction(DOM_VIEWER_ACTION); + dViewerAction.openDOMViewer(); + domViewer.selectNode(node); + } + } + } + + /** + * The panel where the svgCanvas is displayed + */ + protected JPanel svgCanvasPanel; + + /** + * A window used for full screen display + */ + protected JWindow window; + + /** + * The memory monitor frame. + */ + protected static JFrame memoryMonitorFrame; + + /** + * The current path. + */ + protected File currentPath = new File(""); + + /** + * The current export path. + */ + protected File currentSavePath = new File(""); + + /** + * The back action + */ + protected BackAction backAction = new BackAction(); + + /** + * The forward action + */ + protected ForwardAction forwardAction = new ForwardAction(); + + /** + * The play action + */ + protected PlayAction playAction = new PlayAction(); + + /** + * The pause action + */ + protected PauseAction pauseAction = new PauseAction(); + + /** + * The stop action + */ + protected StopAction stopAction = new StopAction(); + + /** + * The previous transform action + */ + protected PreviousTransformAction previousTransformAction = + new PreviousTransformAction(); + + /** + * The next transform action + */ + protected NextTransformAction nextTransformAction = + new NextTransformAction(); + + /** + * The use (author) stylesheet action + */ + protected UseStylesheetAction useStylesheetAction = + new UseStylesheetAction(); + + /** + * The debug flag. + */ + protected boolean debug; + + /** + * The auto adjust flag. + */ + protected boolean autoAdjust = true; + + /** + * Whether the update manager was stopped. + */ + protected boolean managerStopped; + + /** + * The SVG user agent. + */ + protected SVGUserAgent userAgent = new UserAgent(); + + /** + * The current document. + */ + protected SVGDocument svgDocument; + + /** + * The URI chooser. + */ + protected URIChooser uriChooser; + + /** + * The DOM viewer. + */ + protected DOMViewer domViewer; + + /** + * The Find dialog. + */ + protected FindDialog findDialog; + + /** + * The Find dialog. + */ + protected ThumbnailDialog thumbnailDialog; + + /** + * The transform dialog + */ + protected JAffineTransformChooser.Dialog transformDialog; + + /** + * The location bar. + */ + protected LocationBar locationBar; + + /** + * The status bar. + */ + protected StatusBar statusBar; + + /** + * The initial frame title. + */ + protected String title; + + /** + * The local history. + */ + protected LocalHistory localHistory; + + /** + * The transform history. + */ + protected TransformHistory transformHistory = new TransformHistory(); + + /** + * The alternate style-sheet title. + */ + protected String alternateStyleSheet; + + /** + * The debugger object. + */ + protected Debugger debugger; + + /** + * Creates a new SVG viewer frame. + */ + public JSVGViewerFrame(Application app) { + application = app; + + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + application.closeJSVGViewerFrame(JSVGViewerFrame.this); + } + }); + + // + // Set the frame's maximum size so that content + // bigger than the screen does not cause the creation + // of unnecessary large images. + // + svgCanvas = new Canvas(userAgent, true, true) { + Dimension screenSize; + + { + screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + setMaximumSize(screenSize); + } + + public Dimension getPreferredSize(){ + Dimension s = super.getPreferredSize(); + if (s.width > screenSize.width) s.width =screenSize.width; + if (s.height > screenSize.height) s.height = screenSize.height; + return s; + } + + + /** + * This method is called when the component knows the desired + * size of the window (based on width/height of outermost SVG + * element). We override it to immediately pack this frame. + */ + public void setMySize(Dimension d) { + setPreferredSize(d); + invalidate(); + if (JSVGViewerFrame.this.autoAdjust) { + Platform.unmaximize(JSVGViewerFrame.this); + JSVGViewerFrame.this.pack(); + } + } + + public void setDisableInteractions(boolean b) { + super.setDisableInteractions(b); + + // Disable/Enable all our different ways to adjust the + // rendering transform (menus, toolbar, thumbnail, keyboard). + + ((Action)listeners.get(SET_TRANSFORM_ACTION)) .setEnabled(!b); + + if (thumbnailDialog != null) + thumbnailDialog.setInteractionEnabled(!b); + } + }; + + javax.swing.ActionMap map = svgCanvas.getActionMap(); + map.put(FULL_SCREEN_ACTION, new FullScreenAction()); + javax.swing.InputMap imap = svgCanvas.getInputMap(JComponent.WHEN_FOCUSED); + KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0); + imap.put(key, FULL_SCREEN_ACTION); + + svgCanvas.setDoubleBufferedRendering(true); + + listeners.put(ABOUT_ACTION, new AboutAction()); + listeners.put(OPEN_ACTION, new OpenAction()); + listeners.put(OPEN_LOCATION_ACTION, new OpenLocationAction()); + listeners.put(NEW_WINDOW_ACTION, new NewWindowAction()); + listeners.put(RELOAD_ACTION, new ReloadAction()); + listeners.put(SAVE_AS_ACTION, new SaveAsAction()); + listeners.put(BACK_ACTION, backAction); + listeners.put(FORWARD_ACTION, forwardAction); + listeners.put(PRINT_ACTION, new PrintAction()); + listeners.put(EXPORT_AS_JPG_ACTION, new ExportAsJPGAction()); + listeners.put(EXPORT_AS_PNG_ACTION, new ExportAsPNGAction()); + listeners.put(EXPORT_AS_TIFF_ACTION, new ExportAsTIFFAction()); + listeners.put(PREFERENCES_ACTION, new PreferencesAction()); + listeners.put(CLOSE_ACTION, new CloseAction()); + listeners.put(EXIT_ACTION, application.createExitAction(this)); + listeners.put(VIEW_SOURCE_ACTION, new ViewSourceAction()); + + javax.swing.ActionMap cMap = svgCanvas.getActionMap(); + listeners.put(RESET_TRANSFORM_ACTION, + cMap.get(JSVGCanvas.RESET_TRANSFORM_ACTION)); + listeners.put(ZOOM_IN_ACTION, + cMap.get(JSVGCanvas.ZOOM_IN_ACTION)); + listeners.put(ZOOM_OUT_ACTION, + cMap.get(JSVGCanvas.ZOOM_OUT_ACTION)); + + listeners.put(PREVIOUS_TRANSFORM_ACTION, previousTransformAction); + key = KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_MASK); + imap.put(key, previousTransformAction); + + listeners.put(NEXT_TRANSFORM_ACTION, nextTransformAction); + key = KeyStroke.getKeyStroke(KeyEvent.VK_L, KeyEvent.CTRL_MASK); + imap.put(key, nextTransformAction); + + listeners.put(USE_STYLESHEET_ACTION, useStylesheetAction); + listeners.put(PLAY_ACTION, playAction); + listeners.put(PAUSE_ACTION, pauseAction); + listeners.put(STOP_ACTION, stopAction); + listeners.put(MONITOR_ACTION, new MonitorAction()); + listeners.put(DOM_VIEWER_ACTION, new DOMViewerAction()); + listeners.put(SET_TRANSFORM_ACTION, new SetTransformAction()); + listeners.put(FIND_DIALOG_ACTION, new FindDialogAction()); + listeners.put(THUMBNAIL_DIALOG_ACTION, new ThumbnailDialogAction()); + listeners.put(FLUSH_ACTION, new FlushAction()); + listeners.put(TOGGLE_DEBUGGER_ACTION, new ToggleDebuggerAction()); + + JPanel p = null; + try { + // Create the menu + MenuFactory mf = new MenuFactory(bundle, this); + JMenuBar mb = + mf.createJMenuBar("MenuBar", application.getUISpecialization()); + setJMenuBar(mb); + + localHistory = new LocalHistory(mb, this); + + String[] uri = application.getVisitedURIs(); + for (int i=0; i "Close" + menu.getItem(3).setAccelerator + (KeyStroke.getKeyStroke(KeyEvent.VK_W, Event.CTRL_MASK)); + + debugGui.setSize(600, 460); + debugGui.pack(); + setExitAction(new Runnable() { + public void run() { + svgFrame.hideDebugger(); + }}); + WindowAdapter wa = new WindowAdapter() { + public void windowClosing(WindowEvent e) { + svgFrame.hideDebugger(); + }}; + debugGui.addWindowListener(wa); + debugGui.setVisible(true); + attach(); + } + + /** + * Attaches the debugger to the canvas' current interpreter. + */ + public void attach() { + Object interpreter = svgFrame.svgCanvas.getRhinoInterpreter(); + if (interpreter != null) { + attachTo(getContextFactory(interpreter)); + } + } + + /** + * Calls {@code getDebugFrame} on {@link #debuggerInstance}. + */ + protected JFrame getDebugFrame() { + try { + return (JFrame) debuggerMethods[GET_DEBUG_FRAME_METHOD].invoke + (debuggerInstance, (Object[]) null); + } catch (InvocationTargetException ite) { + throw new RuntimeException(ite.getMessage()); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae.getMessage()); + } + } + + /** + * Calls {@code setExitAction} on {@link #debuggerInstance}. + */ + protected void setExitAction(Runnable r) { + try { + debuggerMethods[SET_EXIT_ACTION_METHOD].invoke + (debuggerInstance, new Object[] { r }); + } catch (InvocationTargetException ite) { + throw new RuntimeException(ite.getMessage()); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae.getMessage()); + } + } + + /** + * Calls {@code attachTo} on {@link #debuggerInstance}. + */ + public void attachTo(Object contextFactory) { + try { + debuggerMethods[ATTACH_TO_METHOD].invoke + (debuggerInstance, new Object[] { contextFactory }); + } catch (InvocationTargetException ite) { + throw new RuntimeException(ite.getMessage()); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae.getMessage()); + } + } + + /** + * Calls {@code detach} on {@link #debuggerInstance}. + */ + public void detach() { + try { + debuggerMethods[DETACH_METHOD].invoke(debuggerInstance, + (Object[]) null); + } catch (InvocationTargetException ite) { + throw new RuntimeException(ite.getMessage()); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae.getMessage()); + } + } + + /** + * Calls {@code go} on {@link #debuggerInstance}. + */ + public void go() { + try { + debuggerMethods[GO_METHOD].invoke(debuggerInstance, + (Object[]) null); + } catch (InvocationTargetException ite) { + throw new RuntimeException(ite.getMessage()); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae.getMessage()); + } + } + + /** + * Calls {@code clearAllBreakpoints} on {@link #debuggerInstance}. + */ + public void clearAllBreakpoints() { + try { + debuggerMethods[CLEAR_ALL_BREAKPOINTS_METHOD].invoke + (debuggerInstance, (Object[]) null); + } catch (InvocationTargetException ite) { + throw new RuntimeException(ite.getMessage()); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae.getMessage()); + } + } + + /** + * Calls {@code dispose} on {@link #debuggerInstance}. + */ + public void dispose() { + try { + debuggerMethods[DISPOSE_METHOD].invoke(debuggerInstance, + (Object[]) null); + } catch (InvocationTargetException ite) { + throw new RuntimeException(ite.getMessage()); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae.getMessage()); + } + } + + /** + * Calls {@code getContextFactory} on the given instance of + * {@link org.apache.batik.script.rhino.RhinoInterpreter}. + */ + protected Object getContextFactory(Object rhinoInterpreter) { + try { + return getContextFactoryMethod.invoke(rhinoInterpreter, + (Object[]) null); + } catch (InvocationTargetException ite) { + throw new RuntimeException(ite.getMessage()); + } catch (IllegalAccessException iae) { + throw new RuntimeException(iae.getMessage()); + } + } + } + + /** + * To show the about dialog + */ + public class AboutAction extends AbstractAction { + public AboutAction(){ + } + + public void actionPerformed(ActionEvent e){ + AboutDialog dlg = new AboutDialog(JSVGViewerFrame.this); + // Work around pack() bug on some platforms + dlg.setSize(dlg.getPreferredSize()); + dlg.setLocationRelativeTo(JSVGViewerFrame.this); + dlg.setVisible(true); + dlg.toFront(); + } + } + + /** + * To open a new file. + */ + public class OpenAction extends AbstractAction { + + public OpenAction() { + } + public void actionPerformed(ActionEvent e) { + File f = null; + if (Platform.isOSX) { + FileDialog fileDialog = + new FileDialog(JSVGViewerFrame.this, + Resources.getString(OPEN_TITLE)); + fileDialog.setFilenameFilter(new FilenameFilter() { + public boolean accept(File dir, String name) { + Iterator iter = getHandlers().iterator(); + while (iter.hasNext()) { + SquiggleInputHandler handler + = (SquiggleInputHandler)iter.next(); + if (handler.accept(new File(dir, name))) { + return true; + } + } + return false; + } + }); + fileDialog.setVisible(true); + String filename = fileDialog.getFile(); + if (fileDialog != null) { + String dirname = fileDialog.getDirectory(); + f = new File(dirname, filename); + } + } else { + JFileChooser fileChooser = null; + + // Apply work around Windows problem when security is enabled, + // and when prior to JDK 1.4. + String os = System.getProperty(PROPERTY_OS_NAME, PROPERTY_OS_NAME_DEFAULT); + SecurityManager sm = System.getSecurityManager(); + + if ( priorJDK1_4 && sm != null && os.indexOf(PROPERTY_OS_WINDOWS_PREFIX) != -1 ){ + fileChooser = new JFileChooser(makeAbsolute(currentPath), + new WindowsAltFileSystemView()); + } else { + fileChooser = new JFileChooser(makeAbsolute(currentPath)); + } + + fileChooser.setFileHidingEnabled(false); + fileChooser.setFileSelectionMode + (JFileChooser.FILES_ONLY); + + // + // Add file filters from the handlers map + // + Iterator iter = getHandlers().iterator(); + while (iter.hasNext()) { + SquiggleInputHandler handler + = (SquiggleInputHandler)iter.next(); + fileChooser.addChoosableFileFilter + (new SquiggleInputHandlerFilter(handler)); + } + + int choice = fileChooser.showOpenDialog(JSVGViewerFrame.this); + if (choice == JFileChooser.APPROVE_OPTION) { + f = fileChooser.getSelectedFile(); + currentPath = f; + } + } + + if (f != null) { + try { + String furl = f.toURL().toString(); + showSVGDocument(furl); + } catch (MalformedURLException ex) { + if (userAgent != null) { + userAgent.displayError(ex); + } + } + } + } + } + + /** + * Shows the given document into the viewer frame + */ + public void showSVGDocument(String uri){ + try { + ParsedURL purl = new ParsedURL(uri); + SquiggleInputHandler + handler = getInputHandler(purl); + + handler.handle(purl, + JSVGViewerFrame.this); + } catch (Exception e) { + if (userAgent != null) { + userAgent.displayError(e); + } + } + + } + + /** + * Returns the input handler for the given URI + */ + public SquiggleInputHandler getInputHandler(ParsedURL purl) throws IOException { + Iterator iter = getHandlers().iterator(); + SquiggleInputHandler handler = null; + + while (iter.hasNext()) { + SquiggleInputHandler curHandler = + (SquiggleInputHandler)iter.next(); + if (curHandler.accept(purl)) { + handler = curHandler; + break; + } + } + + // No handler found, use the default one. + if (handler == null) { + handler = defaultHandler; + } + + return handler; + } + + + /** + * Returns the list of input file handler. + */ + protected static Vector getHandlers() { + if (handlers != null) { + return handlers; + } + + handlers = new Vector(); + registerHandler(new SVGInputHandler()); + + Iterator iter = Service.providers(SquiggleInputHandler.class); + while (iter.hasNext()) { + SquiggleInputHandler handler + = (SquiggleInputHandler)iter.next(); + + registerHandler(handler); + } + + return handlers; + } + + /** + * Registers an input file handler by adding it to the handlers map. + * @param handler the new input handler to register. + */ + public static synchronized + void registerHandler(SquiggleInputHandler handler) { + Vector handlers = getHandlers(); + handlers.addElement(handler); + } + + /** + * To open a new document. + */ + public class OpenLocationAction extends AbstractAction { + public OpenLocationAction() {} + public void actionPerformed(ActionEvent e) { + if (uriChooser == null) { + uriChooser = new URIChooser(JSVGViewerFrame.this); + uriChooser.setFileFilter(new SVGFileFilter()); + uriChooser.pack(); + Rectangle fr = getBounds(); + Dimension sd = uriChooser.getSize(); + uriChooser.setLocation(fr.x + (fr.width - sd.width) / 2, + fr.y + (fr.height - sd.height) / 2); + } + if (uriChooser.showDialog() == URIChooser.OK_OPTION) { + String s = uriChooser.getText(); + if (s == null) return; + int i = s.indexOf( '#' ); + String t = ""; + if (i != -1) { + t = s.substring(i + 1); + s = s.substring(0, i); + } + if (!s.equals("")) { + File f = new File(s); + if (f.exists()) { + if (f.isDirectory()) { + s = null; + } else { + try { + s = f.getCanonicalPath(); + if (s.startsWith("/")) { + s = "file:" + s; + } else { + s = "file:/" + s; + } + } catch (IOException ex) { + } + } + } + if (s != null) { + if (svgDocument != null) { + ParsedURL docPURL + = new ParsedURL(svgDocument.getURL()); + ParsedURL purl = new ParsedURL(docPURL, s); + String fi = svgCanvas.getFragmentIdentifier(); + if (docPURL.equals(purl) && t.equals(fi)) { + return; + } + } + if (t.length() != 0) { + s += '#' + t; + } + + showSVGDocument(s); + } + } + } + } + } + + /** + * To open a new window. + */ + public class NewWindowAction extends AbstractAction { + public NewWindowAction() {} + public void actionPerformed(ActionEvent e) { + JSVGViewerFrame vf = application.createAndShowJSVGViewerFrame(); + + // Copy the current settings to the new window. + vf.autoAdjust = autoAdjust; + vf.debug = debug; + vf.svgCanvas.setProgressivePaint(svgCanvas.getProgressivePaint()); + vf.svgCanvas.setDoubleBufferedRendering + (svgCanvas.getDoubleBufferedRendering()); + } + } + + /** + * To show the preferences. + */ + public class PreferencesAction extends AbstractAction { + public PreferencesAction() {} + public void actionPerformed(ActionEvent e) { + application.showPreferenceDialog(JSVGViewerFrame.this); + } + } + + /** + * To close the last document. + */ + public class CloseAction extends AbstractAction { + public CloseAction() {} + public void actionPerformed(ActionEvent e) { + application.closeJSVGViewerFrame(JSVGViewerFrame.this); + } + } + + /** + * To reload the current document. + */ + public class ReloadAction extends AbstractAction { + public ReloadAction() {} + public void actionPerformed(ActionEvent e) { + if ((e.getModifiers() & ActionEvent.SHIFT_MASK) == 1) { + svgCanvas.flushImageCache(); + } + if (svgDocument != null) { + localHistory.reload(); + } + } + } + + /** + * To go back to the previous document + */ + public class BackAction extends AbstractAction + implements JComponentModifier { + List components = new LinkedList(); + public BackAction() {} + public void actionPerformed(ActionEvent e) { + if (localHistory.canGoBack()) { + localHistory.back(); + } + } + + public void addJComponent(JComponent c) { + components.add(c); + c.setEnabled(false); + } + + protected void update() { + boolean b = localHistory.canGoBack(); + Iterator it = components.iterator(); + while (it.hasNext()) { + ((JComponent)it.next()).setEnabled(b); + } + } + } + + /** + * To go forward to the next document + */ + public class ForwardAction extends AbstractAction + implements JComponentModifier { + List components = new LinkedList(); + public ForwardAction() {} + public void actionPerformed(ActionEvent e) { + if (localHistory.canGoForward()) { + localHistory.forward(); + } + } + + public void addJComponent(JComponent c) { + components.add(c); + c.setEnabled(false); + } + + protected void update() { + boolean b = localHistory.canGoForward(); + Iterator it = components.iterator(); + while (it.hasNext()) { + ((JComponent)it.next()).setEnabled(b); + } + } + } + + /** + * To print the current document. + */ + public class PrintAction extends AbstractAction { + public PrintAction() {} + public void actionPerformed(ActionEvent e) { + if (svgDocument != null) { + final SVGDocument doc = svgDocument; + new Thread() { + public void run(){ + String uri = doc.getURL(); + String fragment = svgCanvas.getFragmentIdentifier(); + if (fragment != null) { + uri += '#' +fragment; + } + + // + // Build a PrintTranscoder to handle printing + // of the svgDocument object + // + PrintTranscoder pt = new PrintTranscoder(); + + // + // Set transcoding hints + // + if (application.getXMLParserClassName() != null) { + pt.addTranscodingHint + (JPEGTranscoder.KEY_XML_PARSER_CLASSNAME, + application.getXMLParserClassName()); + } + + pt.addTranscodingHint(PrintTranscoder.KEY_SHOW_PAGE_DIALOG, + Boolean.TRUE); + + + pt.addTranscodingHint(PrintTranscoder.KEY_SHOW_PRINTER_DIALOG, + Boolean.TRUE); + + // + // Do transcoding now + // + pt.transcode(new TranscoderInput(uri), null); + + // + // Print + // + try { + pt.print(); + } catch (PrinterException ex) { + userAgent.displayError(ex); + } + } + }.start(); + } + } + } + + /** + * To save the current document as SVG. + */ + public class SaveAsAction extends AbstractAction { + public SaveAsAction() {} + + public void actionPerformed(ActionEvent e) { + JFileChooser fileChooser; + fileChooser = new JFileChooser(makeAbsolute(currentSavePath)); + fileChooser.setDialogTitle(resources.getString("SaveAs.title")); + fileChooser.setFileHidingEnabled(false); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + fileChooser.addChoosableFileFilter(new ImageFileFilter(".svg")); + + int choice = fileChooser.showSaveDialog(JSVGViewerFrame.this); + if (choice != JFileChooser.APPROVE_OPTION) + return; + + final File f = fileChooser.getSelectedFile(); + + SVGOptionPanel sop; + sop = SVGOptionPanel.showDialog(JSVGViewerFrame.this); + + final boolean useXMLBase = sop.getUseXMLBase(); + final boolean prettyPrint = sop.getPrettyPrint(); + sop = null; + + final SVGDocument svgDoc = svgCanvas.getSVGDocument(); + if (svgDoc == null) return; + + statusBar.setMessage(resources.getString("Message.saveAs")); + currentSavePath = f; + OutputStreamWriter w = null; + try { + OutputStream tos = null; + tos = new FileOutputStream(f); + tos = new BufferedOutputStream(tos); + w = new OutputStreamWriter(tos, "utf-8"); + } catch (Exception ex) { + userAgent.displayError(ex); + return; + } + + final OutputStreamWriter writer = w; + + final Runnable doneRun = new Runnable() { + public void run() { + String doneStr = resources.getString("Message.done"); + statusBar.setMessage(doneStr); + } + }; + Runnable r = new Runnable() { + public void run() { + try { + // Write standard XML header. + writer.write + (""); + writer.write (EOL); + + Node fc = svgDoc.getFirstChild(); + if (fc.getNodeType() != Node.DOCUMENT_TYPE_NODE) { + // Not DT node in Document, so + // provide Document Type dec. + writer.write (""); + writer.write (EOL); + writer.write (EOL); + } + Element root = svgDoc.getRootElement(); + boolean doXMLBase = useXMLBase; + if (root.hasAttributeNS + (XMLConstants.XML_NAMESPACE_URI, "base")) + doXMLBase = false; + + if (doXMLBase) { + root.setAttributeNS + (XMLConstants.XML_NAMESPACE_URI, + "xml:base", + svgDoc.getURL()); + } + + if (prettyPrint) { + SVGTranscoder trans = new SVGTranscoder(); + trans.transcode(new TranscoderInput(svgDoc), + new TranscoderOutput(writer)); + } else { + DOMUtilities.writeDocument(svgDoc, writer); + } + + writer.close(); + + if (doXMLBase) + root.removeAttributeNS + (XMLConstants.XML_NAMESPACE_URI, + "xml:base"); + + if (EventQueue.isDispatchThread()) { + doneRun.run(); + } else { + EventQueue.invokeLater(doneRun); + } + } catch (Exception ex) { + userAgent.displayError(ex); + } + } + }; + + UpdateManager um = svgCanvas.getUpdateManager(); + if ((um != null) && (um.isRunning())) { + um.getUpdateRunnableQueue().invokeLater(r); + } else { + r.run(); + } + } + } + + /** + * To save the current document as JPG. + */ + public class ExportAsJPGAction extends AbstractAction { + public ExportAsJPGAction() {} + public void actionPerformed(ActionEvent e) { + JFileChooser fileChooser = + new JFileChooser(makeAbsolute(currentSavePath)); + fileChooser.setDialogTitle(resources.getString("ExportAsJPG.title")); + fileChooser.setFileHidingEnabled(false); + fileChooser.setFileSelectionMode + (JFileChooser.FILES_ONLY); + fileChooser.addChoosableFileFilter(new ImageFileFilter(".jpg")); + + int choice = fileChooser.showSaveDialog(JSVGViewerFrame.this); + if (choice == JFileChooser.APPROVE_OPTION) { + float quality = + JPEGOptionPanel.showDialog(JSVGViewerFrame.this); + + final File f = fileChooser.getSelectedFile(); + BufferedImage buffer = svgCanvas.getOffScreen(); + if (buffer != null) { + statusBar.setMessage + (resources.getString("Message.exportAsJPG")); + + // create a BufferedImage of the appropriate type + int w = buffer.getWidth(); + int h = buffer.getHeight(); + final ImageTranscoder trans = new JPEGTranscoder(); + if (application.getXMLParserClassName() != null) { + trans.addTranscodingHint + (JPEGTranscoder.KEY_XML_PARSER_CLASSNAME, + application.getXMLParserClassName()); + } + trans.addTranscodingHint + (JPEGTranscoder.KEY_QUALITY, new Float(quality)); + + final BufferedImage img = trans.createImage(w, h); + + // paint the buffer to the image + Graphics2D g2d = img.createGraphics(); + g2d.setColor(Color.white); + g2d.fillRect(0, 0, w, h); + g2d.drawImage(buffer, null, 0, 0); + new Thread() { + public void run() { + try { + currentSavePath = f; + OutputStream ostream = + new BufferedOutputStream(new FileOutputStream(f)); + trans.writeImage(img, new TranscoderOutput(ostream)); + ostream.close(); + } catch (Exception ex) { } + statusBar.setMessage + (resources.getString("Message.done")); + } + }.start(); + } + } + } + } + + /** + * To save the current document as PNG. + */ + public class ExportAsPNGAction extends AbstractAction { + public ExportAsPNGAction() {} + public void actionPerformed(ActionEvent e) { + JFileChooser fileChooser = + new JFileChooser(makeAbsolute(currentSavePath)); + fileChooser.setDialogTitle(resources.getString("ExportAsPNG.title")); + fileChooser.setFileHidingEnabled(false); + fileChooser.setFileSelectionMode + (JFileChooser.FILES_ONLY); + fileChooser.addChoosableFileFilter(new ImageFileFilter(".png")); + + int choice = fileChooser.showSaveDialog(JSVGViewerFrame.this); + if (choice == JFileChooser.APPROVE_OPTION) { + + // Start: By Jun Inamori (jun@oop-reserch.com) + boolean isIndexed = PNGOptionPanel.showDialog(JSVGViewerFrame.this); + // End: By Jun Inamori (jun@oop-reserch.com) + + final File f = fileChooser.getSelectedFile(); + BufferedImage buffer = svgCanvas.getOffScreen(); + if (buffer != null) { + statusBar.setMessage + (resources.getString("Message.exportAsPNG")); + + // create a BufferedImage of the appropriate type + int w = buffer.getWidth(); + int h = buffer.getHeight(); + final ImageTranscoder trans = new PNGTranscoder(); + if (application.getXMLParserClassName() != null) { + trans.addTranscodingHint + (JPEGTranscoder.KEY_XML_PARSER_CLASSNAME, + application.getXMLParserClassName()); + } + trans.addTranscodingHint(PNGTranscoder.KEY_FORCE_TRANSPARENT_WHITE, + Boolean.TRUE ); + + // Start: By Jun Inamori + if(isIndexed){ + trans.addTranscodingHint(PNGTranscoder.KEY_INDEXED,new Integer(256)); + } + // End: By Jun Inamori + + final BufferedImage img = trans.createImage(w, h); + + // paint the buffer to the image + Graphics2D g2d = img.createGraphics(); + g2d.drawImage(buffer, null, 0, 0); + new Thread() { + public void run() { + try { + currentSavePath = f; + OutputStream ostream = + new BufferedOutputStream(new FileOutputStream(f)); + trans.writeImage(img, + new TranscoderOutput(ostream)); + ostream.close(); + } catch (Exception ex) {} + statusBar.setMessage + (resources.getString("Message.done")); + } + }.start(); + } + } + } + } + + /** + * To save the current document as TIFF. + */ + public class ExportAsTIFFAction extends AbstractAction { + public ExportAsTIFFAction() {} + public void actionPerformed(ActionEvent e) { + JFileChooser fileChooser = + new JFileChooser(makeAbsolute(currentSavePath)); + fileChooser.setDialogTitle(resources.getString("ExportAsTIFF.title")); + fileChooser.setFileHidingEnabled(false); + fileChooser.setFileSelectionMode + (JFileChooser.FILES_ONLY); + fileChooser.addChoosableFileFilter(new ImageFileFilter(".tiff")); + + int choice = fileChooser.showSaveDialog(JSVGViewerFrame.this); + if (choice == JFileChooser.APPROVE_OPTION) { + final File f = fileChooser.getSelectedFile(); + BufferedImage buffer = svgCanvas.getOffScreen(); + if (buffer != null) { + statusBar.setMessage + (resources.getString("Message.exportAsTIFF")); + + // create a BufferedImage of the appropriate type + int w = buffer.getWidth(); + int h = buffer.getHeight(); + final ImageTranscoder trans = new TIFFTranscoder(); + if (application.getXMLParserClassName() != null) { + trans.addTranscodingHint + (JPEGTranscoder.KEY_XML_PARSER_CLASSNAME, + application.getXMLParserClassName()); + } + final BufferedImage img = trans.createImage(w, h); + + // paint the buffer to the image + Graphics2D g2d = img.createGraphics(); + g2d.drawImage(buffer, null, 0, 0); + new Thread() { + public void run() { + try { + currentSavePath = f; + OutputStream ostream = new BufferedOutputStream + (new FileOutputStream(f)); + trans.writeImage + (img, new TranscoderOutput(ostream)); + ostream.close(); + } catch (Exception ex) {} + statusBar.setMessage + (resources.getString("Message.done")); + } + }.start(); + } + } + } + } + + /** + * To view the source of the current document. + */ + public class ViewSourceAction extends AbstractAction { + public ViewSourceAction() {} + public void actionPerformed(ActionEvent e) { + if (svgDocument == null) { + return; + } + + final ParsedURL u = new ParsedURL(svgDocument.getURL()); + + final JFrame fr = new JFrame(u.toString()); + fr.setSize(resources.getInteger("ViewSource.width"), + resources.getInteger("ViewSource.height")); + final XMLTextEditor ta = new XMLTextEditor(); + // ta.setLineWrap(true); + ta.setFont(new Font("monospaced", Font.PLAIN, 12)); + + JScrollPane scroll = new JScrollPane(); + scroll.getViewport().add(ta); + scroll.setVerticalScrollBarPolicy + (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + fr.getContentPane().add(scroll, BorderLayout.CENTER); + + new Thread() { + public void run() { + char [] buffer = new char[4096]; + + try { + Document doc = new XMLDocument(); + + ParsedURL purl = new ParsedURL(svgDocument.getURL()); + InputStream is + = u.openStream(getInputHandler(purl). + getHandledMimeTypes()); + // u.openStream(MimeTypeConstants.MIME_TYPES_SVG); + + Reader in = XMLUtilities.createXMLDocumentReader(is); + int len; + while ((len=in.read(buffer, 0, buffer.length)) != -1) { + doc.insertString(doc.getLength(), + new String(buffer, 0, len), null); + } + + ta.setDocument(doc); + ta.setEditable(false); + // ta.setBackground(Color.white); + fr.setVisible(true); + } catch (Exception ex) { + userAgent.displayError(ex); + } + } + }.start(); + } + } + + /** + * To flush image cache (purely for debugging purposes) + */ + public class FlushAction extends AbstractAction { + public FlushAction() {} + public void actionPerformed(ActionEvent e) { + svgCanvas.flush(); + // Force redraw... + svgCanvas.setRenderingTransform(svgCanvas.getRenderingTransform()); + } + } + + /** + * To toggle visiblity of JavaScript Debugger. + */ + public class ToggleDebuggerAction extends AbstractAction { + public ToggleDebuggerAction() { + super("Toggle Debugger Action"); + } + + public void actionPerformed(ActionEvent e) { + if (debugger == null) { + showDebugger(); + } else { + hideDebugger(); + } + } + } + + /** + * To go back to the previous transform + */ + public class PreviousTransformAction extends AbstractAction + implements JComponentModifier { + List components = new LinkedList(); + public PreviousTransformAction() {} + public void actionPerformed(ActionEvent e) { + if (transformHistory.canGoBack()) { + transformHistory.back(); + update(); + nextTransformAction.update(); + svgCanvas.setRenderingTransform(transformHistory.currentTransform()); + } + } + + public void addJComponent(JComponent c) { + components.add(c); + c.setEnabled(false); + } + + protected void update() { + boolean b = transformHistory.canGoBack(); + Iterator it = components.iterator(); + while (it.hasNext()) { + ((JComponent)it.next()).setEnabled(b); + } + } + } + + /** + * To go forward to the next transform + */ + public class NextTransformAction extends AbstractAction + implements JComponentModifier { + List components = new LinkedList(); + public NextTransformAction() {} + public void actionPerformed(ActionEvent e) { + if (transformHistory.canGoForward()) { + transformHistory.forward(); + update(); + previousTransformAction.update(); + svgCanvas.setRenderingTransform(transformHistory.currentTransform()); + } + } + + public void addJComponent(JComponent c) { + components.add(c); + c.setEnabled(false); + } + + protected void update() { + boolean b = transformHistory.canGoForward(); + Iterator it = components.iterator(); + while (it.hasNext()) { + ((JComponent)it.next()).setEnabled(b); + } + } + } + + /** + * To apply the selected author stylesheet + */ + public class UseStylesheetAction extends AbstractAction + implements JComponentModifier { + + List components = new LinkedList(); + + public UseStylesheetAction() {} + + public void actionPerformed(ActionEvent e) { + } + + public void addJComponent(JComponent c) { + components.add(c); + c.setEnabled(false); + } + + protected void update() { + alternateStyleSheet = null; + Iterator it = components.iterator(); + SVGDocument doc = svgCanvas.getSVGDocument(); + while (it.hasNext()) { + JComponent stylesheetMenu = (JComponent)it.next(); + stylesheetMenu.removeAll(); + stylesheetMenu.setEnabled(false); + + ButtonGroup buttonGroup = new ButtonGroup(); + + for (Node n = doc.getFirstChild(); + n != null && n.getNodeType() != Node.ELEMENT_NODE; + n = n.getNextSibling()) { + if (n instanceof StyleSheetProcessingInstruction) { + StyleSheetProcessingInstruction sspi; + sspi = (StyleSheetProcessingInstruction)n; + HashTable attrs = sspi.getPseudoAttributes(); + final String title = (String)attrs.get("title"); + String alt = (String)attrs.get("alternate"); + if (title != null && "yes".equals(alt)) { + JRadioButtonMenuItem button; + button = new JRadioButtonMenuItem(title); + + button.addActionListener + (new java.awt.event.ActionListener() { + public void actionPerformed(ActionEvent e) { + SVGOMDocument doc; + doc = (SVGOMDocument)svgCanvas.getSVGDocument(); + doc.clearViewCSS(); + alternateStyleSheet = title; + svgCanvas.setSVGDocument(doc); + } + }); + + buttonGroup.add(button); + stylesheetMenu.add(button); + stylesheetMenu.setEnabled(true); + } + } + } + } + } + } + + /** + * To restart after a pause. + */ + public class PlayAction extends AbstractAction + implements JComponentModifier { + List components = new LinkedList(); + public PlayAction() {} + public void actionPerformed(ActionEvent e) { + svgCanvas.resumeProcessing(); + } + + public void addJComponent(JComponent c) { + components.add(c); + c.setEnabled(false); + } + + public void update(boolean enabled) { + Iterator it = components.iterator(); + while (it.hasNext()) { + ((JComponent)it.next()).setEnabled(enabled); + } + } + } + + /** + * To pause a document. + */ + public class PauseAction extends AbstractAction + implements JComponentModifier { + List components = new LinkedList(); + public PauseAction() {} + public void actionPerformed(ActionEvent e) { + svgCanvas.suspendProcessing(); + } + + public void addJComponent(JComponent c) { + components.add(c); + c.setEnabled(false); + } + + public void update(boolean enabled) { + Iterator it = components.iterator(); + while (it.hasNext()) { + ((JComponent)it.next()).setEnabled(enabled); + } + } + } + + /** + * To stop the current processing. + */ + public class StopAction extends AbstractAction + implements JComponentModifier { + List components = new LinkedList(); + public StopAction() {} + public void actionPerformed(ActionEvent e) { + svgCanvas.stopProcessing(); + } + + public void addJComponent(JComponent c) { + components.add(c); + c.setEnabled(false); + } + + public void update(boolean enabled) { + Iterator it = components.iterator(); + while (it.hasNext()) { + ((JComponent)it.next()).setEnabled(enabled); + } + } + } + + /** + * To show the set transform dialog + */ + public class SetTransformAction extends AbstractAction { + public SetTransformAction(){} + public void actionPerformed(ActionEvent e){ + if (transformDialog == null){ + transformDialog + = JAffineTransformChooser.createDialog + (JSVGViewerFrame.this, + resources.getString("SetTransform.title")); + } + + AffineTransform txf = transformDialog.showDialog(); + if(txf != null){ + AffineTransform at = svgCanvas.getRenderingTransform(); + if(at == null){ + at = new AffineTransform(); + } + + txf.concatenate(at); + svgCanvas.setRenderingTransform(txf); + } + } + } + + /** + * To display the memory monitor. + */ + public class MonitorAction extends AbstractAction { + public MonitorAction() {} + public void actionPerformed(ActionEvent e) { + if (memoryMonitorFrame == null) { + memoryMonitorFrame = new MemoryMonitor(); + Rectangle fr = getBounds(); + Dimension md = memoryMonitorFrame.getSize(); + memoryMonitorFrame.setLocation(fr.x + (fr.width - md.width) / 2, + fr.y + (fr.height - md.height) / 2); + } + memoryMonitorFrame.setVisible(true); + } + } + + /** + * To display the Find dialog + */ + public class FindDialogAction extends AbstractAction { + public FindDialogAction() {} + public void actionPerformed(ActionEvent e) { + if (findDialog == null) { + findDialog = new FindDialog(JSVGViewerFrame.this, svgCanvas); + findDialog.setGraphicsNode(svgCanvas.getGraphicsNode()); + findDialog.pack(); + Rectangle fr = getBounds(); + Dimension td = findDialog.getSize(); + findDialog.setLocation(fr.x + (fr.width - td.width) / 2, + fr.y + (fr.height - td.height) / 2); + } + findDialog.setVisible(true); + } + } + + /** + * To display the Thumbnail dialog + */ + public class ThumbnailDialogAction extends AbstractAction { + public ThumbnailDialogAction() {} + public void actionPerformed(ActionEvent e) { + if (thumbnailDialog == null) { + thumbnailDialog + = new ThumbnailDialog(JSVGViewerFrame.this, svgCanvas); + thumbnailDialog.pack(); + Rectangle fr = getBounds(); + Dimension td = thumbnailDialog.getSize(); + thumbnailDialog.setLocation(fr.x + (fr.width - td.width) / 2, + fr.y + (fr.height - td.height) / 2); + } + thumbnailDialog.setInteractionEnabled + (!svgCanvas.getDisableInteractions()); + thumbnailDialog.setVisible(true); + } + } + + /** + * To display the document full screen + */ + public class FullScreenAction extends AbstractAction { + public FullScreenAction() {} + + public void actionPerformed(ActionEvent e) { + if (window == null || !window.isVisible()) { + if (window == null) { + window = new JWindow(JSVGViewerFrame.this); + Dimension size = Toolkit.getDefaultToolkit().getScreenSize(); + window.setSize(size); + } + // Go to full screen in JWindow) + svgCanvas.getParent().remove(svgCanvas); + window.getContentPane().add(svgCanvas); + window.setVisible(true); + window.toFront(); + svgCanvas.requestFocus(); + } else { + // Go back to JSVGViewerFrame display + svgCanvas.getParent().remove(svgCanvas); + svgCanvasPanel.add(svgCanvas, BorderLayout.CENTER); + window.setVisible(false); + } + } + } + + /** + * To display the DOM viewer of the document + */ + public class DOMViewerAction extends AbstractAction { + + public DOMViewerAction() { + } + + public void actionPerformed(ActionEvent e) { + openDOMViewer(); + } + + public void openDOMViewer() { + if (domViewer == null || domViewer.isDisplayable()) { + domViewer = new DOMViewer + (svgCanvas.new JSVGViewerDOMViewerController()); + Rectangle fr = getBounds(); + Dimension td = domViewer.getSize(); + domViewer.setLocation(fr.x + (fr.width - td.width) / 2, + fr.y + (fr.height - td.height) / 2); + } + domViewer.setVisible(true); + } + + public DOMViewer getDOMViewer() { + return domViewer; + } + } + + // ActionMap ///////////////////////////////////////////////////// + + /** + * The map that contains the action listeners + */ + protected Map listeners = new HashMap(); + + /** + * Returns the action associated with the given string + * or null on error + * @param key the key mapped with the action to get + * @throws MissingListenerException if the action is not found + */ + public Action getAction(String key) throws MissingListenerException { + Action result = (Action)listeners.get(key); + //if (result == null) { + //result = canvas.getAction(key); + //} + if (result == null) { + throw new MissingListenerException("Can't find action.", RESOURCES, key); + } + return result; + } + + // SVGDocumentLoaderListener /////////////////////////////////////////// + + long time; // For debug. + + /** + * Called when the loading of a document was started. + */ + public void documentLoadingStarted(SVGDocumentLoaderEvent e) { + String msg = resources.getString("Message.documentLoad"); + if (debug) { + System.out.println(msg); + time = System.currentTimeMillis(); + } + statusBar.setMainMessage(msg); + stopAction.update(true); + svgCanvas.setCursor(WAIT_CURSOR); + } + + + /** + * Called when the loading of a document was completed. + */ + public void documentLoadingCompleted(SVGDocumentLoaderEvent e) { + if (debug) { + System.out.print(resources.getString("Message.documentLoadTime")); + System.out.println((System.currentTimeMillis() - time) + " ms"); + } + + setSVGDocument(e.getSVGDocument(), + e.getSVGDocument().getURL(), + e.getSVGDocument().getTitle()); + } + + /** + * Forces the viewer frame to show the input SVGDocument + */ + public void setSVGDocument(SVGDocument svgDocument, + String svgDocumentURL, + String svgDocumentTitle) { + this.svgDocument = svgDocument; + + if (domViewer != null) { + if(domViewer.isVisible() && svgDocument != null) { + domViewer.setDocument(svgDocument, + (ViewCSS)svgDocument.getDocumentElement()); + } else { + domViewer.dispose(); + domViewer = null; + } + } + stopAction.update(false); + svgCanvas.setCursor(DEFAULT_CURSOR); + String s = svgDocumentURL; + locationBar.setText(s); + if (debugger != null) { + debugger.detach(); + debugger.setDocumentURL(s); + } + if (title == null) { + title = getTitle(); + } + + String dt = svgDocumentTitle; + if (dt.length() != 0) { + setTitle(title + ": " + dt); + } else { + int i = s.lastIndexOf("/"); + if (i == -1) + i = s.lastIndexOf("\\"); + if (i == -1) { + setTitle(title + ": " + s); + } else { + setTitle(title + ": " + s.substring(i + 1)); + } + } + + localHistory.update(s); + application.addVisitedURI(s); + backAction.update(); + forwardAction.update(); + + transformHistory = new TransformHistory(); + previousTransformAction.update(); + nextTransformAction.update(); + + useStylesheetAction.update(); + } + + /** + * Called when the loading of a document was cancelled. + */ + public void documentLoadingCancelled(SVGDocumentLoaderEvent e) { + String msg = resources.getString("Message.documentCancelled"); + if (debug) { + System.out.println(msg); + } + statusBar.setMainMessage(""); + statusBar.setMessage(msg); + stopAction.update(false); + svgCanvas.setCursor(DEFAULT_CURSOR); + } + + /** + * Called when the loading of a document has failed. + */ + public void documentLoadingFailed(SVGDocumentLoaderEvent e) { + String msg = resources.getString("Message.documentFailed"); + if (debug) { + System.out.println(msg); + } + statusBar.setMainMessage(""); + statusBar.setMessage(msg); + stopAction.update(false); + svgCanvas.setCursor(DEFAULT_CURSOR); + } + + // GVTTreeBuilderListener ////////////////////////////////////////////// + + /** + * Called when a build started. + * The data of the event is initialized to the old document. + */ + public void gvtBuildStarted(GVTTreeBuilderEvent e) { + String msg = resources.getString("Message.treeBuild"); + if (debug) { + System.out.println(msg); + time = System.currentTimeMillis(); + } + statusBar.setMainMessage(msg); + stopAction.update(true); + svgCanvas.setCursor(WAIT_CURSOR); + } + + /** + * Called when a build was completed. + */ + public void gvtBuildCompleted(GVTTreeBuilderEvent e) { + if (debug) { + System.out.print(resources.getString("Message.treeBuildTime")); + System.out.println((System.currentTimeMillis() - time) + " ms"); + } + if (findDialog != null) { + if(findDialog.isVisible()) { + findDialog.setGraphicsNode(svgCanvas.getGraphicsNode()); + } else { + findDialog.dispose(); + findDialog = null; + } + } + stopAction.update(false); + svgCanvas.setCursor(DEFAULT_CURSOR); + svgCanvas.setSelectionOverlayXORMode + (application.isSelectionOverlayXORMode()); + svgCanvas.requestFocus(); // request focus when load completes. + if (debugger != null) { + debugger.attach(); + } + } + + /** + * Called when a build was cancelled. + */ + public void gvtBuildCancelled(GVTTreeBuilderEvent e) { + String msg = resources.getString("Message.treeCancelled"); + if (debug) { + System.out.println(msg); + } + statusBar.setMainMessage(""); + statusBar.setMessage(msg); + stopAction.update(false); + svgCanvas.setCursor(DEFAULT_CURSOR); + svgCanvas.setSelectionOverlayXORMode + (application.isSelectionOverlayXORMode()); + } + + /** + * Called when a build failed. + */ + public void gvtBuildFailed(GVTTreeBuilderEvent e) { + String msg = resources.getString("Message.treeFailed"); + if (debug) { + System.out.println(msg); + } + statusBar.setMainMessage(""); + statusBar.setMessage(msg); + stopAction.update(false); + svgCanvas.setCursor(DEFAULT_CURSOR); + svgCanvas.setSelectionOverlayXORMode + (application.isSelectionOverlayXORMode()); + if (autoAdjust) { + pack(); + } + } + + // SVGLoadEventDispatcherListener ////////////////////////////////////// + + /** + * Called when a onload event dispatch started. + */ + public void svgLoadEventDispatchStarted(SVGLoadEventDispatcherEvent e) { + String msg = resources.getString("Message.onload"); + if (debug) { + System.out.println(msg); + time = System.currentTimeMillis(); + } + stopAction.update(true); + statusBar.setMainMessage(msg); + } + + /** + * Called when a onload event dispatch was completed. + */ + public void svgLoadEventDispatchCompleted(SVGLoadEventDispatcherEvent e) { + if (debug) { + System.out.print(resources.getString("Message.onloadTime")); + System.out.println((System.currentTimeMillis() - time) + " ms"); + } + stopAction.update(false); + statusBar.setMainMessage(""); + statusBar.setMessage(resources.getString("Message.done")); + } + + /** + * Called when a onload event dispatch was cancelled. + */ + public void svgLoadEventDispatchCancelled(SVGLoadEventDispatcherEvent e) { + String msg = resources.getString("Message.onloadCancelled"); + if (debug) { + System.out.println(msg); + } + stopAction.update(false); + statusBar.setMainMessage(""); + statusBar.setMessage(msg); + } + + /** + * Called when a onload event dispatch failed. + */ + public void svgLoadEventDispatchFailed(SVGLoadEventDispatcherEvent e) { + String msg = resources.getString("Message.onloadFailed"); + if (debug) { + System.out.println(msg); + } + stopAction.update(false); + statusBar.setMainMessage(""); + statusBar.setMessage(msg); + } + + // GVTTreeRendererListener ///////////////////////////////////////////// + + /** + * Called when a rendering is in its preparing phase. + */ + public void gvtRenderingPrepare(GVTTreeRendererEvent e) { + if (debug) { + String msg = resources.getString("Message.treeRenderingPrep"); + System.out.println(msg); + time = System.currentTimeMillis(); + } + stopAction.update(true); + svgCanvas.setCursor(WAIT_CURSOR); + statusBar.setMainMessage(resources.getString("Message.treeRendering")); + } + + /** + * Called when a rendering started. + */ + public void gvtRenderingStarted(GVTTreeRendererEvent e) { + if (debug) { + String msg = resources.getString("Message.treeRenderingPrepTime"); + System.out.print(msg); + System.out.println((System.currentTimeMillis() - time) + " ms"); + time = System.currentTimeMillis(); + msg = resources.getString("Message.treeRenderingStart"); + System.out.println(msg); + } + // Do nothing + } + + /** + * Called when a rendering was completed. + */ + public void gvtRenderingCompleted(GVTTreeRendererEvent e) { + if (debug) { + String msg = resources.getString("Message.treeRenderingTime"); + System.out.print(msg); + System.out.println((System.currentTimeMillis() - time) + " ms"); + } + statusBar.setMainMessage(""); + statusBar.setMessage(resources.getString("Message.done")); + if (!svgCanvas.isDynamic() || managerStopped) { + stopAction.update(false); + } + svgCanvas.setCursor(DEFAULT_CURSOR); + + transformHistory.update(svgCanvas.getRenderingTransform()); + previousTransformAction.update(); + nextTransformAction.update(); + } + + /** + * Called when a rendering was cancelled. + */ + public void gvtRenderingCancelled(GVTTreeRendererEvent e) { + String msg = resources.getString("Message.treeRenderingCancelled"); + if (debug) { + System.out.println(msg); + } + statusBar.setMainMessage(""); + statusBar.setMessage(msg); + if (!svgCanvas.isDynamic()) { + stopAction.update(false); + } + svgCanvas.setCursor(DEFAULT_CURSOR); + } + + /** + * Called when a rendering failed. + */ + public void gvtRenderingFailed(GVTTreeRendererEvent e) { + String msg = resources.getString("Message.treeRenderingFailed"); + if (debug) { + System.out.println(msg); + } + statusBar.setMainMessage(""); + statusBar.setMessage(msg); + if (!svgCanvas.isDynamic()) { + stopAction.update(false); + } + svgCanvas.setCursor(DEFAULT_CURSOR); + } + + // LinkActivationListener ///////////////////////////////////////// + + /** + * Called when a link was activated. + */ + public void linkActivated(LinkActivationEvent e) { + String s = e.getReferencedURI(); + if (svgDocument != null) { + ParsedURL docURL = new ParsedURL(svgDocument.getURL()); + ParsedURL url = new ParsedURL(docURL, s); + if (!url.sameFile(docURL)) { + return; + } + + if (s.indexOf( '#' ) != -1) { + localHistory.update(s); + locationBar.setText(s); + if (debugger != null) { + debugger.detach(); + debugger.setDocumentURL(s); + } + application.addVisitedURI(s); + backAction.update(); + forwardAction.update(); + + transformHistory = new TransformHistory(); + previousTransformAction.update(); + nextTransformAction.update(); + } + } + } + + // UpdateManagerListener //////////////////////////////////////////////// + + /** + * Called when the manager was started. + */ + public void managerStarted(UpdateManagerEvent e) { + if (debug) { + String msg = resources.getString("Message.updateManagerStarted"); + System.out.println(msg); + } + managerStopped = false; + playAction.update(false); + pauseAction.update(true); + stopAction.update(true); + } + + /** + * Called when the manager was suspended. + */ + public void managerSuspended(UpdateManagerEvent e) { + if (debug) { + String msg = resources.getString("Message.updateManagerSuspended"); + System.out.println(msg); + } + playAction.update(true); + pauseAction.update(false); + } + + /** + * Called when the manager was resumed. + */ + public void managerResumed(UpdateManagerEvent e) { + if (debug) { + String msg = resources.getString("Message.updateManagerResumed"); + System.out.println(msg); + } + playAction.update(false); + pauseAction.update(true); + } + + /** + * Called when the manager was stopped. + */ + public void managerStopped(UpdateManagerEvent e) { + if (debug) { + String msg = resources.getString("Message.updateManagerStopped"); + System.out.println(msg); + } + managerStopped = true; + playAction.update(false); + pauseAction.update(false); + stopAction.update(false); + } + + /** + * Called when an update started. + */ + public void updateStarted(final UpdateManagerEvent e) { + } + + /** + * Called when an update was completed. + */ + public void updateCompleted(final UpdateManagerEvent e) { + } + + /** + * Called when an update failed. + */ + public void updateFailed(UpdateManagerEvent e) { + } + + /** + * This class implements a SVG user agent. + */ + protected class UserAgent implements SVGUserAgent { + + /** + * Creates a new SVGUserAgent. + */ + protected UserAgent() { + } + + /** + * Displays an error message. + */ + public void displayError(String message) { + if (debug) { + System.err.println(message); + } + JOptionPane pane = + new JOptionPane(message, JOptionPane.ERROR_MESSAGE); + JDialog dialog = pane.createDialog(JSVGViewerFrame.this, "ERROR"); + dialog.setModal(false); + dialog.setVisible(true); + } + + /** + * Displays an error resulting from the specified Exception. + */ + public void displayError(Exception ex) { + if (debug) { + ex.printStackTrace(); + } + JErrorPane pane = + new JErrorPane(ex, JOptionPane.ERROR_MESSAGE); + JDialog dialog = pane.createDialog(JSVGViewerFrame.this, "ERROR"); + dialog.setModal(false); + dialog.setVisible(true); + } + + /** + * Displays a message in the User Agent interface. + * The given message is typically displayed in a status bar. + */ + public void displayMessage(String message) { + statusBar.setMessage(message); + } + + /** + * Shows an alert dialog box. + */ + public void showAlert(String message) { + svgCanvas.showAlert(message); + } + + /** + * Shows a prompt dialog box. + */ + public String showPrompt(String message) { + return svgCanvas.showPrompt(message); + } + + /** + * Shows a prompt dialog box. + */ + public String showPrompt(String message, String defaultValue) { + return svgCanvas.showPrompt(message, defaultValue); + } + + /** + * Shows a confirm dialog box. + */ + public boolean showConfirm(String message) { + return svgCanvas.showConfirm(message); + } + + /** + * Returns the size of a px CSS unit in millimeters. + */ + public float getPixelUnitToMillimeter() { + return 0.26458333333333333333333333333333f; // 96dpi + } + + /** + * Returns the size of a px CSS unit in millimeters. + * This will be removed after next release. + * @see #getPixelUnitToMillimeter() + */ + public float getPixelToMM() { + return getPixelUnitToMillimeter(); + + } + + /** + * Returns the default font family. + */ + public String getDefaultFontFamily() { + return application.getDefaultFontFamily(); + } + + /** + * Returns the medium font size. + */ + public float getMediumFontSize() { + // 9pt (72pt == 1in) + return 9f * 25.4f / (72f * getPixelUnitToMillimeter()); + } + + /** + * Returns a lighter font-weight. + */ + public float getLighterFontWeight(float f) { + // Round f to nearest 100... + int weight = ((int)((f+50)/100))*100; + switch (weight) { + case 100: return 100; + case 200: return 100; + case 300: return 200; + case 400: return 300; + case 500: return 400; + case 600: return 400; + case 700: return 400; + case 800: return 400; + case 900: return 400; + default: + throw new IllegalArgumentException("Bad Font Weight: " + f); + } + } + + /** + * Returns a bolder font-weight. + */ + public float getBolderFontWeight(float f) { + // Round f to nearest 100... + int weight = ((int)((f+50)/100))*100; + switch (weight) { + case 100: return 600; + case 200: return 600; + case 300: return 600; + case 400: return 600; + case 500: return 600; + case 600: return 700; + case 700: return 800; + case 800: return 900; + case 900: return 900; + default: + throw new IllegalArgumentException("Bad Font Weight: " + f); + } + } + + + /** + * Returns the language settings. + */ + public String getLanguages() { + return application.getLanguages(); + } + + /** + * Returns the user stylesheet uri. + * @return null if no user style sheet was specified. + */ + public String getUserStyleSheetURI() { + return application.getUserStyleSheetURI(); + } + + /** + * Returns the class name of the XML parser. + */ + public String getXMLParserClassName() { + return application.getXMLParserClassName(); + } + + /** + * Returns true if the XML parser must be in validation mode, false + * otherwise. + */ + public boolean isXMLParserValidating() { + return application.isXMLParserValidating(); + } + + /** + * Returns this user agent's CSS media. + */ + public String getMedia() { + return application.getMedia(); + } + + /** + * Returns this user agent's alternate style-sheet title. + */ + public String getAlternateStyleSheet() { + return alternateStyleSheet; + } + + /** + * Opens a link. + * @param uri The document URI. + * @param newc Whether the link should be activated in a new component. + */ + public void openLink(String uri, boolean newc) { + if (newc) { + application.openLink(uri); + } else { + showSVGDocument(uri); + } + } + + /** + * Tells whether the given extension is supported by this + * user agent. + */ + public boolean supportExtension(String s) { + return false; + } + + public void handleElement(Element elt, Object data){ + } + + /** + * Returns the security settings for the given script + * type, script url and document url + * + * @param scriptType type of script, as found in the + * type attribute of the <script> element. + * @param scriptURL url for the script, as defined in + * the script's xlink:href attribute. If that + * attribute was empty, then this parameter should + * be null + * @param docURL url for the document into which the + * script was found. + */ + public ScriptSecurity getScriptSecurity(String scriptType, + ParsedURL scriptURL, + ParsedURL docURL){ + if (!application.canLoadScriptType(scriptType)) { + return new NoLoadScriptSecurity(scriptType); + } else { + switch(application.getAllowedScriptOrigin()) { + case ResourceOrigin.ANY: + return new RelaxedScriptSecurity(scriptType, + scriptURL, + docURL); + case ResourceOrigin.DOCUMENT: + return new DefaultScriptSecurity(scriptType, + scriptURL, + docURL); + case ResourceOrigin.EMBEDED: + return new EmbededScriptSecurity(scriptType, + scriptURL, + docURL); + default: + return new NoLoadScriptSecurity(scriptType); + } + } + } + + /** + * This method throws a SecurityException if the script + * of given type, found at url and referenced from docURL + * should not be loaded. + * + * This is a convenience method to call checkLoadScript + * on the ScriptSecurity strategy returned by + * getScriptSecurity. + * + * @param scriptType type of script, as found in the + * type attribute of the <script> element. + * @param scriptURL url for the script, as defined in + * the script's xlink:href attribute. If that + * attribute was empty, then this parameter should + * be null + * @param docURL url for the document into which the + * script was found. + */ + public void checkLoadScript(String scriptType, + ParsedURL scriptURL, + ParsedURL docURL) throws SecurityException { + ScriptSecurity s = getScriptSecurity(scriptType, + scriptURL, + docURL); + + if (s != null) { + s.checkLoadScript(); + } + } + + /** + * Returns the security settings for the given + * resource url and document url + * + * @param resourceURL url for the resource, as defined in + * the resource's xlink:href attribute. If that + * attribute was empty, then this parameter should + * be null + * @param docURL url for the document into which the + * resource was found. + */ + public ExternalResourceSecurity + getExternalResourceSecurity(ParsedURL resourceURL, + ParsedURL docURL){ + switch(application.getAllowedExternalResourceOrigin()) { + case ResourceOrigin.ANY: + return new RelaxedExternalResourceSecurity(resourceURL, + docURL); + case ResourceOrigin.DOCUMENT: + return new DefaultExternalResourceSecurity(resourceURL, + docURL); + case ResourceOrigin.EMBEDED: + return new EmbededExternalResourceSecurity(resourceURL); + default: + return new NoLoadExternalResourceSecurity(); + } + } + + /** + * This method throws a SecurityException if the resource + * found at url and referenced from docURL + * should not be loaded. + * + * This is a convenience method to call checkLoadExternalResource + * on the ExternalResourceSecurity strategy returned by + * getExternalResourceSecurity. + * + * @param resourceURL url for the script, as defined in + * the resource's xlink:href attribute. If that + * attribute was empty, then this parameter should + * be null + * @param docURL url for the document into which the + * resource was found. + */ + public void + checkLoadExternalResource(ParsedURL resourceURL, + ParsedURL docURL) throws SecurityException { + ExternalResourceSecurity s + = getExternalResourceSecurity(resourceURL, docURL); + + if (s != null) { + s.checkLoadExternalResource(); + } + } + } + + /** + * A FileFilter used when exporting the SVG document as an image. + */ + protected static class ImageFileFilter extends FileFilter { + + /** The extension of the image filename. */ + protected String extension; + + public ImageFileFilter(String extension) { + this.extension = extension; + } + + /** + * Returns true if f is a file with the correct extension, + * false otherwise. + */ + public boolean accept(File f) { + boolean accept = false; + String fileName = null; + if (f != null) { + if (f.isDirectory()) { + accept = true; + } else { + fileName = f.getPath().toLowerCase(); + if (fileName.endsWith(extension)) { + accept = true; + } + } + } + return accept; + } + + /** + * Returns the file description + */ + public String getDescription() { + return extension; + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/LocalHistory.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/LocalHistory.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/LocalHistory.java 8 Apr 2013 10:55:08 -0000 1.1 @@ -0,0 +1,258 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.ButtonGroup; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JRadioButtonMenuItem; + +/** + * This class represents an history of the files visited by a single + * browser frame. + * + * @author Stephane Hillion + * @version $Id: LocalHistory.java,v 1.1 2013/04/08 10:55:08 marcin Exp $ + */ +public class LocalHistory { + /** + * The frame to manage. + */ + protected JSVGViewerFrame svgFrame; + + /** + * The menu which contains the history. + */ + protected JMenu menu; + + /** + * The index of the first history item in this menu. + */ + protected int index; + + /** + * The visited URIs. + */ + protected List visitedURIs = new ArrayList(); + + /** + * The index of the current URI. + */ + protected int currentURI = -1; + + /** + * The button group for the menu items. + */ + protected ButtonGroup group = new ButtonGroup(); + + /** + * The action listener. + */ + protected ActionListener actionListener = new RadioListener(); + + /** + * The current state. + */ + protected int state; + + // States + protected static final int STABLE_STATE = 0; + protected static final int BACK_PENDING_STATE = 1; + protected static final int FORWARD_PENDING_STATE = 2; + protected static final int RELOAD_PENDING_STATE = 3; + + /** + * Creates a new local history. + * @param mb The menubar used to display the history. It must + * contain one '@@@' item used as marker to place the + * history items. + * @param svgFrame The frame to manage. + */ + public LocalHistory(JMenuBar mb, JSVGViewerFrame svgFrame) { + this.svgFrame = svgFrame; + + // Find the marker. + int mc = mb.getMenuCount(); + for (int i = 0; i < mc; i++) { + JMenu m = mb.getMenu(i); + int ic = m.getItemCount(); + for (int j = 0; j < ic; j++) { + JMenuItem mi = m.getItem(j); + if (mi != null) { + String s = mi.getText(); + if ("@@@".equals(s)) { + menu = m; + index = j; + m.remove(j); + return; + } + } + } + } + throw new IllegalArgumentException("No '@@@' marker found"); + } + + /** + * Goes back of one position in the history. + * Assumes that canGoBack() is true. + */ + public void back() { + update(); + state = BACK_PENDING_STATE; + currentURI -= 2; + svgFrame.showSVGDocument((String)visitedURIs.get(currentURI + 1)); + } + + /** + * Whether it is possible to go back. + */ + public boolean canGoBack() { + return currentURI > 0; + } + + /** + * Goes forward of one position in the history. + * Assumes that canGoForward() is true. + */ + public void forward() { + update(); + state = FORWARD_PENDING_STATE; + svgFrame.showSVGDocument((String)visitedURIs.get(currentURI + 1)); + } + + /** + * Whether it is possible to go forward. + */ + public boolean canGoForward() { + return currentURI < visitedURIs.size() - 1; + } + + /** + * Reloads the current document. + */ + public void reload() { + update(); + state = RELOAD_PENDING_STATE; + currentURI--; + svgFrame.showSVGDocument((String)visitedURIs.get(currentURI + 1)); + } + + /** + * Updates the history. + * @param uri The URI of the document just loaded. + */ + public void update(String uri) { + if (currentURI < -1) { + throw new IllegalStateException("Unexpected currentURI:" + currentURI ); + } + state = STABLE_STATE; + if (++currentURI < visitedURIs.size()) { + if (!visitedURIs.get(currentURI).equals(uri)) { + int len = menu.getItemCount(); + for (int i = len - 1; i >= index + currentURI + 1; i--) { + JMenuItem mi = menu.getItem(i); + group.remove(mi); + menu.remove(i); + } + visitedURIs = visitedURIs.subList(0, currentURI + 1); + } + JMenuItem mi = menu.getItem(index + currentURI); + group.remove(mi); + menu.remove(index + currentURI); + visitedURIs.set(currentURI, uri); + } else { + if (visitedURIs.size() >= 15) { + visitedURIs.remove(0); + JMenuItem mi = menu.getItem(index); + group.remove(mi); + menu.remove(index); + currentURI--; + } + visitedURIs.add(uri); + } + + // Computes the button text. + String text = uri; + int i = uri.lastIndexOf('/'); + if (i == -1) { + i = uri.lastIndexOf('\\' ); + } + + if (i != -1) { + text = uri.substring(i + 1); + } + + JMenuItem mi = new JRadioButtonMenuItem(text); + mi.setToolTipText(uri); + mi.setActionCommand(uri); + mi.addActionListener(actionListener); + group.add(mi); + mi.setSelected(true); + menu.insert(mi, index + currentURI); + } + + /** + * Updates the state of this history. + */ + protected void update() { + switch (state) { + case BACK_PENDING_STATE: + currentURI += 2; + break; + case RELOAD_PENDING_STATE: + currentURI++; + break; + case FORWARD_PENDING_STATE: + // fall-through intended + case STABLE_STATE: + } + } + + /** + * To listen to the radio buttons. + */ + protected class RadioListener + implements ActionListener { + + protected RadioListener() { + } + + public void actionPerformed( ActionEvent e ) { + String uri = e.getActionCommand(); + currentURI = getItemIndex( (JMenuItem)e.getSource() ) - 1; + svgFrame.showSVGDocument( uri ); + } + + public int getItemIndex( JMenuItem item ) { + int ic = menu.getItemCount(); + for ( int i = index; i < ic; i++ ) { + if ( menu.getItem( i ) == item ) { + return i - index; + } + } + throw new IllegalArgumentException("MenuItem is not from my menu!" ); + } + } +} Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/Main.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/Main.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/Main.java 8 Apr 2013 10:55:07 -0000 1.1 @@ -0,0 +1,1023 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; +import java.net.Authenticator; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.StringTokenizer; +import java.util.Vector; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ImageIcon; +import javax.swing.JOptionPane; +import javax.swing.JProgressBar; +import javax.swing.UIManager; +import javax.swing.plaf.FontUIResource; + +import org.apache.batik.swing.JSVGCanvas; +import org.apache.batik.swing.gvt.GVTTreeRendererAdapter; +import org.apache.batik.swing.gvt.GVTTreeRendererEvent; +import org.apache.batik.swing.svg.GVTTreeBuilderAdapter; +import org.apache.batik.swing.svg.GVTTreeBuilderEvent; +import org.apache.batik.swing.svg.SVGDocumentLoaderAdapter; +import org.apache.batik.swing.svg.SVGDocumentLoaderEvent; +import org.apache.batik.util.ApplicationSecurityEnforcer; +import org.apache.batik.util.Platform; +import org.apache.batik.util.ParsedURL; +import org.apache.batik.util.SVGConstants; +import org.apache.batik.util.XMLResourceDescriptor; +import org.apache.batik.util.resources.ResourceManager; + +/** + * This class contains the main method of an SVG viewer. + * + * @author Stephane Hillion + * @version $Id: Main.java,v 1.1 2013/04/08 10:55:07 marcin Exp $ + */ +public class Main implements Application { + /** + * Extension used in addition to the scriptType value + * to read from the PreferenceManager whether or not the + * scriptType can be loaded. + */ + public static final String UNKNOWN_SCRIPT_TYPE_LOAD_KEY_EXTENSION + = ".load"; + + /** + * User home property + */ + public static final String PROPERTY_USER_HOME = "user.home"; + + /** + * System property for specifying an additional policy file. + */ + public static final String PROPERTY_JAVA_SECURITY_POLICY + = "java.security.policy"; + + /** + * Batik configuration sub-directory + */ + public static final String BATIK_CONFIGURATION_SUBDIRECTORY = ".batik"; + + /** + * Name of the Squiggle configuration file + */ + public static final String SQUIGGLE_CONFIGURATION_FILE = "preferences.xml"; + + /** + * Name of the Squiggle policy file + */ + public static final String SQUIGGLE_POLICY_FILE = "__svgbrowser.policy"; + + /** + * Entry for granting network access to scripts + */ + public static final String POLICY_GRANT_SCRIPT_NETWORK_ACCESS + = "grant {\n permission java.net.SocketPermission \"*\", \"listen, connect, resolve, accept\";\n};\n\n"; + + /** + * Entry for granting file system access to scripts + */ + public static final String POLICY_GRANT_SCRIPT_FILE_ACCESS + = "grant {\n permission java.io.FilePermission \"<>\", \"read\";\n};\n\n"; + + /** + * Entry for the list of recently visited URI + */ + public static final String PREFERENCE_KEY_VISITED_URI_LIST + = "preference.key.visited.uri.list"; + + /** + * Entry for the maximum number of last visited URIs + */ + public static final String PREFERENCE_KEY_VISITED_URI_LIST_LENGTH + = "preference.key.visited.uri.list.length"; + + /** + * List of separators between URI values in the preference + * file + */ + public static final String URI_SEPARATOR = " "; + + /** + * Default font-family value. + */ + public static final String DEFAULT_DEFAULT_FONT_FAMILY + = "Arial, Helvetica, sans-serif"; + + /** + * SVG initialization file, used to trigger loading of most of + * the Batik classes + */ + public static final String SVG_INITIALIZATION = "resources/init.svg"; + + /** + * Stores the initialization file URI + */ + protected String svgInitializationURI; + + /** + * Creates a viewer frame and shows it.. + * @param args The command-line arguments. + */ + public static void main(String[] args) { + new Main(args); + } + + /** + * The gui resources file name + */ + public static final String RESOURCES = + "org.apache.batik.apps.svgbrowser.resources.Main"; + + /** + * URL for Squiggle's security policy file + */ + public static final String SQUIGGLE_SECURITY_POLICY + = "org/apache/batik/apps/svgbrowser/resources/svgbrowser.policy"; + + /** + * The resource bundle + */ + protected static ResourceBundle bundle; + + /** + * The resource manager + */ + protected static ResourceManager resources; + static { + bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault()); + resources = new ResourceManager(bundle); + } + + /** + * The frame's icon. + */ + protected static ImageIcon frameIcon = new ImageIcon + (Main.class.getResource(resources.getString("Frame.icon"))); + + /** + * The preference manager. + */ + protected XMLPreferenceManager preferenceManager; + + /** + * Maximum number of recently visited URIs + */ + public static final int MAX_VISITED_URIS = 10; + + /** + * The array of last visited URIs + */ + protected Vector lastVisited = new Vector(); + + /** + * The actual allowed maximum number of last visited URIs + */ + protected int maxVisitedURIs = MAX_VISITED_URIS; + + /** + * The arguments. + */ + protected String[] arguments; + + /** + * Controls whether the application can override the + * system security policy property. This is done when there + * was no initial security policy specified when the application + * started, in which case Batik will use that property. + */ + protected boolean overrideSecurityPolicy = false; + + /** + * Script security enforcement is delegated to the + * security utility + */ + protected ApplicationSecurityEnforcer securityEnforcer; + + /** + * The option handlers. + */ + protected Map handlers = new HashMap(); + { + handlers.put("-font-size", new FontSizeHandler()); + } + + /** + * The viewer frames. + */ + protected List viewerFrames = new LinkedList(); + + /** + * The preference dialog. + */ + protected PreferenceDialog preferenceDialog; + + /** + * The UI specialization to use in the JSVGViewerFrames. + */ + protected String uiSpecialization; + + /** + * Creates a new application. + * @param args The command-line arguments. + */ + public Main(String[] args) { + arguments = args; + + if (Platform.isOSX) { + uiSpecialization = "OSX"; + + // Move the menu bars to the top of the screen. + System.setProperty("apple.laf.useScreenMenuBar", "true"); + + // Register listeners for the About and Preferences menu items + // in the application menu (using reflection). + try { + Class Application = Class.forName("com.apple.eawt.Application"); + Class ApplicationListener = + Class.forName("com.apple.eawt.ApplicationListener"); + Class ApplicationEvent = + Class.forName("com.apple.eawt.ApplicationEvent"); + + Method getApplication = Application.getMethod("getApplication", + new Class[0]); + Method addApplicationListener = + Application.getMethod("addApplicationListener", + new Class[] { ApplicationListener }); + final Method setHandled = + ApplicationEvent.getMethod("setHandled", + new Class[] { Boolean.TYPE }); + Method setEnabledPreferencesMenu = + Application.getMethod("setEnabledPreferencesMenu", + new Class[] { Boolean.TYPE }); + + InvocationHandler listenerHandler = new InvocationHandler() { + public Object invoke(Object proxy, Method method, + Object[] args) { + String name = method.getName(); + if (name.equals("handleAbout")) { + JSVGViewerFrame relativeTo = + viewerFrames.isEmpty() + ? null + : (JSVGViewerFrame) viewerFrames.get(0); + AboutDialog dlg = new AboutDialog(relativeTo); + // Work around pack() bug on some platforms + dlg.setSize(dlg.getPreferredSize()); + dlg.setLocationRelativeTo(relativeTo); + dlg.setVisible(true); + dlg.toFront(); + } else if (name.equals("handlePreferences")) { + JSVGViewerFrame relativeTo = + viewerFrames.isEmpty() + ? null + : (JSVGViewerFrame) viewerFrames.get(0); + showPreferenceDialog(relativeTo); + } else if (name.equals("handleQuit")) { + // Do nothing, let the OS quit the app. + } else { + return null; + } + try { + setHandled.invoke(args[0], + new Object[] { Boolean.TRUE }); + } catch (Exception e) { + } + return null; + } + }; + + Object application = getApplication.invoke(null, (Object[]) null); + setEnabledPreferencesMenu.invoke(application, + new Object[] { Boolean.TRUE }); + Object listener = + Proxy.newProxyInstance(Main.class.getClassLoader(), + new Class[] { ApplicationListener }, + listenerHandler); + addApplicationListener.invoke(application, + new Object[] { listener }); + } catch (Exception ex) { + ex.printStackTrace(); + uiSpecialization = null; + } + } + + // + // Preferences + // + Map defaults = new HashMap(11); + + defaults.put(PreferenceDialog.PREFERENCE_KEY_LANGUAGES, + Locale.getDefault().getLanguage()); + defaults.put(PreferenceDialog.PREFERENCE_KEY_SHOW_RENDERING, + Boolean.FALSE); + defaults.put(PreferenceDialog.PREFERENCE_KEY_AUTO_ADJUST_WINDOW, + Boolean.TRUE); + defaults.put(PreferenceDialog.PREFERENCE_KEY_SELECTION_XOR_MODE, + Boolean.FALSE); + defaults.put(PreferenceDialog.PREFERENCE_KEY_ENABLE_DOUBLE_BUFFERING, + Boolean.TRUE); + defaults.put(PreferenceDialog.PREFERENCE_KEY_SHOW_DEBUG_TRACE, + Boolean.FALSE); + defaults.put(PreferenceDialog.PREFERENCE_KEY_PROXY_HOST, + ""); + defaults.put(PreferenceDialog.PREFERENCE_KEY_PROXY_PORT, + ""); + defaults.put(PreferenceDialog.PREFERENCE_KEY_CSS_MEDIA, + "screen"); + defaults.put(PreferenceDialog.PREFERENCE_KEY_DEFAULT_FONT_FAMILY, + DEFAULT_DEFAULT_FONT_FAMILY); + defaults.put(PreferenceDialog.PREFERENCE_KEY_IS_XML_PARSER_VALIDATING, + Boolean.FALSE); + defaults.put(PreferenceDialog.PREFERENCE_KEY_ENFORCE_SECURE_SCRIPTING, + Boolean.TRUE); + defaults.put(PreferenceDialog.PREFERENCE_KEY_GRANT_SCRIPT_FILE_ACCESS, + Boolean.FALSE); + defaults.put(PreferenceDialog.PREFERENCE_KEY_GRANT_SCRIPT_NETWORK_ACCESS, + Boolean.FALSE); + defaults.put(PreferenceDialog.PREFERENCE_KEY_LOAD_JAVA, + Boolean.TRUE); + defaults.put(PreferenceDialog.PREFERENCE_KEY_LOAD_ECMASCRIPT, + Boolean.TRUE); + defaults.put(PreferenceDialog.PREFERENCE_KEY_ALLOWED_SCRIPT_ORIGIN, + new Integer(ResourceOrigin.DOCUMENT)); + defaults.put(PreferenceDialog.PREFERENCE_KEY_ALLOWED_EXTERNAL_RESOURCE_ORIGIN, + new Integer(ResourceOrigin.ANY)); + defaults.put(PREFERENCE_KEY_VISITED_URI_LIST, + ""); + defaults.put(PREFERENCE_KEY_VISITED_URI_LIST_LENGTH, + new Integer(MAX_VISITED_URIS)); + defaults.put(PreferenceDialog.PREFERENCE_KEY_ANIMATION_RATE_LIMITING_MODE, + new Integer(1)); + defaults.put(PreferenceDialog.PREFERENCE_KEY_ANIMATION_RATE_LIMITING_CPU, + new Float(0.75f)); + defaults.put(PreferenceDialog.PREFERENCE_KEY_ANIMATION_RATE_LIMITING_FPS, + new Float(10)); + defaults.put(PreferenceDialog.PREFERENCE_KEY_USER_STYLESHEET_ENABLED, + Boolean.TRUE); + + securityEnforcer + = new ApplicationSecurityEnforcer(this.getClass(), + SQUIGGLE_SECURITY_POLICY); + + + try { + preferenceManager = new XMLPreferenceManager(SQUIGGLE_CONFIGURATION_FILE, + defaults); + String dir = System.getProperty(PROPERTY_USER_HOME); + File f = new File(dir, BATIK_CONFIGURATION_SUBDIRECTORY); + f.mkdir(); + XMLPreferenceManager.setPreferenceDirectory(f.getCanonicalPath()); + preferenceManager.load(); + setPreferences(); + initializeLastVisited(); + Authenticator.setDefault(new JAuthenticator()); + } catch (Exception e) { + e.printStackTrace(); + } + + // + // Initialization + // + final AboutDialog initDialog = new AboutDialog(); + ((BorderLayout) initDialog.getContentPane().getLayout()).setVgap(8); + final JProgressBar pb = new JProgressBar(0, 3); + initDialog.getContentPane().add(pb, BorderLayout.SOUTH); + + // Work around pack() bug on some platforms + Dimension ss = initDialog.getToolkit().getScreenSize(); + Dimension ds = initDialog.getPreferredSize(); + + initDialog.setLocation((ss.width - ds.width) / 2, + (ss.height - ds.height) / 2); + + initDialog.setSize(ds); + initDialog.setVisible(true); + + final JSVGViewerFrame v = new JSVGViewerFrame(this); + JSVGCanvas c = v.getJSVGCanvas(); + c.addSVGDocumentLoaderListener(new SVGDocumentLoaderAdapter() { + public void documentLoadingStarted(SVGDocumentLoaderEvent e) { + pb.setValue(1); + } + public void documentLoadingCompleted(SVGDocumentLoaderEvent e) { + pb.setValue(2); + } + }); + c.addGVTTreeBuilderListener(new GVTTreeBuilderAdapter() { + public void gvtBuildCompleted(GVTTreeBuilderEvent e) { + pb.setValue(3); + } + }); + c.addGVTTreeRendererListener(new GVTTreeRendererAdapter() { + public void gvtRenderingCompleted(GVTTreeRendererEvent e) { + initDialog.dispose(); + v.dispose(); + System.gc(); + run(); + } + }); + + c.setSize(100, 100); + svgInitializationURI = Main.class.getResource(SVG_INITIALIZATION).toString(); + c.loadSVGDocument(svgInitializationURI); + } + + /** + * Installs a custom policy file in the '.batik' directory. This is initialized + * with the content of the policy file coming with the distribution + */ + public void installCustomPolicyFile() throws IOException { + String securityPolicyProperty + = System.getProperty(PROPERTY_JAVA_SECURITY_POLICY); + + if (overrideSecurityPolicy + || + securityPolicyProperty == null + || + "".equals(securityPolicyProperty)) { + // Access default policy file + ParsedURL policyURL = new ParsedURL(securityEnforcer.getPolicyURL()); + + // Override the user policy + String dir = System.getProperty(PROPERTY_USER_HOME); + File batikConfigDir = new File(dir, BATIK_CONFIGURATION_SUBDIRECTORY); + File policyFile = new File(batikConfigDir, SQUIGGLE_POLICY_FILE); + + // Copy original policy file into local policy file + Reader r = new BufferedReader(new InputStreamReader(policyURL.openStream())); + Writer w = new FileWriter(policyFile); + + char[] buf = new char[1024]; + int n = 0; + while ( (n=r.read(buf, 0, buf.length)) != -1 ) { + w.write(buf, 0, n); + } + + r.close(); + + // Now, append additional grants depending on the security + // settings + boolean grantScriptNetworkAccess + = preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_GRANT_SCRIPT_NETWORK_ACCESS); + boolean grantScriptFileAccess + = preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_GRANT_SCRIPT_FILE_ACCESS); + + if (grantScriptNetworkAccess) { + w.write(POLICY_GRANT_SCRIPT_NETWORK_ACCESS); + } + + if (grantScriptFileAccess) { + w.write(POLICY_GRANT_SCRIPT_FILE_ACCESS); + } + + w.close(); + + // We now use the JAVA_SECURITY_POLICY property, so + // we allow override on subsequent calls. + overrideSecurityPolicy = true; + + System.setProperty(PROPERTY_JAVA_SECURITY_POLICY, + policyFile.toURL().toString()); + + } + } + + /** + * Runs the application. + */ + public void run() { + try { + int i = 0; + + for (; i < arguments.length; i++) { + OptionHandler oh = (OptionHandler)handlers.get(arguments[i]); + if (oh == null) { + break; + } + i = oh.handleOption(i); + } + + JSVGViewerFrame frame = createAndShowJSVGViewerFrame(); + while (i < arguments.length) { + if (arguments[i].length() == 0) { + i++; + continue; + } + + File file = new File(arguments[i]); + String uri = null; + + try{ + if (file.canRead()) { + uri = file.toURL().toString(); + } + }catch(SecurityException se){ + // Cannot access files. + } + + if(uri == null){ + uri = arguments[i]; + ParsedURL purl = null; + purl = new ParsedURL(arguments[i]); + + if (!purl.complete()) + // This is not a valid uri + uri = null; + } + + if (uri != null) { + if (frame == null) + frame = createAndShowJSVGViewerFrame(); + + frame.showSVGDocument(uri); + frame = null; + } else { + // Let the user know that we are + // skipping this file... + + // Note that frame may be null, which is + // a valid argument for showMessageDialog + + // NOTE: Need to revisit Resources/Messages usage to + // have a single entry point. Should have a + // formated message here instead of a + ... + JOptionPane.showMessageDialog + (frame, + resources.getString("Error.skipping.file") + + arguments[i]); + } + i++; + } + } catch (Exception e) { + e.printStackTrace(); + printUsage(); + } + } + + /** + * Prints the command line usage. + */ + protected void printUsage() { + System.out.println(); + + System.out.println(resources.getString("Command.header")); + System.out.println(resources.getString("Command.syntax")); + System.out.println(); + System.out.println(resources.getString("Command.options")); + Iterator it = handlers.keySet().iterator(); + while (it.hasNext()) { + String s = (String)it.next(); + System.out.println(((OptionHandler)handlers.get(s)).getDescription()); + } + } + + /** + * This interface represents an option handler. + */ + protected interface OptionHandler { + /** + * Handles the current option. + * @return the index of argument just before the next one to handle. + */ + int handleOption(int i); + + /** + * Returns the option description. + */ + String getDescription(); + } + + /** + * To handle the '-font-size' option. + */ + protected class FontSizeHandler implements OptionHandler { + public int handleOption(int i) { + int size = Integer.parseInt(arguments[++i]); + + Font font = new Font("Dialog", Font.PLAIN, size); + FontUIResource fontRes = new FontUIResource(font); + UIManager.put("CheckBox.font", fontRes); + UIManager.put("PopupMenu.font", fontRes); + UIManager.put("TextPane.font", fontRes); + UIManager.put("MenuItem.font", fontRes); + UIManager.put("ComboBox.font", fontRes); + UIManager.put("Button.font", fontRes); + UIManager.put("Tree.font", fontRes); + UIManager.put("ScrollPane.font", fontRes); + UIManager.put("TabbedPane.font", fontRes); + UIManager.put("EditorPane.font", fontRes); + UIManager.put("TitledBorder.font", fontRes); + UIManager.put("Menu.font", fontRes); + UIManager.put("TextArea.font", fontRes); + UIManager.put("OptionPane.font", fontRes); + UIManager.put("DesktopIcon.font", fontRes); + UIManager.put("MenuBar.font", fontRes); + UIManager.put("ToolBar.font", fontRes); + UIManager.put("RadioButton.font", fontRes); + UIManager.put("RadioButtonMenuItem.font", fontRes); + UIManager.put("ToggleButton.font", fontRes); + UIManager.put("ToolTip.font", fontRes); + UIManager.put("ProgressBar.font", fontRes); + UIManager.put("TableHeader.font", fontRes); + UIManager.put("Panel.font", fontRes); + UIManager.put("List.font", fontRes); + UIManager.put("ColorChooser.font", fontRes); + UIManager.put("PasswordField.font", fontRes); + UIManager.put("TextField.font", fontRes); + UIManager.put("Table.font", fontRes); + UIManager.put("Label.font", fontRes); + UIManager.put("InternalFrameTitlePane.font", fontRes); + UIManager.put("CheckBoxMenuItem.font", fontRes); + + return i; + } + public String getDescription() { + return resources.getString("Command.font-size"); + } + } + + // Application /////////////////////////////////////////////// + + /** + * Creates and shows a new viewer frame. + */ + public JSVGViewerFrame createAndShowJSVGViewerFrame() { + JSVGViewerFrame mainFrame = new JSVGViewerFrame(this); + mainFrame.setSize(resources.getInteger("Frame.width"), + resources.getInteger("Frame.height")); + mainFrame.setIconImage(frameIcon.getImage()); + mainFrame.setTitle(resources.getString("Frame.title")); + mainFrame.setVisible(true); + viewerFrames.add(mainFrame); + setPreferences(mainFrame); + return mainFrame; + } + + /** + * Closes the given viewer frame. + */ + public void closeJSVGViewerFrame(JSVGViewerFrame f) { + f.getJSVGCanvas().stopProcessing(); + viewerFrames.remove(f); + if (viewerFrames.size() == 0) { + System.exit(0); + } + f.dispose(); + } + + /** + * Creates a new application exit action. + */ + public Action createExitAction(JSVGViewerFrame vf) { + return new AbstractAction() { + public void actionPerformed(ActionEvent e) { + System.exit(0); + } + }; + } + + /** + * Opens the given link in a new window. + */ + public void openLink(String url) { + JSVGViewerFrame f = createAndShowJSVGViewerFrame(); + f.getJSVGCanvas().loadSVGDocument(url); + } + + /** + * Returns the XML parser class name. + */ + public String getXMLParserClassName() { + return XMLResourceDescriptor.getXMLParserClassName(); + } + + /** + * Returns true if the XML parser must be in validation mode, false + * otherwise. + */ + public boolean isXMLParserValidating() { + return preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_IS_XML_PARSER_VALIDATING); + } + + /** + * Shows the preference dialog. + */ + public void showPreferenceDialog(JSVGViewerFrame f) { + if (preferenceDialog == null) { + preferenceDialog = new PreferenceDialog(f, preferenceManager); + } + if (preferenceDialog.showDialog() == PreferenceDialog.OK_OPTION) { + try { + preferenceManager.save(); + setPreferences(); + } catch (Exception e) { + } + } + } + + private void setPreferences() throws IOException { + Iterator it = viewerFrames.iterator(); + while (it.hasNext()) { + setPreferences((JSVGViewerFrame)it.next()); + } + + System.setProperty("proxyHost", preferenceManager.getString + (PreferenceDialog.PREFERENCE_KEY_PROXY_HOST)); + System.setProperty("proxyPort", preferenceManager.getString + (PreferenceDialog.PREFERENCE_KEY_PROXY_PORT)); + + installCustomPolicyFile(); + + securityEnforcer.enforceSecurity + (preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_ENFORCE_SECURE_SCRIPTING) + ); + + } + + private void setPreferences(JSVGViewerFrame vf) { + boolean db = preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_ENABLE_DOUBLE_BUFFERING); + vf.getJSVGCanvas().setDoubleBufferedRendering(db); + boolean sr = preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_SHOW_RENDERING); + vf.getJSVGCanvas().setProgressivePaint(sr); + boolean d = preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_SHOW_DEBUG_TRACE); + vf.setDebug(d); + boolean aa = preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_AUTO_ADJUST_WINDOW); + vf.setAutoAdjust(aa); + boolean dd = preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_SELECTION_XOR_MODE); + vf.getJSVGCanvas().setSelectionOverlayXORMode(dd); + int al = preferenceManager.getInteger + (PreferenceDialog.PREFERENCE_KEY_ANIMATION_RATE_LIMITING_MODE); + if (al < 0 || al > 2) { + al = 1; + } + switch (al) { + case 0: // none + vf.getJSVGCanvas().setAnimationLimitingNone(); + break; + case 1: { // %cpu + float pc = preferenceManager.getFloat + (PreferenceDialog.PREFERENCE_KEY_ANIMATION_RATE_LIMITING_CPU); + if (pc <= 0f || pc > 1.0f) { + pc = 0.75f; + } + vf.getJSVGCanvas().setAnimationLimitingCPU(pc); + break; + } + case 2: { // fps + float fps = preferenceManager.getFloat + (PreferenceDialog.PREFERENCE_KEY_ANIMATION_RATE_LIMITING_FPS); + if (fps <= 0f) { + fps = 10f; + } + vf.getJSVGCanvas().setAnimationLimitingFPS(fps); + break; + } + } + } + + /** + * Returns the user languages. + */ + public String getLanguages() { + String s = preferenceManager.getString + (PreferenceDialog.PREFERENCE_KEY_LANGUAGES); + return (s == null) + ? Locale.getDefault().getLanguage() + : s; + } + + /** + * Returns the user stylesheet uri. + * @return null if no user style sheet was specified. + */ + public String getUserStyleSheetURI() { + boolean enabled = preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_USER_STYLESHEET_ENABLED); + String ssPath = preferenceManager.getString + (PreferenceDialog.PREFERENCE_KEY_USER_STYLESHEET); + if (!enabled || ssPath.length() == 0) { + return null; + } + try { + File f = new File(ssPath); + if (f.exists()) { + return f.toURL().toString(); + } + } catch (IOException ioe) { + // Nothing... + } + return ssPath; + } + + /** + * Returns the default value for the CSS + * "font-family" property + */ + public String getDefaultFontFamily() { + return preferenceManager.getString + (PreferenceDialog.PREFERENCE_KEY_DEFAULT_FONT_FAMILY); + } + + /** + * Returns the CSS media to use. + * @return empty string if no CSS media was specified. + */ + public String getMedia() { + String s = preferenceManager.getString + (PreferenceDialog.PREFERENCE_KEY_CSS_MEDIA); + return (s == null) ? "screen" : s; + } + + /** + * Returns true if the selection overlay is painted in XOR mode, false + * otherwise. + */ + public boolean isSelectionOverlayXORMode() { + return preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_SELECTION_XOR_MODE); + } + + /** + * Returns true if the input scriptType can be loaded in + * this application. + */ + public boolean canLoadScriptType(String scriptType){ + if (SVGConstants.SVG_SCRIPT_TYPE_ECMASCRIPT.equals(scriptType) + || SVGConstants.SVG_SCRIPT_TYPE_APPLICATION_ECMASCRIPT + .equals(scriptType) + || SVGConstants.SVG_SCRIPT_TYPE_JAVASCRIPT.equals(scriptType) + || SVGConstants.SVG_SCRIPT_TYPE_APPLICATION_JAVASCRIPT + .equals(scriptType)) { + return preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_LOAD_ECMASCRIPT); + } else if (SVGConstants.SVG_SCRIPT_TYPE_JAVA.equals(scriptType)) { + return preferenceManager.getBoolean + (PreferenceDialog.PREFERENCE_KEY_LOAD_JAVA); + } else { + return preferenceManager.getBoolean + (scriptType + UNKNOWN_SCRIPT_TYPE_LOAD_KEY_EXTENSION); + } + } + + /** + * Returns the allowed origins for scripts. + * @see ResourceOrigin + */ + public int getAllowedScriptOrigin() { + int ret = preferenceManager.getInteger + (PreferenceDialog.PREFERENCE_KEY_ALLOWED_SCRIPT_ORIGIN); + + return ret; + } + + /** + * Returns the allowed origins for external + * resources. + * @see ResourceOrigin + */ + public int getAllowedExternalResourceOrigin() { + int ret = preferenceManager.getInteger + (PreferenceDialog.PREFERENCE_KEY_ALLOWED_EXTERNAL_RESOURCE_ORIGIN); + + return ret; + } + + /** + * Notifies Application of recently visited URI + */ + public void addVisitedURI(String uri) { + if(svgInitializationURI.equals(uri)) { + return; + } + + int maxVisitedURIs = + preferenceManager.getInteger + (PREFERENCE_KEY_VISITED_URI_LIST_LENGTH); + + if (maxVisitedURIs < 0) { + maxVisitedURIs = 0; + } + + if (lastVisited.contains(uri)) { + lastVisited.removeElement(uri); + } + + while (lastVisited.size() > 0 && lastVisited.size() > (maxVisitedURIs-1)) { + lastVisited.removeElementAt(0); + } + + if (maxVisitedURIs > 0) { + lastVisited.addElement(uri); + } + + // Now, save the list of visited URL into the preferences + StringBuffer lastVisitedBuffer = new StringBuffer( lastVisited.size() * 8 ); + + for (int i=0; i maxVisitedURIs) { + n = maxVisitedURIs; + } + + for (int i=0; i= 0; i--) { + Node newAttr = newNodeMap.item(i); + String qualifiedName = newAttr.getNodeName(); + String attributeValue = newAttr.getNodeValue(); + String prefix = DOMUtilities.getPrefix(qualifiedName); + String namespaceURI = getNamespaceURI(prefix); + elem.setAttributeNS(namespaceURI, qualifiedName, attributeValue); + } + } + + /** + * Replaces all of the atributes of a given element with the values from the + * given table model. + * + * @param element + * The node whose attributes should update + * @param tableModel + * The tableModel from which to get attributes + */ + private void updateElementAttributes + (Element element, AttributesTableModel tableModel) { + + // Remove all element attributes + removeAttributes(element); + + // Copy all the attribute name - value pairs from the table model to + // the given element + for (int i = 0; i < tableModel.getRowCount(); i++) { + String newAttrName = (String) tableModel.getAttrNameAt(i); + String newAttrValue = (String) tableModel.getAttrValueAt(i); + if (newAttrName != null && newAttrName.length() > 0) { + String namespaceURI; + if (newAttrName.equals(XMLConstants.XMLNS_PREFIX)) { + namespaceURI = XMLConstants.XMLNS_NAMESPACE_URI; + } else { + String prefix = DOMUtilities.getPrefix(newAttrName); + namespaceURI = getNamespaceURI(prefix); + } + if (newAttrValue != null) { + element.setAttributeNS + (namespaceURI, newAttrName, newAttrValue); + } else { + element.setAttributeNS(namespaceURI, newAttrName, ""); + } + } + } + } + + /** + * Removes all the attributes from an element. + * + * @param element + * The given element + */ + private void removeAttributes(Element element) { + NamedNodeMap oldNodeMap = element.getAttributes(); + int n = oldNodeMap.getLength(); + for (int i = n - 1; i >= 0; i--) { + element.removeAttributeNode((Attr) oldNodeMap.item(i)); + } + } + + /** + * Looks up for the namespaceURI based on the given prefix. Uses the + * Node.lookupNamespaceURI method, starting from the parent element of + * the element being edited / created. + * + * @param prefix + * The given prefix + * @return namespaceURI or null + */ + private String getNamespaceURI(String prefix) { + String namespaceURI = null; + if (prefix != null) { + if (prefix.equals(SVGConstants.XMLNS_PREFIX)) { + namespaceURI = SVGConstants.XMLNS_NAMESPACE_URI; + } else { + AbstractNode n; + if (mode == EDIT_MODE) { + n = (AbstractNode) previewElement; + namespaceURI = n.lookupNamespaceURI(prefix); + } else if (mode == ADD_NEW_ELEMENT) { + n = (AbstractNode) parentElement; + namespaceURI = n.lookupNamespaceURI(prefix); + } + + } + } + return namespaceURI; + } + + /** + * Fills the attributesTable with the given element attribute name - value + * pairs. + * + * @param elem + * The given element + */ + private void updateAttributesTable(Element elem) { + NamedNodeMap map = elem.getAttributes(); + AttributesTableModel tableModel = + (AttributesTableModel) attributesTable.getModel(); + // Remove and update rows from the table if needed... + for (int i = tableModel.getRowCount() - 1; i >= 0; i--) { + String attrName = (String) tableModel.getValueAt(i, 0); + String newAttrValue = ""; + if (attrName != null) { + newAttrValue = elem.getAttributeNS(null, attrName); + } + if (attrName == null || newAttrValue.length() == 0) { + tableModel.removeRow(i); + } + if (newAttrValue.length() > 0) { + tableModel.setValueAt(newAttrValue, i, 1); + } + } + + // Add rows + for (int i = 0; i < map.getLength(); i++) { + Node attr = map.item(i); + String attrName = attr.getNodeName(); + String attrValue = attr.getNodeValue(); + if (tableModel.getValueForName(attrName) == null) { + Vector rowData = new Vector(); + rowData.add(attrName); + rowData.add(attrValue); + tableModel.addRow(rowData); + } + } + } + + /** + * Shows node's String representation in svgInputPanel + * + * @param node + * The given node + */ + private void updateNodeXmlArea(Node node) { + getSvgInputPanel().getNodeXmlArea().setText(DOMUtilities.getXML(node)); + } + + /** + * Getter for the preivewElement. + * + * @return the preivewElement + */ + private Element getPreviewElement() { + return previewElement; + } + + /** + * Sets the preview element. Enters the view mode and updates the associated + * components. + * + * @param elem + * the element to set + */ + public void setPreviewElement(Element elem) { + if (previewElement != elem && isDirty) { + if (!promptForChanges()) { + return; + } + } + + this.previewElement = elem; + enterViewMode(); + + updateNodeXmlArea(elem); + updateAttributesTable(elem); + } + + /** + * Invoked by the {@link DOMViewer} to inform the + * NodePickerPanel that it is being hidden. + */ + boolean panelHiding() { + return !isDirty || promptForChanges(); + } + + /** + * Gets the current working mode. + * + * @return the mode + */ + private int getMode() { + return mode; + } + + /** + * Enters the view mode. + */ + public void enterViewMode() { + if (mode != VIEW_MODE) { + mode = VIEW_MODE; + // Disable appropriate buttons + getApplyButton().setEnabled(false); + getResetButton().setEnabled(false); + // Enable the remove and add buttons + getRemoveButton().setEnabled(true); + getAddButton().setEnabled(true); + // Update the isWellFormed label + String isWellFormedLabelVal = + resources.getString("IsWellFormedLabel.wellFormed"); + isWellFormedLabel.setText(isWellFormedLabelVal); + } + } + + /** + * Enters the edit mode. + */ + public void enterEditMode() { + if (mode != EDIT_MODE) { + mode = EDIT_MODE; + clonedElement = (Element) previewElement.cloneNode(true); + + // Enable appropriate buttons + getApplyButton().setEnabled(true); + getResetButton().setEnabled(true); + } + } + + /** + * Enters the add new element mode. + * + * @param newElement + * The element to be added + * @param parent + * The parent node of the element to be added + */ + public void enterAddNewElementMode(Element newElement, Node parent) { + if (mode != ADD_NEW_ELEMENT) { + mode = ADD_NEW_ELEMENT; + previewElement = newElement; + clonedElement = (Element) newElement.cloneNode(true); + parentElement = parent; + // Update the appropriate areas + updateNodeXmlArea(newElement); + // Enable appropriate buttons + getApplyButton().setEnabled(true); + getResetButton().setEnabled(true); +// // Request focus +// getSvgInputPanel().getNodeXmlArea().requestFocusInWindow(); + } + } + + /** + * Updates the panel when DOM Mutation event occures. + */ + public void updateOnDocumentChange(String mutationEventType, Node targetNode) { + if (mode == VIEW_MODE) { + if (this.isShowing() && + shouldUpdate(mutationEventType, + targetNode, + getPreviewElement())) { + setPreviewElement(getPreviewElement()); + } + } + } + + /** + * If the panel should update its components after dom mutation event. + * Checks whether any node that is the child node of the node currently + * being previewed has changed. If true, updates the xml text area of this + * NodePicker. In case of DOMAttrModiefied mutation event, the additional + * condition is added - to check whether the attributes of an element that + * is being previewed are changed. If true, the xml text area is refreshed. + * + * @return True if should update + */ + private boolean shouldUpdate(String mutationEventType, Node affectedNode, + Node currentNode) { + if (mutationEventType.equals("DOMNodeInserted")) { + if (DOMUtilities.isAncestorOf(currentNode, affectedNode)) { + return true; + } + } else if (mutationEventType.equals("DOMNodeRemoved")) { + if (DOMUtilities.isAncestorOf(currentNode, affectedNode)) { + return true; + } + } else if (mutationEventType.equals("DOMAttrModified")) { + if (DOMUtilities.isAncestorOf(currentNode, affectedNode) + || currentNode == affectedNode) { + return true; + } + } else if (mutationEventType.equals("DOMCharDataModified")) { + if (DOMUtilities.isAncestorOf(currentNode, affectedNode)) { + return true; + } + } + return false; + } + + /** + * Parses the given xml and return parsed document's root element. + * Used to check whether the given xml is well formed. + * + * @param xmlString + * Xml as a String + * @return Element + */ + private Element parseXml(String xmlString) { + Document doc = null; + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + try { + javax.xml.parsers.DocumentBuilder parser = factory + .newDocumentBuilder(); + parser.setErrorHandler(new ErrorHandler() { + public void error(SAXParseException exception) + throws SAXException { + } + + public void fatalError(SAXParseException exception) + throws SAXException { + } + + public void warning(SAXParseException exception) + throws SAXException { + } + }); + doc = parser.parse(new InputSource(new StringReader(xmlString))); + } catch (ParserConfigurationException e1) { + } catch (SAXException e1) { + } catch (IOException e1) { + } + if (doc != null) { + return doc.getDocumentElement(); + } + return null; + } + + /** + * Sets the node picker components to be editable / uneditable. + * + * @param editable + * Whether to enable or disable edit + */ + public void setEditable(boolean editable) { + getSvgInputPanel().getNodeXmlArea().setEditable(editable); + getResetButton().setEnabled(editable); + getApplyButton().setEnabled(editable); + getAddButton().setEnabled(editable); + getRemoveButton().setEnabled(editable); + attributesTable.setEnabled(editable); + } + + /** + * Checks whether the given component is a part component of the this node + * picker. + * + * @param component + * The given component + * @return True if the given component is a part of the this NodePicker + */ + private boolean isANodePickerComponent(Component component) { + return SwingUtilities.getAncestorOfClass(NodePickerPanel.class, + component) != null; + } + + /** + * Shows a dialog to save changes. + */ + public boolean promptForChanges() { + // If the xml is well formed + if (getApplyButton().isEnabled() && isElementModified()) { + String confirmString = resources.getString("ConfirmDialog.message"); + int option = JOptionPane.showConfirmDialog(getSvgInputPanel(), + confirmString); + if (option == JOptionPane.YES_OPTION) { + getApplyButton().doClick(); + } else if (option == JOptionPane.CANCEL_OPTION) { + return false; + } else { + getResetButton().doClick(); + } + } else { + getResetButton().doClick(); + } + isDirty = false; + return true; + } + + /** + * Whether the element being edit is changed. + * + * @return True if the element being edit is changed + */ + private boolean isElementModified() { + if (getMode() == EDIT_MODE) { + return !DOMUtilities.getXML(previewElement).equals + (getSvgInputPanel().getNodeXmlArea().getText()); + } else if (getMode() == ADD_NEW_ELEMENT) { + return true; + } + return false; + } + + /** + * Manages the edits on focus events. + */ + protected class NodePickerEditListener extends FocusAdapter { + + public void focusGained(FocusEvent e) { + if (getMode() == VIEW_MODE) { + enterEditMode(); + } + setEditable(controller.isEditable() + && controller.canEdit(previewElement)); + isDirty = isElementModified(); + } + + // XXX Java 1.3 does not have getOppositeComponent() + /*public void focusLost(FocusEvent e) { + // Prompts the user to save changes that he made for an element, + // when the NodePicker loses focus + if (!isANodePickerComponent(e.getOppositeComponent()) + && !e.isTemporary() && isDirty) { + promptForChanges(); + } + }*/ + } + + /** + * Listens for the changes in the xml text area and updates this node picker + * panel if needed. + */ + protected class XMLAreaListener implements DocumentListener { + public void changedUpdate(DocumentEvent e) { + isDirty = isElementModified(); + } + + public void insertUpdate(DocumentEvent e) { + updateNodePicker(e); + isDirty = isElementModified(); + } + + public void removeUpdate(DocumentEvent e) { + updateNodePicker(e); + isDirty = isElementModified(); + } + + /** + * Updates the node picker panel after document changes. + * + * @param e + * The document event + */ + private void updateNodePicker(DocumentEvent e) { + if (getMode() == EDIT_MODE) { + updateViewAfterSvgInput + (parseXml(svgInputPanel.getNodeXmlArea().getText()), + clonedElement); + } else if (getMode() == ADD_NEW_ELEMENT) { + updateViewAfterSvgInput + (parseXml(svgInputPanel.getNodeXmlArea().getText()), + previewElement); + } + } + } + + /** + * Listens for the changes in the table and updates this node picker panel + * if needed. + */ + protected class AttributesTableModelListener implements TableModelListener { + public void tableChanged(TableModelEvent e) { + if (e.getType() == TableModelEvent.UPDATE && shouldProcessUpdate) { + updateNodePicker(e); + } + } + + /** + * Updates the node picker panel after document changes. + * + * @param e + * The document event + */ + private void updateNodePicker(TableModelEvent e) { + if (getMode() == EDIT_MODE) { + updateElementAttributes + (clonedElement, (AttributesTableModel) (e.getSource())); + updateNodeXmlArea(clonedElement); + } else if (getMode() == ADD_NEW_ELEMENT) { + updateElementAttributes + (previewElement, (AttributesTableModel) (e.getSource())); + updateNodeXmlArea(previewElement); + } + } + } + + /** + * The action associated with the 'Apply' button. + */ + protected class ApplyButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + isDirty = false; + String xmlAreaText = getResults(); + if (getMode() == EDIT_MODE) { + fireUpdateElement + (new NodePickerEvent + (NodePickerPanel.this, + xmlAreaText, + previewElement, + NodePickerEvent.EDIT_ELEMENT)); + } else if (getMode() == ADD_NEW_ELEMENT) { + fireAddNewElement + (new NodePickerEvent + (NodePickerPanel.this, + xmlAreaText, + parentElement, + NodePickerEvent.ADD_NEW_ELEMENT)); + } + enterViewMode(); + } + } + + /** + * The action associated with the 'Reset' button. + */ + protected class ResetButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + isDirty = false; + setPreviewElement(getPreviewElement()); + } + } + + /** + * The action associated with the 'Add' button. + */ + protected class AddButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + if (getMode() == VIEW_MODE) { + enterEditMode(); + } + DefaultTableModel model = + (DefaultTableModel) attributesTable.getModel(); + shouldProcessUpdate = false; + model.addRow((Vector) null); + shouldProcessUpdate = true; + } + } + + /** + * The action associated with the 'Remove' button. + */ + protected class RemoveButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + if (getMode() == VIEW_MODE) { + enterEditMode(); + } + // Find the contextElement + Element contextElement = clonedElement; + if (getMode() == ADD_NEW_ELEMENT) { + contextElement = previewElement; + } + DefaultTableModel model = + (DefaultTableModel) attributesTable.getModel(); + int[] selectedRows = attributesTable.getSelectedRows(); + for (int i = 0; i < selectedRows.length; i++) { + String attrName = (String) model.getValueAt(selectedRows[i], 0); + if (attrName != null) { + String prefix = DOMUtilities.getPrefix(attrName); + String localName = DOMUtilities.getLocalName(attrName); + String namespaceURI = getNamespaceURI(prefix); + contextElement.removeAttributeNS(namespaceURI, localName); + } + } + shouldProcessUpdate = false; + updateAttributesTable(contextElement); + shouldProcessUpdate = true; + updateNodeXmlArea(contextElement); + } + } + + /** + * Returns the action associated with the given string or null on error + * + * @param key + * the key mapped with the action to get + * @throws MissingListenerException + * if the action is not found + */ + public Action getAction(String key) throws MissingListenerException { + return (Action) listeners.get(key); + } + + /** + * The attributesTable model. + */ + public static class AttributesTableModel extends DefaultTableModel { + public AttributesTableModel(int rowCount, int columnCount) { + super(rowCount, columnCount); + } + + public String getColumnName(int column) { + if (column == 0) { + return resources.getString("AttributesTable.column1"); + } else { + return resources.getString("AttributesTable.column2"); + } + } + + /** + * Gets the value of the attribute with the given attribute name. + * + * @param attrName + * The given attribute name + */ + public Object getValueForName(Object attrName) { + for (int i = 0; i < getRowCount(); i++) { + if (getValueAt(i, 0) != null + && getValueAt(i, 0).equals(attrName)) { + return getValueAt(i, 1); + } + } + return null; + } + + /** + * Gets the name of the attribute with the table row. + */ + public Object getAttrNameAt(int i) { + return getValueAt(i, 0); + } + + /** + * Gets the value of the attribute with the table row. + */ + public Object getAttrValueAt(int i) { + return getValueAt(i, 1); + } + + /** + * Gets the first row where the given attribute name appears. + * @param attrName The given attribute name + */ + public int getRow(Object attrName) { + for (int i = 0; i < getRowCount(); i++) { + if (getValueAt(i, 0) != null + && getValueAt(i, 0).equals(attrName)) { + return i; + } + } + return -1; + } + } + + // Custom events support + /** + * Fires the updateElement event. + * + * @param event + * The associated NodePickerEvent event + */ + public void fireUpdateElement(NodePickerEvent event) { + Object[] listeners = eventListeners.getListenerList(); + + int length = listeners.length; + for (int i = 0; i < length; i += 2) { + if (listeners[i] == NodePickerListener.class) { + ((NodePickerListener) listeners[i + 1]) + .updateElement(event); + } + } + } + + /** + * Fires the AddNewElement event. + * + * @param event + * The associated NodePickerEvent event + */ + public void fireAddNewElement(NodePickerEvent event) { + Object[] listeners = eventListeners.getListenerList(); + int length = listeners.length; + for (int i = 0; i < length; i += 2) { + if (listeners[i] == NodePickerListener.class) { + ((NodePickerListener) listeners[i + 1]) + .addNewElement(event); + } + } + } + + /** + * Adds the listener to the listener list. + * + * @param listener + * The listener to add + */ + public void addListener(NodePickerListener listener) { + eventListeners.add(NodePickerListener.class, listener); + } + + /** + * Event to pass to listener. + */ + public static class NodePickerEvent extends EventObject { + + // The event types + public static final int EDIT_ELEMENT = 1; + + public static final int ADD_NEW_ELEMENT = 2; + + /** + * The type of this event. + */ + private int type; + + /** + * The string that is to be parsed. + */ + private String result; + + /** + * The context node associated with this event. + */ + private Node contextNode; + + /** + * Creates the NodePickerEvent. + * + * @param source + * The NodePicker that initiated the event + * @param result + * the NodePicker result + * @param contextNode + * the associated context node + */ + public NodePickerEvent(Object source, String result, Node contextNode, + int type) { + super(source); + this.result = result; + this.contextNode = contextNode; + } + + /** + * Gets the NodePickerPanel result. + * + * @return the result + */ + public String getResult() { + return result; + } + + /** + * Gets the context node. + * 'EDIT_ELEMENT' event type - the context node is the original element + * being previewed. + * 'ADD_NEW_ELEMENT' event type - the context node is the parent node of + * the element being added + * + * @return the context node + */ + public Node getContextNode() { + return contextNode; + } + + /** + * Gets the type of this event. + * + * @return the type + */ + public int getType() { + return type; + } + } + + /** + * Node picker listener. + */ + public static interface NodePickerListener extends EventListener { + /** + * Updates the element from the data contained in the NodePickerEvent. + */ + void updateElement(NodePickerEvent event); + + /** + * Adds the element from the data contained in the NodePickerEvent. + */ + void addNewElement(NodePickerEvent event); + } + + /** + * The adapter for the NodePicker listener. + */ + public static class NodePickerAdapter implements NodePickerListener { + + public void addNewElement(NodePickerEvent event) { + } + + public void updateElement(NodePickerEvent event) { + } + } + + /** + * The panel to view and edit the elements xml representation. + */ + protected class SVGInputPanel extends JPanel { + + /** + * The text area. + */ + protected XMLTextEditor nodeXmlArea; + + /** + * Constructor. + */ + public SVGInputPanel() { + super(new BorderLayout()); + add(new JScrollPane(getNodeXmlArea())); + } + + /** + * Gets the nodeXmlArea. + * + * @return the nodeXmlArea + */ + protected XMLTextEditor getNodeXmlArea() { + if (nodeXmlArea == null) { + // Create syntax-highlighted text area + nodeXmlArea = new XMLTextEditor(); + nodeXmlArea.setEditable(true); + } + return nodeXmlArea; + } + } + + /** + * Dialog for choosing element name. + */ + public static class NameEditorDialog extends JDialog implements ActionMap { + + /** + * The return value if 'OK' is chosen. + */ + public static final int OK_OPTION = 0; + + /** + * The return value if 'Cancel' is chosen. + */ + public static final int CANCEL_OPTION = 1; + + /** + * The resource file name. + */ + protected static final String RESOURCES = + "org.apache.batik.apps.svgbrowser.resources.NameEditorDialogMessages"; + + /** + * The resource bundle. + */ + protected static ResourceBundle bundle; + + /** + * The resource manager. + */ + protected static ResourceManager resources; + static { + bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault()); + resources = new ResourceManager(bundle); + } + + /** + * The Dialog results. + */ + protected int returnCode; + + /** + * The Dialog main panel. + */ + protected JPanel mainPanel; + + /** + * The Button factory. + */ + protected ButtonFactory buttonFactory; + + /** + * The node name label. + */ + protected JLabel nodeNameLabel; + + /** + * The node name field. + */ + protected JTextField nodeNameField; + + /** + * The OK button. + */ + protected JButton okButton; + + /** + * The Cancel button. + */ + protected JButton cancelButton; + + /** + * The map that contains the listeners + */ + protected Map listeners = new HashMap(10); + + /** + * Constructor. + * + * @param frame + * Parent frame + */ + public NameEditorDialog(Frame frame) { + super(frame, true); + this.setResizable(false); + this.setModal(true); + initialize(); + } + + /** + * Initializes the dialog. + */ + protected void initialize() { + this.setSize(resources.getInteger("Dialog.width"), + resources.getInteger("Dialog.height")); + this.setTitle(resources.getString("Dialog.title")); + addButtonActions(); + this.setContentPane(getMainPanel()); + } + + /** + * Gets buttonFactory. + */ + protected ButtonFactory getButtonFactory() { + if (buttonFactory == null) { + buttonFactory = new ButtonFactory(bundle, this); + } + return buttonFactory; + } + + /** + * Adds button actions. + */ + protected void addButtonActions() { + listeners.put("OKButtonAction", new OKButtonAction()); + listeners.put("CancelButtonAction", new CancelButtonAction()); + } + + /** + * Shows the dialog. + * + * @return OK_OPTION or CANCEL_OPTION. + */ + public int showDialog() { + setVisible(true); + return returnCode; + } + + /** + * Gets the Ok button. + * + * @return the okButton + */ + protected JButton getOkButton() { + if (okButton == null) { + okButton = getButtonFactory().createJButton("OKButton"); + this.getRootPane().setDefaultButton(okButton); + } + return okButton; + } + + /** + * Gets the Cancel button. + * + * @return the cancelButton + */ + protected JButton getCancelButton() { + if (cancelButton == null) { + cancelButton = getButtonFactory().createJButton("CancelButton"); + } + return cancelButton; + } + + /** + * Gets dialog's main panel. + * + * @return the mainPanel + */ + protected JPanel getMainPanel() { + if (mainPanel == null) { + mainPanel = new JPanel(new GridBagLayout()); + + GridBagConstraints gridBag = new GridBagConstraints(); + gridBag.gridx = 1; + gridBag.gridy = 1; + gridBag.fill = GridBagConstraints.NONE; + gridBag.insets = new Insets(5, 5, 5, 5); + mainPanel.add(getNodeNameLabel(), gridBag); + + gridBag.gridx = 2; + gridBag.weightx = 1.0; + gridBag.weighty = 1.0; + gridBag.fill = GridBagConstraints.HORIZONTAL; + gridBag.anchor = GridBagConstraints.CENTER; + mainPanel.add(getNodeNameField(), gridBag); + + gridBag.gridx = 1; + gridBag.gridy = 2; + gridBag.weightx = 0; + gridBag.weighty = 0; + gridBag.anchor = GridBagConstraints.EAST; + gridBag.fill = GridBagConstraints.HORIZONTAL; + mainPanel.add(getOkButton(), gridBag); + + gridBag.gridx = 2; + gridBag.gridy = 2; + gridBag.anchor = GridBagConstraints.EAST; + mainPanel.add(getCancelButton(), gridBag); + } + return mainPanel; + } + + /** + * Gets the node name label. + * + * @return the nodeNameLabel + */ + public JLabel getNodeNameLabel() { + if (nodeNameLabel == null) { + nodeNameLabel = new JLabel(); + nodeNameLabel.setText(resources.getString("Dialog.label")); + } + return nodeNameLabel; + } + + /** + * Gets the text field for node name. + * + * @return the nodeNameField + */ + protected JTextField getNodeNameField() { + if (nodeNameField == null) { + nodeNameField = new JTextField(); + } + return nodeNameField; + } + + /** + * Gets the dialog results. + * + * @return the element name + */ + public String getResults() { + return nodeNameField.getText(); + } + + /** + * The action associated with the 'OK' button of Attribute Adder Dialog + */ + protected class OKButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + returnCode = OK_OPTION; + dispose(); + } + } + + /** + * The action associated with the 'Cancel' button of Attribute Adder + * Dialog + */ + protected class CancelButtonAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + returnCode = CANCEL_OPTION; + dispose(); + } + } + + /** + * Returns the action associated with the given string or null on error + * + * @param key + * the key mapped with the action to get + * @throws MissingListenerException + * if the action is not found + */ + public Action getAction(String key) throws MissingListenerException { + return (Action) listeners.get(key); + } + } +} + Index: 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/NodeTemplates.java =================================================================== RCS file: /usr/local/cvsroot/3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/NodeTemplates.java,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ 3rdParty_sources/batik/org/apache/batik/apps/svgbrowser/NodeTemplates.java 8 Apr 2013 10:55:07 -0000 1.1 @@ -0,0 +1,1368 @@ +/* + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.apache.batik.apps.svgbrowser; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.apache.batik.util.SVGConstants; +import org.w3c.dom.Node; + +/** + * Provides basic xml representation and description for most commonly used + * nodes. + * + * @version $Id: NodeTemplates.java,v 1.1 2013/04/08 10:55:07 marcin Exp $ + */ +public class NodeTemplates { + + // Node template descriptions provide basic information on node properties, + // such as: xml represenation (suffix "Value"), element name + // (suffix "Name"), element type (suffix "Type"), element category + // (suffix "Category"), element description (suffix "Description"). + // Base node name on which these suffixes are appended is read from the + // class members ending with "MemberName". + + // Example: + // public static String rectMemberName = "rectElement"; + // Other class members that describe this node should be declared as: + // rectElementValue = "...", rectElementType = "...", rectElementName = + // "...", rectElementCategory = "..." and rectElementDescription = "..." + + // Suffixes + public static final String VALUE = "Value"; + + public static final String NAME = "Name"; + + public static final String TYPE = "Type"; + + public static final String DESCRIPTION = "Description"; + + public static final String CATEGORY = "Category"; + + // Categories + public static final String BASIC_SHAPES = "Basic Shapes"; + + public static final String LINKING = "Linking"; + + public static final String TEXT = "Text"; + + public static final String ANIMATION = "Animation"; + + public static final String CLIP_MASK_COMPOSITE = "Clipping, Masking and Compositing"; + + public static final String COLOR = "Color"; + + public static final String INTERACTIVITY = "Interactivity"; + + public static final String FONTS = "Fonts"; + + public static final String DOCUMENT_STRUCTURE = "Document Structure"; + + public static final String FILTER_EFFECTS = "Filter Effects"; + + public static final String EXTENSIBILITY = "Extensibility"; + + public static final String GRADIENTS_AND_PATTERNS = "Gradients and Patterns"; + + public static final String PAINTING = "Painting: Filling, Stroking and Marker Symbols"; + + public static final String METADATA = "Metadata"; + + public static final String PATHS = "Paths"; + + public static final String SCRIPTING = "Scripting"; + + public static final String STYLING = "Styling"; + + // Maps + /** + * Map with node template wrappers. + */ + private Map nodeTemplatesMap = new HashMap(); + + /** + * List with all node categories. + */ + private ArrayList categoriesList = new ArrayList(); + + + // Rect element + public static String rectMemberName = "rectElement"; + + public static String rectElementValue = ""; + + public static String rectElementName = SVGConstants.SVG_RECT_TAG; + + public static short rectElementType = Node.ELEMENT_NODE; + + public static String rectElementCategory = BASIC_SHAPES; + + public static String rectElementDescription = "Rect"; + + // Circle element + public static String circleMemberName = "circleElement"; + + public static String circleElementValue = ""; + + public static String circleElementName = SVGConstants.SVG_CIRCLE_TAG; + + public short circleElementType = Node.ELEMENT_NODE; + + public static String circleElementCategory = BASIC_SHAPES; + + public static String circleElementDescription = "Circle"; + + // Line element + public static String lineElementMemberName = "lineElement"; + + public static String lineElementName = SVGConstants.SVG_LINE_TAG; + + public static String lineElementValue = ""; + + public static short lineElementType = Node.ELEMENT_NODE; + + public static String lineElementCategory = BASIC_SHAPES; + + public static String lineElementDescription = "Text"; + + // Path element + public static String pathElementMemberName = "pathElement"; + + public static String pathElementName = SVGConstants.SVG_PATH_TAG; + + public static String pathElementValue = ""; + + public static short pathElementType = Node.ELEMENT_NODE; + + public static String pathElementCategory = PATHS; + + public static String pathElementDescription = "Path"; + + // G element + public static String groupElementMemberName = "groupElement"; + + public static String groupElementName = SVGConstants.SVG_G_TAG; + + public static String groupElementValue = ""; + + public static short groupElementType = Node.ELEMENT_NODE; + + public static String groupElementCategory = DOCUMENT_STRUCTURE; + + public static String groupElementDescription = "Group"; + + // Ellipse element + public static String ellipseElementMemberName = "ellipseElement"; + + public static String ellipseElementName = SVGConstants.SVG_ELLIPSE_TAG; + + public static String ellipseElementValue = ""; + + public static short ellipseElementType = Node.ELEMENT_NODE; + + public static String ellipseElementCategory = BASIC_SHAPES; + + public static String ellipseElementDescription = "Ellipse"; + + // Image element + public static String imageElementMemberName = "imageElement"; + + public static String imageElementName = SVGConstants.SVG_IMAGE_TAG; + + public static String imageElementValue = ""; + + public static short imageElementType = Node.ELEMENT_NODE; + + public static String imageElementCategory = DOCUMENT_STRUCTURE; + + public static String imageElementDescription = "Image"; + + // Polygon element + public static String polygonElementMemberName = "polygonElement"; + + public static String polygonElementName = SVGConstants.SVG_POLYGON_TAG; + + public static String polygonElementValue = ""; + + public static short polygonElementType = Node.ELEMENT_NODE; + + public static String polygonElementCategory = BASIC_SHAPES; + + public static String polygonElementDescription = "Polygon"; + + // Polyline element + public static String polylineElementMemberName = "polylineElement"; + + public static String polylineElementName = SVGConstants.SVG_POLYLINE_TAG; + + public static String polylineElementValue = ""; + + public static short polylineElementType = Node.ELEMENT_NODE; + + public static String polylineElementCategory = BASIC_SHAPES; + + public static String polylineElementDescription = "Polyline"; + + // Text element + public static String textElementMemberName = "textElement"; + + public static String textElementName = SVGConstants.SVG_TEXT_TAG; + + public static String textElementValue = " "; + + public static short textElementType = Node.ELEMENT_NODE; + + public static String textElementCategory = TEXT; + + public static String textElementDescription = "Text"; + + // TRef element + public static String tRefElementMemberName = "tRefElement"; + + public static String tRefElementName = SVGConstants.SVG_TREF_TAG; + + public static String tRefElementValue = ""; + + public static short tRefElementType = Node.ELEMENT_NODE; + + public static String tRefElementCategory = TEXT; + + public static String tRefElementDescription = "TRef"; + + // TSpan element + public static String tspanElementMemberName = "tspanElement"; + + public static String tspanElementName = SVGConstants.SVG_TSPAN_TAG; + + public static String tspanElementValue = ""; + + public static short tspanElementType = Node.ELEMENT_NODE; + + public static String tspanElementCategory = TEXT; + + public static String tspanElementDescription = "TSpan"; + + // TextPath element + public static String textPathElementMemberName = "textPathElement"; + + public static String textPathElementName = SVGConstants.SVG_TEXT_PATH_TAG; + + public static String textPathElementValue = ""; + + public static short textPathElementType = Node.ELEMENT_NODE; + + public static String textPathElementCategory = TEXT; + + public static String textPathElementDescription = "TextPath"; + + // Svg element + public static String svgElementMemberName = "svgElement"; + + public static String svgElementName = SVGConstants.SVG_SVG_TAG; + + public static String svgElementValue = ""; + + public static short svgElementType = Node.ELEMENT_NODE; + + public static String svgElementCategory = DOCUMENT_STRUCTURE; + + public static String svgElementDescription = "svg"; + + // FeBlend element + public static String feBlendElementMemberName = "feBlendElement"; + + public static String feBlendElementName = SVGConstants.SVG_FE_BLEND_TAG; + + public static String feBlendElementValue = ""; + + public static short feBlendElementType = Node.ELEMENT_NODE; + + public static String feBlendElementCategory = FILTER_EFFECTS; + + public static String feBlendElementDescription = "FeBlend"; + + // FeColorMatrix element + public static String feColorMatrixElementMemberName = "feColorMatrixElement"; + + public static String feColorMatrixElementName = SVGConstants.SVG_FE_COLOR_MATRIX_TAG; + + public static String feColorMatrixElementValue = ""; + + public static short feColorMatrixElementType = Node.ELEMENT_NODE; + + public static String feColorMatrixElementCategory = FILTER_EFFECTS; + + public static String feColorMatrixElementDescription = "FeColorMatrix"; + + // FeComponentTransfer element + public static String feComponentTransferElementMemberName = "feComponentTransferElement"; + + public static String feComponentTransferElementName = SVGConstants.SVG_FE_COMPONENT_TRANSFER_TAG; + + public static String feComponentTransferElementValue = ""; + + public static short feComponentTransferElementType = Node.ELEMENT_NODE; + + public static String feComponentTransferElementCategory = FILTER_EFFECTS; + + public static String feComponentTransferElementDescription = "FeComponentTransfer"; + + // FeComposite element + public static String feCompositeElementMemberName = "feCompositeElement"; + + public static String feCompositeElementName = SVGConstants.SVG_FE_COMPOSITE_TAG; + + public static String feCompositeElementValue = ""; + + public static short feCompositeElementType = Node.ELEMENT_NODE; + + public static String feCompositeElementCategory = FILTER_EFFECTS; + + public static String feCompositeElementDescription = "FeComposite"; + + // FeConvolveMatrix element + public static String feConvolveMatrixElementMemberName = "feConvolveMatrixElement"; + + public static String feConvolveMatrixElementName = SVGConstants.SVG_FE_CONVOLVE_MATRIX_TAG; + + public static String feConvolveMatrixElementValue = ""; + + public static short feConvolveMatrixElementType = Node.ELEMENT_NODE; + + public static String feConvolveMatrixElementCategory = FILTER_EFFECTS; + + public static String feConvolveMatrixElementDescription = "FeConvolveMatrix"; + + // FeDiffuseLighting element + public static String feDiffuseLightingElementMemberName = "feDiffuseLightingElement"; + + public static String feDiffuseLightingElementName = SVGConstants.SVG_FE_DIFFUSE_LIGHTING_TAG; + + public static String feDiffuseLightingElementValue = ""; + + public static short feDiffuseLightingElementType = Node.ELEMENT_NODE; + + public static String feDiffuseLightingElementCategory = FILTER_EFFECTS; + + public static String feDiffuseLightingElementDescription = "FeDiffuseLighting"; + + // FeDisplacementMap element + public static String feDisplacementMapElementMemberName = "feDisplacementMapElement"; + + public static String feDisplacementMapElementName = SVGConstants.SVG_FE_DISPLACEMENT_MAP_TAG; + + public static String feDisplacementMapElementValue = ""; + + public static short feDisplacementMapElementType = Node.ELEMENT_NODE; + + public static String feDisplacementMapElementCategory = FILTER_EFFECTS; + + public static String feDisplacementMapElementDescription = "FeDisplacementMap"; + + // FeDistantLight element + public static String feDistantLightElementMemberName = "feDistantLightElement"; + + public static String feDistantLightElementName = SVGConstants.SVG_FE_DISTANT_LIGHT_TAG; + + public static String feDistantLightElementValue = ""; + + public static short feDistantLightElementType = Node.ELEMENT_NODE; + + public static String feDistantLightElementCategory = FILTER_EFFECTS; + + public static String feDistantLightElementDescription = "FeDistantLight"; + + // FeFlood element + public static String feFloodElementMemberName = "feFloodElement"; + + public static String feFloodElementName = SVGConstants.SVG_FE_FLOOD_TAG; + + public static String feFloodElementValue = ""; + + public static short feFloodElementType = Node.ELEMENT_NODE; + + public static String feFloodElementCategory = FILTER_EFFECTS; + + public static String feFloodElementDescription = "FeFlood"; + + // FeFuncA element + public static String feFuncAElementMemberName = "feFuncAElement"; + + public static String feFuncAElementName = SVGConstants.SVG_FE_FUNC_A_TAG; + + public static String feFuncAElementValue = ""; + + public static short feFuncAElementType = Node.ELEMENT_NODE; + + public static String feFuncAElementCategory = FILTER_EFFECTS; + + public static String feFuncAElementDescription = "FeFuncA"; + + // FeFuncB element + public static String feFuncBElementMemberName = "feFuncBElement"; + + public static String feFuncBElementName = SVGConstants.SVG_FE_FUNC_B_TAG; + + public static String feFuncBElementValue = ""; + + public static short feFuncBElementType = Node.ELEMENT_NODE; + + public static String feFuncBElementCategory = FILTER_EFFECTS; + + public static String feFuncBElementDescription = "FeFuncB"; + + // FeFuncG element + public static String feFuncGElementMemberName = "feFuncGElement"; + + public static String feFuncGElementName = SVGConstants.SVG_FE_FUNC_G_TAG; + + public static String feFuncGElementValue = ""; + + public static short feFuncGElementType = Node.ELEMENT_NODE; + + public static String feFuncGElementCategory = FILTER_EFFECTS; + + public static String feFuncGElementDescription = "FeFuncG"; + + // FeFuncR element + public static String feFuncRElementMemberName = "feFuncRElement"; + + public static String feFuncRElementName = SVGConstants.SVG_FE_FUNC_R_TAG; + + public static String feFuncRElementValue = ""; + + public static short feFuncRElementType = Node.ELEMENT_NODE; + + public static String feFuncRElementCategory = FILTER_EFFECTS; + + public static String feFuncRElementDescription = "FeFuncR"; + + // FeGaussianBlur element + public static String feGaussianBlurElementMemberName = "feGaussianBlurElement"; + + public static String feGaussianBlurElementName = SVGConstants.SVG_FE_GAUSSIAN_BLUR_TAG; + + public static String feGaussianBlurElementValue = ""; + + public static short feGaussianBlurElementType = Node.ELEMENT_NODE; + + public static String feGaussianBlurElementCategory = FILTER_EFFECTS; + + public static String feGaussianBlurElementDescription = "FeGaussianBlur"; + + // FeImage element + public static String feImageElementMemberName = "feImageElement"; + + public static String feImageElementName = SVGConstants.SVG_FE_IMAGE_TAG; + + public static String feImageElementValue = ""; + + public static short feImageElementType = Node.ELEMENT_NODE; + + public static String feImageElementCategory = FILTER_EFFECTS; + + public static String feImageElementDescription = "FeImage"; + + // FeMerge element + public static String feMergeElementMemberName = "feImageElement"; + + public static String feMergeElementName = SVGConstants.SVG_FE_MERGE_TAG; + + public static String feMergeElementValue = ""; + + public static short feMergeElementType = Node.ELEMENT_NODE; + + public static String feMergeElementCategory = FILTER_EFFECTS; + + public static String feMergeElementDescription = "FeMerge"; + + // FeMergeNode element + public static String feMergeNodeElementMemberName = "feMergeNodeElement"; + + public static String feMergeNodeElementName = SVGConstants.SVG_FE_MERGE_NODE_TAG; + + public static String feMergeNodeElementValue = ""; + + public static short feMergeNodeElementType = Node.ELEMENT_NODE; + + public static String feMergeNodeElementCategory = FILTER_EFFECTS; + + public static String feMergeNodeElementDescription = "FeMergeNode"; + + // FeMorphology element + public static String feMorphologyElementMemberName = "feMorphologyElement"; + + public static String feMorphologyElementName = SVGConstants.SVG_FE_MORPHOLOGY_TAG; + + public static String feMorphologyElementValue = ""; + + public static short feMorphologyElementType = Node.ELEMENT_NODE; + + public static String feMorphologyElementCategory = FILTER_EFFECTS; + + public static String feMorphologyElementDescription = "FeMorphology"; + + // FeOffset element + public static String feOffsetElementMemberName = "feMorphologyElement"; + + public static String feOffsetElementName = SVGConstants.SVG_FE_OFFSET_TAG; + + public static String feOffsetElementValue = ""; + + public static short feOffsetElementType = Node.ELEMENT_NODE; + + public static String feOffsetElementCategory = FILTER_EFFECTS; + + public static String feOffsetElementDescription = "FeOffset"; + + // FePointLight element + public static String fePointLightElementMemberName = "fePointLightElement"; + + public static String fePointLightElementName = SVGConstants.SVG_FE_POINT_LIGHT_TAG; + + public static String fePointLightElementValue = ""; + + public static short fePointLightElementType = Node.ELEMENT_NODE; + + public static String fePointLightElementCategory = FILTER_EFFECTS; + + public static String fePointLightElementDescription = "FePointLight"; + + // FeSpecularLighting element + public static String feSpecularLightingElementMemberName = "fePointLightElement"; + + public static String feSpecularLightingElementName = SVGConstants.SVG_FE_SPECULAR_LIGHTING_TAG; + + public static String feSpecularLightingElementValue = ""; + + public static short feSpecularLightingElementType = Node.ELEMENT_NODE; + + public static String feSpecularLightingElementCategory = FILTER_EFFECTS; + + public static String feSpecularLightingElementDescription = "FeSpecularLighting"; + + // FeSpotLight element + public static String feSpotLightElementMemberName = "feSpotLightElement"; + + public static String feSpotLightElementName = SVGConstants.SVG_FE_SPOT_LIGHT_TAG; + + public static String feSpotLightElementValue = ""; + + public static short feSpotLightElementType = Node.ELEMENT_NODE; + + public static String feSpotLightElementCategory = FILTER_EFFECTS; + + public static String feSpotLightElementDescription = "FeSpotLight"; + + // FeTile element + public static String feTileElementMemberName = "feTileElement"; + + public static String feTileElementName = SVGConstants.SVG_FE_TILE_TAG; + + public static String feTileElementValue = ""; + + public static short feTileElementType = Node.ELEMENT_NODE; + + public static String feTileElementCategory = FILTER_EFFECTS; + + public static String feTileElementDescription = "FeTile"; + + // FeTurbulence element + public static String feTurbulenceElementMemberName = "feTurbulenceElement"; + + public static String feTurbulenceElementName = SVGConstants.SVG_FE_TURBULENCE_TAG; + + public static String feTurbulenceElementValue = ""; + + public static short feTurbulenceElementType = Node.ELEMENT_NODE; + + public static String feTurbulenceElementCategory = FILTER_EFFECTS; + + public static String feTurbulenceElementDescription = "FeTurbulence"; + + // Filter element + public static String filterElementMemberName = "filterElement"; + + public static String filterElementName = SVGConstants.SVG_FILTER_TAG; + + public static String filterElementValue = ""; + + public static short filterElementType = Node.ELEMENT_NODE; + + public static String filterElementCategory = FILTER_EFFECTS; + + public static String filterElementDescription = "Filter"; + +// // Text node +// public static String textNodeMemberName = "textNode"; +// +// public static String textNodeName = "textNode"; +// +// public static String textNodeValue = " "; +// +// public static short textNodeType = Node.TEXT_NODE; +// +// public static String textNodeCategory = METADATA; +// +// public static String textNodeDescription = "Text node"; +// +// // CDataSection node +// public static String cdataSectionNodeMemberName = "cdataSectionNode"; +// +// public static String cdataSectionNodeName = "cdataSectionNode"; +// +// public static String cdataSectionNodeValue = " "; +// +// public static short cdataSectionNodeType = Node.CDATA_SECTION_NODE; +// +// public static String cdataSectionNodeCategory = METADATA; +// +// public static String cdataSectionNodeDescription = "CDataSection"; +// +// // Comment node +// public static String commentNodeMemberName = "commentNode"; +// +// public static String commentNodeName = "commentNode"; +// +// public static String commentNodeValue = " "; +// +// public static short commentNodeType = Node.COMMENT_NODE; +// +// public static String commentNodeCategory = METADATA; +// +// public static String commentNodeDescription = "CommentNode"; + + // A element + public static String aElementMemberName = "aElement"; + + public static String aElementName = SVGConstants.SVG_A_TAG; + + public static String aElementValue = ""; + + public static short aElementType = Node.ELEMENT_NODE; + + public static String aElementCategory = LINKING; + + public static String aElementDescription = "A"; + + // AltGlyph element + public static String altGlyphElementMemberName = "altGlyphElement"; + + public static String altGlyphElementName = SVGConstants.SVG_ALT_GLYPH_TAG; + + public static String altGlyphElementValue = ""; + + public static short altGlyphElementType = Node.ELEMENT_NODE; + + public static String altGlyphElementCategory = TEXT; + + public static String altGlyphElementDescription = "AltGlyph"; + + // AltGlyphDef element + public static String altGlyphDefElementMemberName = "altGlyphDefElement"; + + public static String altGlyphDefElementName = SVGConstants.SVG_ALT_GLYPH_DEF_TAG; + + public static String altGlyphDefElementValue = ""; + + public static short altGlyphDefElementType = Node.ELEMENT_NODE; + + public static String altGlyphDefElementCategory = TEXT; + + public static String altGlyphDefElementDescription = "AltGlyphDef"; + + // AltGlyphItem element + public static String altGlyphItemElementMemberName = "altGlyphItemElement"; + + public static String altGlyphItemElementName = SVGConstants.SVG_ALT_GLYPH_ITEM_TAG; + + public static String altGlyphItemElementValue = ""; + + public static short altGlyphItemElementType = Node.ELEMENT_NODE; + + public static String altGlyphItemElementCategory = TEXT; + + public static String altGlyphItemElementDescription = "AltGlyphItem"; + + // ClipPath element + public static String clipPathElementMemberName = "clipPathElement"; + + public static String clipPathElementName = SVGConstants.SVG_CLIP_PATH_TAG; + + public static String clipPathElementValue = ""; + + public static short clipPathElementType = Node.ELEMENT_NODE; + + public static String clipPathElementCategory = CLIP_MASK_COMPOSITE; + + public static String clipPathElementDescription = "ClipPath"; + + // ColorProfile element + public static String colorProfileElementMemberName = "colorProfileElement"; + + public static String colorProfileElementName = SVGConstants.SVG_COLOR_PROFILE_TAG; + + public static String colorProfileElementValue = ""; + + public static short colorProfileElementType = Node.ELEMENT_NODE; + + public static String colorProfileElementCategory = COLOR; + + public static String colorProfileElementDescription = "ColorProfile"; + + // Cursor element + public static String cursorElementMemberName = "cursorElement"; + + public static String cursorElementName = SVGConstants.SVG_CURSOR_TAG; + + public static String cursorElementValue = ""; + + public static short cursorElementType = Node.ELEMENT_NODE; + + public static String cursorElementCategory = INTERACTIVITY; + + public static String cursorElementDescription = "Cursor"; + + // DefinitionSrc element + public static String definitionSrcElementMemberName = "definitionSrcElement"; + + public static String definitionSrcElementName = SVGConstants.SVG_DEFINITION_SRC_TAG; + + public static String definitionSrcElementValue = ""; + + public static short definitionSrcElementType = Node.ELEMENT_NODE; + + public static String definitionSrcElementCategory = FONTS; + + public static String definitionSrcElementDescription = "DefinitionSrc"; + + // Defs element + public static String defsElementMemberName = "defsElement"; + + public static String defsElementName = SVGConstants.SVG_DEFS_TAG; + + public static String defsElementValue = ""; + + public static short defsElementType = Node.ELEMENT_NODE; + + public static String defsElementCategory = DOCUMENT_STRUCTURE; + + public static String defsElementDescription = "Defs"; + + // Desc element + public static String descElementMemberName = "descElement"; + + public static String descElementName = SVGConstants.SVG_DESC_TAG; + + public static String descElementValue = ""; + + public static short descElementType = Node.ELEMENT_NODE; + + public static String descElementCategory = DOCUMENT_STRUCTURE; + + public static String descElementDescription = "Desc"; + + // ForeignObject element + public static String foreignObjectElementMemberName = "foreignObjectElement"; + + public static String foreignObjectElementName = SVGConstants.SVG_FOREIGN_OBJECT_TAG; + + public static String foreignObjectElementValue = ""; + + public static short foreignObjectElementType = Node.ELEMENT_NODE; + + public static String foreignObjectElementCategory = EXTENSIBILITY; + + public static String foreignObjectElementDescription = "ForeignObject"; + + // Glyph element + public static String glyphElementMemberName = "glyphElement"; + + public static String glyphElementName = SVGConstants.SVG_GLYPH_TAG; + + public static String glyphElementValue = ""; + + public static short glyphElementType = Node.ELEMENT_NODE; + + public static String glyphElementCategory = FONTS; + + public static String glyphElementDescription = "Glyph"; + + // GlyphRef element + public static String glyphRefElementMemberName = "glyphRefElement"; + + public static String glyphRefElementName = SVGConstants.SVG_GLYPH_REF_TAG; + + public static String glyphRefElementValue = ""; + + public static short glyphRefElementType = Node.ELEMENT_NODE; + + public static String glyphRefElementCategory = TEXT; + + public static String glyphRefElementDescription = "GlyphRef"; + + // Hkern element + public static String hkernElementMemberName = "hkernElement"; + + public static String hkernElementName = SVGConstants.SVG_HKERN_TAG; + + public static String hkernElementValue = ""; + + public static short hkernElementType = Node.ELEMENT_NODE; + + public static String hkernElementCategory = FONTS; + + public static String hkernElementDescription = "Hkern"; + + // LinearGradient element + public static String linearGradientElementMemberName = "linearGradientElement"; + + public static String linearGradientElementName = SVGConstants.SVG_LINEAR_GRADIENT_TAG; + + public static String linearGradientElementValue = ""; + + public static short linearGradientElementType = Node.ELEMENT_NODE; + + public static String linearGradientElementCategory = GRADIENTS_AND_PATTERNS; + + public static String linearGradientElementDescription = "LinearGradient"; + + // Marker element + public static String markerElementMemberName = "markerElement"; + + public static String markerElementName = SVGConstants.SVG_MARKER_TAG; + + public static String markerElementValue = ""; + + public static short markerElementType = Node.ELEMENT_NODE; + + public static String markerElementCategory = PAINTING; + + public static String markerElementDescription = "Marker"; + + // Mask element + public static String maskElementMemberName = "maskElement"; + + public static String maskElementName = SVGConstants.SVG_MASK_TAG; + + public static String maskElementValue = ""; + + public static short maskElementType = Node.ELEMENT_NODE; + + public static String maskElementCategory = CLIP_MASK_COMPOSITE; + + public static String maskElementDescription = "Mask"; + + // Metadata element + public static String metadataElementMemberName = "metadataElement"; + + public static String metadataElementName = SVGConstants.SVG_METADATA_TAG; + + public static String metadataElementValue = ""; + + public static short metadataElementType = Node.ELEMENT_NODE; + + public static String metadataElementCategory = METADATA; + + public static String metadataElementDescription = "Metadata"; + + // MissingGlyph element + public static String missingGlyphElementMemberName = "missingGlyphElement"; + + public static String missingGlyphElementName = SVGConstants.SVG_MISSING_GLYPH_TAG; + + public static String missingGlyphElementValue = ""; + + public static short missingGlyphElementType = Node.ELEMENT_NODE; + + public static String missingGlyphElementCategory = FONTS; + + public static String missingGlyphElementDescription = "MissingGlyph"; + + // Mpath element + public static String mpathElementMemberName = "mpathElement"; + + public static String mpathElementName = SVGConstants.SVG_MPATH_TAG; + + public static String mpathElementValue = ""; + + public static short mpathElementType = Node.ELEMENT_NODE; + + public static String mpathElementCategory = ANIMATION; + + public static String mpathElementDescription = "Mpath"; + + // Pattern element + public static String patternElementMemberName = "patternElement"; + + public static String patternElementName = SVGConstants.SVG_PATTERN_TAG; + + public static String patternElementValue = ""; + + public static short patternElementType = Node.ELEMENT_NODE; + + public static String patternElementCategory = GRADIENTS_AND_PATTERNS; + + public static String patternElementDescription = "Pattern"; + + // RadialGradient element + public static String radialGradientElementMemberName = "radialGradientElement"; + + public static String radialGradientElementName = SVGConstants.SVG_RADIAL_GRADIENT_TAG; + + public static String radialGradientElementValue = ""; + + public static short radialGradientElementType = Node.ELEMENT_NODE; + + public static String radialGradientElementCategory = GRADIENTS_AND_PATTERNS; + + public static String radialGradientElementDescription = "RadialGradient"; + + // Script element + public static String scriptElementMemberName = "scriptElement"; + + public static String scriptElementName = SVGConstants.SVG_SCRIPT_TAG; + + public static String scriptElementValue = "