001: /*
002: * $RCSfile: OrderedGroup.java,v $
003: *
004: * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.6 $
028: * $Date: 2008/02/28 20:17:27 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.util.Arrays;
035:
036: /**
037: * The OrderedGroup node is a Group that ensures its children render
038: * in a specified order. In addition to the list of children
039: * inherited from the base Group class, OrderedGroup defines an
040: * integer array of child indices that specify the order in which its
041: * children are rendered. This provides a level of indirection in
042: * determining the rendering order of its children. By default, the
043: * child index order array is null, and the children are rendered in
044: * increasing index order.
045: *
046: * <p>
047: * When the child index order array is non-null, it must be the same
048: * length as the number of children. Every entry in the array must
049: * have a unique value between 0 and <code>numChildren-1</code> (i.e.,
050: * there must be no duplicate values and no missing indices). The
051: * order that the child indices appear in the child index order array
052: * determines the order in which the children are rendered. The child
053: * at <code>childIndexOrder[0]</code> is rendered first, followed by
054: * <code>childIndexOrder[1]</code>, and so on, with the child at
055: * <code>childIndexOrder[numChildren-1]</code> rendered
056: * last.
057: *
058: * <p>
059: * The child index order array only affects rendering. List
060: * operations that refer to a child by index, such as getChild(index),
061: * will not be altered by the entries in this array. They will get,
062: * enumerate, add, remove, etc., the children based on the actual
063: * index in the group node. However, some of the list operations,
064: * such as addChild, removeChild, etc., will update the child index
065: * order array as a result of their operation. For example,
066: * removeChild will remove the entry in the child index order array
067: * corresponding to the removed child's index and adjust the remaining
068: * entries accordingly. See the documentation for these methods for
069: * more details.
070: */
071:
072: public class OrderedGroup extends Group {
073:
074: private boolean checkArr[] = null;
075:
076: /**
077: * Specifies that this OrderedGroup node
078: * allows reading its child index order information.
079: *
080: * @since Java 3D 1.3
081: */
082: public static final int ALLOW_CHILD_INDEX_ORDER_READ = CapabilityBits.ORDERED_GROUP_ALLOW_CHILD_INDEX_ORDER_READ;
083:
084: /**
085: * Specifies that this OrderedGroup node
086: * allows writing its child index order information.
087: *
088: * @since Java 3D 1.3
089: */
090: public static final int ALLOW_CHILD_INDEX_ORDER_WRITE = CapabilityBits.ORDERED_GROUP_ALLOW_CHILD_INDEX_ORDER_WRITE;
091:
092: // Array for setting default read capabilities
093: private static final int[] readCapabilities = { ALLOW_CHILD_INDEX_ORDER_READ };
094:
095: /**
096: * Constructs and initializes a new OrderedGroup node object.
097: * The childIndexOrder array is initialized to null, meaning
098: * that its children are rendered in increasing index order.
099: */
100: public OrderedGroup() {
101: // set default read capabilities
102: setDefaultReadCapabilities(readCapabilities);
103: }
104:
105: /**
106: * Sets the childIndexOrder array. If the specified array is
107: * null, this node's childIndexOrder array is set to null. Its
108: * children will then be rendered in increasing index order. If
109: * the specified array is not null, the entire array is copied to
110: * this node's childIndexOrder array. In this case, the length of
111: * the array must be equal to the number of children in this
112: * group, and every entry in the array must have a unique value
113: * between 0 and <code>numChildren-1</code> (i.e., there must be
114: * no duplicate values and no missing indices).
115: *
116: * @param childIndexOrder the array that is copied into this
117: * node's child index order array; this can be null
118: *
119: * @exception IllegalArgumentException if the specified array is
120: * non-null and any of the following are true:
121: * <ul>
122: * <li><code>childIndexOrder.length != numChildren</code>;</li>
123: * <li><code>childIndexOrder[</code><i>i</i><code>] < 0</code>,
124: * for <i>i</i> in <code>[0, numChildren-1]</code>;</li>
125: * <li><code>childIndexOrder[</code><i>i</i><code>] >= numChildren</code>,
126: * for <i>i</i> in <code>[0, numChildren-1]</code>;</li>
127: * <li><code>childIndexOrder[</code><i>i</i><code>] ==
128: * childIndexOrder[</code><i>j</i><code>]</code>,
129: * for <i>i</i>,<i>j</i> in <code>[0, numChildren-1]</code>,
130: * <i>i</i> <code>!=</code> <i>j</i>;</li>
131: * </ul>
132: *
133: * @exception CapabilityNotSetException if appropriate capability is
134: * not set and this object is part of live or compiled scene graph
135: *
136: * @since Java 3D 1.3
137: */
138: public void setChildIndexOrder(int[] childIndexOrder) {
139: verifyChildIndexOrderArray(childIndexOrder, 0);
140:
141: ((OrderedGroupRetained) retained)
142: .setChildIndexOrder(childIndexOrder);
143: }
144:
145: /**
146: * Retrieves the current childIndexOrder array.
147: *
148: * @return a copy of this node's childIndexOrder array; this
149: * can be null.
150: *
151: * @exception CapabilityNotSetException if appropriate capability is
152: * not set and this object is part of live or compiled scene graph
153: *
154: * @since Java 3D 1.3
155: */
156: public int[] getChildIndexOrder() {
157:
158: if (isLiveOrCompiled())
159: if (!this .getCapability(ALLOW_CHILD_INDEX_ORDER_READ))
160: throw new CapabilityNotSetException(J3dI18N
161: .getString("OrderedGroup5"));
162:
163: return ((OrderedGroupRetained) this .retained)
164: .getChildIndexOrder();
165: }
166:
167: /**
168: * Appends the specified child node to this group node's list of
169: * children, and sets the child index order array to the specified
170: * array. If the specified array is null, this node's
171: * childIndexOrder array is set to null. Its children will then
172: * be rendered in increasing index order. If the specified array
173: * is not null, the entire array is copied to this node's
174: * childIndexOrder array. In this case, the length of the array
175: * must be equal to the number of children in this group after the
176: * new child has been added, and every entry in the array must
177: * have a unique value between 0 and <code>numChildren-1</code>
178: * (i.e., there must be no duplicate values and no missing
179: * indices).
180: *
181: * @param child the child to add to this node's list of children
182: *
183: * @param childIndexOrder the array that is copied into this
184: * node's child index order array; this can be null
185: *
186: * @exception CapabilityNotSetException if the appropriate capability is
187: * not set and this group node is part of live or compiled scene graph
188: *
189: * @exception RestrictedAccessException if this group node is part
190: * of live
191: * or compiled scene graph and the child node being added is not
192: * a BranchGroup node
193: *
194: * @exception MultipleParentException if <code>child</code> has already
195: * been added as a child of another group node.
196: *
197: * @exception IllegalArgumentException if the specified array is
198: * non-null and any of the following are true:
199: * <ul>
200: * <li><code>childIndexOrder.length != numChildren</code>;</li>
201: * <li><code>childIndexOrder[</code><i>i</i><code>] < 0</code>,
202: * for <i>i</i> in <code>[0, numChildren-1]</code>;</li>
203: * <li><code>childIndexOrder[</code><i>i</i><code>] >= numChildren</code>,
204: * for <i>i</i> in <code>[0, numChildren-1]</code>;</li>
205: * <li><code>childIndexOrder[</code><i>i</i><code>] ==
206: * childIndexOrder[</code><i>j</i><code>]</code>,
207: * for <i>i</i>,<i>j</i> in <code>[0, numChildren-1]</code>,
208: * <i>i</i> <code>!=</code> <i>j</i>;</li>
209: * </ul>
210: *
211: * @since Java 3D 1.3
212: */
213: public void addChild(Node child, int[] childIndexOrder) {
214:
215: verifyAddStates(child);
216: verifyChildIndexOrderArray(childIndexOrder, 1);
217:
218: ((OrderedGroupRetained) retained).addChild(child,
219: childIndexOrder);
220:
221: }
222:
223: // Overridden methods from Group
224:
225: /**
226: * Appends the specified child node to this group node's list of children.
227: *
228: * <p>
229: * If the current child index order array is non-null, the array
230: * is increased in size by one element, and a new element
231: * containing the index of the new child is added to the end of
232: * the array. Thus, this new child will be rendered last.
233: *
234: * @param child the child to add to this node's list of children
235: * @exception CapabilityNotSetException if the appropriate capability is
236: * not set and this group node is part of live or compiled scene graph
237: * @exception RestrictedAccessException if this group node is part
238: * of live
239: * or compiled scene graph and the child node being added is not
240: * a BranchGroup node
241: * @exception MultipleParentException if <code>child</code> has already
242: * been added as a child of another group node.
243: *
244: * @since Java 3D 1.3
245: */
246: public void addChild(Node child) {
247: // Just call super -- the extra work is done by the retained class
248: super .addChild(child);
249: }
250:
251: /**
252: * Inserts the specified child node in this group node's list of
253: * children at the specified index.
254: * This method is only supported when the child index order array
255: * is null.
256: *
257: * @param child the new child
258: * @param index at which location to insert. The <code>index</code>
259: * must be a value
260: * greater than or equal to 0 and less than or equal to
261: * <code>numChildren()</code>.
262: * @exception CapabilityNotSetException if the appropriate capability is
263: * not set and this group node is part of live or compiled scene graph
264: * @exception RestrictedAccessException if this group node is part of
265: * live
266: * or compiled scene graph and the child node being inserted is not
267: * a BranchGroup node
268: * @exception MultipleParentException if <code>child</code> has already
269: * been added as a child of another group node.
270: * @exception IndexOutOfBoundsException if <code>index</code> is invalid.
271: * @exception IllegalStateException if the childIndexOrder array is
272: * not null.
273: *
274: * @since Java 3D 1.3
275: */
276: public void insertChild(Node child, int index) {
277: if (((OrderedGroupRetained) retained).userChildIndexOrder != null) {
278: throw new IllegalStateException(J3dI18N
279: .getString("OrderedGroup6"));
280: }
281:
282: // Just call super -- the extra work is done by the retained class
283: super .insertChild(child, index);
284: }
285:
286: /**
287: * Removes the child node at the specified index from this group node's
288: * list of children.
289: *
290: * <p>
291: * If the current child index order array is non-null, the element
292: * containing the removed child's index will be removed from the
293: * child index order array, and the array will be reduced in size
294: * by one element. If the child removed was not the last child in
295: * the Group, the values of the child index order array will be
296: * updated to reflect the indices that were renumbered. More
297: * formally, each child whose index in the Group node was greater
298: * than the removed element (before removal) will have its index
299: * decremented by one.
300: *
301: * @param index which child to remove. The <code>index</code>
302: * must be a value
303: * greater than or equal to 0 and less than <code>numChildren()</code>.
304: * @exception CapabilityNotSetException if the appropriate capability is
305: * not set and this group node is part of live or compiled scene graph
306: * @exception RestrictedAccessException if this group node is part of
307: * live or compiled scene graph and the child node being removed is not
308: * a BranchGroup node
309: * @exception IndexOutOfBoundsException if <code>index</code> is invalid.
310: *
311: * @since Java 3D 1.3
312: */
313: public void removeChild(int index) {
314: // Just call super -- the extra work is done by the retained class
315: super .removeChild(index);
316: }
317:
318: /**
319: * Moves the specified branch group node from its existing location to
320: * the end of this group node's list of children.
321: *
322: * <p>
323: * If the current child index order array is non-null, the array
324: * is increased in size by one element, and a new element
325: * containing the index of the new child is added to the end of
326: * the array. Thus, this new child will be rendered last.
327: *
328: * @param branchGroup the branch group node to move to this node's list
329: * of children
330: * @exception CapabilityNotSetException if the appropriate capability is
331: * not set and this group node is part of live or compiled scene graph
332: *
333: * @since Java 3D 1.3
334: */
335: public void moveTo(BranchGroup branchGroup) {
336: // Just call super -- the extra work is done by the retained class
337: super .moveTo(branchGroup);
338: }
339:
340: /**
341: * Removes the specified child node from this group node's
342: * list of children.
343: * If the specified object is not in the list, the list is not modified.
344: *
345: * <p>
346: * If the current child index order array is non-null, the element
347: * containing the removed child's index will be removed from the
348: * child index order array, and the array will be reduced in size
349: * by one element. If the child removed was not the last child in
350: * the Group, the values of the child index order array will be
351: * updated to reflect the indices that were renumbered. More
352: * formally, each child whose index in the Group node was greater
353: * than the removed element (before removal) will have its index
354: * decremented by one.
355: *
356: * @param child the child node to be removed.
357: * @exception CapabilityNotSetException if appropriate capability is
358: * not set and this object is part of live or compiled scene graph
359: * @exception RestrictedAccessException if this group node is part of
360: * live or compiled scene graph and the child node being removed is not
361: * a BranchGroup node
362: *
363: * @since Java 3D 1.3
364: */
365: public void removeChild(Node child) {
366: // Just call super -- the extra work is done by the retained class
367: super .removeChild(child);
368: }
369:
370: /**
371: * Removes all children from this Group node.
372: *
373: * <p>
374: * If the current child index order array is non-null, then it is set to
375: * a zero-length array (the empty set). Note that a zero-length
376: * child index order array is not the same as a null array in that
377: * as new elements are added, the child index order array will grow
378: * and will be used instead of the Group's natural child order.
379: *
380: * @exception CapabilityNotSetException if appropriate capability is
381: * not set and this object is part of live or compiled scene graph
382: * @exception RestrictedAccessException if this group node is part of
383: * live or compiled scene graph and any of the children being removed are
384: * not BranchGroup nodes
385: *
386: * @since Java 3D 1.3
387: */
388: public void removeAllChildren() {
389: // Just call super -- the extra work is done by the retained class
390: super .removeAllChildren();
391: }
392:
393: /**
394: * Creates the retained mode OrderedGroupRetained object that this
395: * OrderedGroup component object will point to.
396: */
397: void createRetained() {
398: this .retained = new OrderedGroupRetained();
399: this .retained.setSource(this );
400: }
401:
402: void verifyAddStates(Node child) {
403:
404: if (child instanceof SharedGroup) {
405: throw new IllegalArgumentException(J3dI18N
406: .getString("Group2"));
407: }
408:
409: if (isLiveOrCompiled()) {
410: if (!(child instanceof BranchGroup))
411: throw new RestrictedAccessException(J3dI18N
412: .getString("Group12"));
413:
414: if (!this .getCapability(ALLOW_CHILDREN_EXTEND))
415: throw new CapabilityNotSetException(J3dI18N
416: .getString("Group16"));
417: }
418: }
419:
420: void verifyChildIndexOrderArray(int[] cIOArr, int plus) {
421:
422: if (isLiveOrCompiled()) {
423:
424: if (!this .getCapability(ALLOW_CHILD_INDEX_ORDER_WRITE))
425: throw new CapabilityNotSetException(J3dI18N
426: .getString("OrderedGroup4"));
427: }
428:
429: if (cIOArr != null) {
430:
431: if (cIOArr.length != (((GroupRetained) retained).children
432: .size() + plus)) {
433: throw new IllegalArgumentException(J3dI18N
434: .getString("OrderedGroup0"));
435: }
436:
437: if ((checkArr == null)
438: || (checkArr.length != cIOArr.length)) {
439: checkArr = new boolean[cIOArr.length];
440: }
441:
442: Arrays.fill(checkArr, false);
443:
444: for (int i = 0; i < cIOArr.length; i++) {
445: if (cIOArr[i] < 0) {
446: throw new IllegalArgumentException(J3dI18N
447: .getString("OrderedGroup1"));
448: } else if (cIOArr[i] >= cIOArr.length) {
449: throw new IllegalArgumentException(J3dI18N
450: .getString("OrderedGroup2"));
451: } else if (checkArr[cIOArr[i]]) {
452: throw new IllegalArgumentException(J3dI18N
453: .getString("OrderedGroup3"));
454: } else {
455: checkArr[cIOArr[i]] = true;
456: }
457: }
458: }
459: }
460:
461: /**
462: * Used to create a new instance of the node. This routine is called
463: * by <code>cloneTree</code> to duplicate the current node.
464: * @param forceDuplicate when set to <code>true</code>, causes the
465: * <code>duplicateOnCloneTree</code> flag to be ignored. When
466: * <code>false</code>, the value of each node's
467: * <code>duplicateOnCloneTree</code> variable determines whether
468: * NodeComponent data is duplicated or copied.
469: *
470: * @see Node#cloneTree
471: * @see Node#cloneNode
472: * @see Node#duplicateNode
473: * @see NodeComponent#setDuplicateOnCloneTree
474: */
475: public Node cloneNode(boolean forceDuplicate) {
476: OrderedGroup og = new OrderedGroup();
477: og.duplicateNode(this, forceDuplicate);
478: return og;
479: }
480: }
|