001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package com.sun.perseus.model;
027:
028: import com.sun.perseus.util.SVGConstants;
029:
030: import org.w3c.dom.DOMException;
031:
032: import org.w3c.dom.svg.SVGMatrix;
033:
034: import com.sun.perseus.j2d.Transform;
035:
036: /**
037: * A <code>Group</code> corresponds to an SVT Tiny <code><g></code>
038: * element.
039: *
040: * @version $Id: Group.java,v 1.10 2006/06/29 10:47:32 ln156897 Exp $
041: */
042: public class Group extends StructureNode implements Transformable {
043: /**
044: * The Transform applied to this node.
045: */
046: protected Transform transform;
047:
048: /**
049: * The motion transform applied to this node. This is typically used for
050: * animateMotion, but it can be used as a regular trait as well.
051: */
052: protected Transform motion;
053:
054: /**
055: * The parent space to child space transform
056: */
057: protected Transform inverseTransform;
058:
059: /**
060: * Constructor.
061: *
062: * @param ownerDocument this element's owner <code>DocumentNode</code>
063: */
064: public Group(final DocumentNode ownerDocument) {
065: super (ownerDocument);
066: }
067:
068: /**
069: * @return the SVGConstants.SVG_GROUP_TAG value
070: */
071: public String getLocalName() {
072: return SVGConstants.SVG_G_TAG;
073: }
074:
075: /**
076: * Used by <code>DocumentNode</code> to create a new instance from
077: * a prototype <code>Group</code>.
078: *
079: * @param doc the <code>DocumentNode</code> for which a new node is
080: * should be created.
081: * @return a new <code>Group</code> for the requested document.
082: */
083: public ElementNode newInstance(final DocumentNode doc) {
084: return new Group(doc);
085: }
086:
087: /**
088: * @param newTransform this node's new transform. Note that the
089: * input value is used by reference.
090: */
091: public void setTransform(final Transform newTransform) {
092: if (equal(newTransform, transform)) {
093: return;
094: }
095:
096: modifyingNode();
097: this .transform = newTransform;
098: recomputeTransformState();
099: recomputeProxyTransformState();
100: modifiedNode();
101: }
102:
103: /**
104: * @param newMotion The new motion transform.
105: */
106: public void setMotion(final Transform newMotion) {
107: if (equal(newMotion, motion)) {
108: return;
109: }
110:
111: modifyingNode();
112: this .motion = newMotion;
113: recomputeTransformState();
114: recomputeProxyTransformState();
115: modifiedNode();
116: }
117:
118: /**
119: * @return this node's transform
120: */
121: public Transform getTransform() {
122: return transform;
123: }
124:
125: /**
126: * @return this node's motion transform
127: */
128: public Transform getMotion() {
129: return motion;
130: }
131:
132: /**
133: * Appends this node's transform, if it is not null.
134: *
135: * @param tx the <code>Transform</code> to apply additional node
136: * transforms to. This may be null.
137: * @param workTx a <code>Transform</code> which can be re-used if a
138: * new <code>Transform</code> needs to be created and workTx
139: * is not the same instance as tx.
140: * @return a transform with this node's transform added.
141: */
142: protected Transform appendTransform(Transform tx,
143: final Transform workTx) {
144: if (transform == null && motion == null) {
145: return tx;
146: }
147:
148: tx = recycleTransform(tx, workTx);
149:
150: if (motion != null) {
151: tx.mMultiply(motion);
152: }
153:
154: if (transform != null) {
155: tx.mMultiply(transform);
156: }
157:
158: return tx;
159: }
160:
161: /**
162: * Supported traits: transform.
163: *
164: * @param traitName the name of the trait which the element may support.
165: * @return true if this element supports the given trait in one of the
166: * trait accessor methods.
167: */
168: boolean supportsTrait(final String traitName) {
169: if (SVGConstants.SVG_TRANSFORM_ATTRIBUTE == traitName
170: || SVGConstants.SVG_MOTION_PSEUDO_ATTRIBUTE == traitName) {
171: return true;
172: } else {
173: return super .supportsTrait(traitName);
174: }
175: }
176:
177: /**
178: * AbstractShapeNode handles the transform attribute.
179: * Other attributes are handled by the super class.
180: *
181: * @param name the requested trait name.
182: * @return the requested trait value.
183: *
184: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
185: * trait is not supported on this element or null.
186: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
187: * trait's computed value cannot be converted to a String (SVG Tiny only).
188: */
189: public String getTraitImpl(final String name) throws DOMException {
190: if (SVGConstants.SVG_TRANSFORM_ATTRIBUTE == name) {
191: return toStringTrait(transform);
192: } else if (SVGConstants.SVG_MOTION_PSEUDO_ATTRIBUTE == name) {
193: return toStringTrait(motion);
194: } else {
195: return super .getTraitImpl(name);
196: }
197: }
198:
199: /**
200: * AbstractShapeNode handles the transform attribute.
201: * Other attributes are handled by the super class.
202: *
203: * @param name the trait's name.
204: * @param value the new trait value, as a string.
205: *
206: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
207: * trait is not supported on this element or null.
208: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
209: * trait's value cannot be specified as a String
210: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
211: * value is an invalid value for the given trait or null.
212: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
213: * attempt is made to change readonly trait.
214: */
215: public void setTraitImpl(final String name, final String value)
216: throws DOMException {
217: if (SVGConstants.SVG_TRANSFORM_ATTRIBUTE == name) {
218: setTransform(parseTransformTrait(name, value));
219: } else if (SVGConstants.SVG_MOTION_PSEUDO_ATTRIBUTE == name) {
220: setMotion(parseTransformTrait(name, value));
221: } else {
222: super .setTraitImpl(name, value);
223: }
224: }
225:
226: /**
227: * AbstractShapeNode handles the transform attribute.
228: * Other attributes are handled by the super class.
229: *
230: * @param name matrix trait name.
231: * @return the trait value corresponding to name as SVGMatrix.
232: *
233: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
234: * trait is not supported on this element or null.
235: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
236: * trait's computed value cannot be converted to {@link
237: * org.w3c.dom.svg.SVGMatrix SVGMatrix}
238: */
239: SVGMatrix getMatrixTraitImpl(final String name) throws DOMException {
240: if (SVGConstants.SVG_TRANSFORM_ATTRIBUTE.equals(name)) {
241: return toSVGMatrixTrait(transform);
242: } else if (SVGConstants.SVG_MOTION_PSEUDO_ATTRIBUTE
243: .equals(name)) {
244: return toSVGMatrixTrait(motion);
245: } else {
246: return super .getMatrixTraitImpl(name);
247: }
248: }
249:
250: /**
251: * AbstractShapeNode handles the transform attribute.
252: * Other attributes are handled by the super class.
253: *
254: * @param name name of trait to set
255: * @param matrix Transform value of trait
256: *
257: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
258: * trait is not supported on this element or null.
259: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
260: * trait's value cannot be specified as an {@link org.w3c.dom.svg.SVGMatrix
261: * SVGMatrix}
262: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
263: * value is an invalid value for the given trait or null.
264: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
265: * attempt is made to change readonly trait.
266: */
267: void setMatrixTraitImpl(final String name, final Transform matrix)
268: throws DOMException {
269: if (SVGConstants.SVG_TRANSFORM_ATTRIBUTE.equals(name)) {
270: setTransform(matrix);
271: } else if (SVGConstants.SVG_MOTION_PSEUDO_ATTRIBUTE
272: .equals(name)) {
273: setMotion(matrix);
274: } else {
275: super .setMatrixTraitImpl(name, matrix);
276: }
277: }
278:
279: /**
280: * @param traitName the trait name.
281: */
282: TraitAnim createTraitAnimImpl(final String traitName) {
283: if (SVGConstants.SVG_TRANSFORM_ATTRIBUTE == traitName) {
284: return new TransformTraitAnim(this , traitName);
285: } else if (SVGConstants.SVG_MOTION_PSEUDO_ATTRIBUTE == traitName) {
286: return new MotionTraitAnim(this , traitName);
287: } else {
288: return super .createTraitAnimImpl(traitName);
289: }
290: }
291:
292: /**
293: * Set the trait value as float array.
294: *
295: * @param name the trait's name.
296: * @param value the trait's value.
297: *
298: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
299: * trait is not supported on this element.
300: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
301: * trait's value cannot be specified as a float
302: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
303: * value is an invalid value for the given trait.
304: */
305: void setFloatArrayTrait(final String name, final float[][] value)
306: throws DOMException {
307: // We use .equals for the transform attribute as the string may not
308: // have been interned. We use == for the motion pseudo attribute because
309: // it is only used internally and from the SVGConstants strings.
310: if (SVGConstants.SVG_TRANSFORM_ATTRIBUTE.equals(name)) {
311: if (transform == null) {
312: modifyingNode();
313: transform = new Transform(value[0][0], value[1][0],
314: value[2][0], value[3][0], value[4][0],
315: value[5][0]);
316: } else {
317: if (!transform.equals(value)) {
318: modifyingNode();
319: transform.setTransform(value[0][0], value[1][0],
320: value[2][0], value[3][0], value[4][0],
321: value[5][0]);
322: } else {
323: return;
324: }
325: }
326: recomputeTransformState();
327: recomputeProxyTransformState();
328: modifiedNode();
329: } else if (SVGConstants.SVG_MOTION_PSEUDO_ATTRIBUTE == name) {
330: if (motion == null) {
331: modifyingNode();
332: motion = new Transform(value[0][0], value[1][0],
333: value[2][0], value[3][0], value[4][0],
334: value[5][0]);
335: } else {
336: if (!motion.equals(value)) {
337: modifyingNode();
338: motion.setTransform(value[0][0], value[1][0],
339: value[2][0], value[3][0], value[4][0],
340: value[5][0]);
341: } else {
342: return;
343: }
344: }
345: recomputeTransformState();
346: recomputeProxyTransformState();
347: modifiedNode();
348: } else {
349: super .setFloatArrayTrait(name, value);
350: }
351: }
352:
353: /**
354: * Validates the input trait value.
355: *
356: * @param traitName the name of the trait to be validated.
357: * @param value the value to be validated
358: * @param reqNamespaceURI the namespace of the element requesting
359: * validation.
360: * @param reqLocalName the local name of the element requesting validation.
361: * @param reqTraitNamespace the namespace of the trait which has the values
362: * value on the requesting element.
363: * @param reqTraitName the name of the trait which has the values value on
364: * the requesting element.
365: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
366: * value is incompatible with the given trait.
367: */
368: public float[][] validateFloatArrayTrait(final String traitName,
369: final String value, final String reqNamespaceURI,
370: final String reqLocalName, final String reqTraitNamespace,
371: final String reqTraitName) throws DOMException {
372: if (SVGConstants.SVG_TRANSFORM_ATTRIBUTE == traitName
373: || SVGConstants.SVG_MOTION_PSEUDO_ATTRIBUTE == traitName) {
374: Transform txf = parseTransformTrait(traitName, value);
375: return new float[][] { { (float) txf.getComponent(0) },
376: { (float) txf.getComponent(1) },
377: { (float) txf.getComponent(2) },
378: { (float) txf.getComponent(3) },
379: { (float) txf.getComponent(4) },
380: { (float) txf.getComponent(5) } };
381: } else {
382: return super .validateFloatArrayTrait(traitName, value,
383: reqNamespaceURI, reqLocalName, reqTraitNamespace,
384: reqTraitName);
385: }
386: }
387:
388: /**
389: * @param name the name of the trait to convert.
390: * @param value the float trait value to convert.
391: */
392: String toStringTrait(final String name, final float[][] value) {
393: if (SVGConstants.SVG_TRANSFORM_ATTRIBUTE == name) {
394: Transform transform = new Transform(value[0][0],
395: value[1][0], value[2][0], value[3][0], value[4][0],
396: value[5][0]);
397: return toStringTrait(transform);
398: } else {
399: return super.toStringTrait(name, value);
400: }
401: }
402: }
|