001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.tax;
042:
043: import java.util.Collection;
044: import java.util.Iterator;
045: import java.util.LinkedList;
046:
047: /**
048: * This tree object own a list of its children accessible by getChildNodes().
049: *
050: * @author Libor Kramolis
051: * @version 0.1
052: */
053: public abstract class TreeParentNode extends TreeChild {
054:
055: /** */
056: public static final String PROP_CHILD_LIST = "childList"; // NOI18N
057:
058: /** */
059: private TreeObjectList childList;
060:
061: //
062: // init
063: //
064:
065: /** Creates new TreeParentNode. */
066: protected TreeParentNode() {
067: super ();
068:
069: this .childList = new TreeObjectList(
070: createChildListContentManager());
071: }
072:
073: /** Creates new TreeParentNode -- copy constructor. */
074: protected TreeParentNode(TreeParentNode parentNode, boolean deep) {
075: super (parentNode);
076:
077: this .childList = new TreeObjectList(
078: createChildListContentManager());
079: if (deep) {
080: this .childList.addAll((TreeObjectList) parentNode.childList
081: .clone());
082: }
083: }
084:
085: //
086: // from TreeObject
087: //
088:
089: /** Clone depply tree object.
090: * @return deep clone of this node
091: */
092: public abstract Object clone(boolean deep);
093:
094: /** Call clone (true).
095: * @return deep clone of this node.
096: */
097: public final Object clone() {
098: return clone(true);
099: }
100:
101: /**
102: */
103: public boolean equals(Object object, boolean deep) {
104: if (!!!super .equals(object, deep))
105: return false;
106:
107: TreeParentNode peer = (TreeParentNode) object;
108: if (!!!Util.equals(this .childList, peer.childList)) {
109: return false;
110: }
111:
112: return true;
113: }
114:
115: /*
116: * Merges childlist.
117: */
118: public void merge(TreeObject treeObject)
119: throws CannotMergeException {
120: super .merge(treeObject);
121:
122: TreeParentNode peer = (TreeParentNode) treeObject;
123:
124: childList.merge(peer.childList);
125: }
126:
127: //
128: // itself
129: //
130:
131: /**
132: */
133: public boolean isAssignableChild(TreeChild child) {
134: return childList.isAssignableObject(child);
135: }
136:
137: /**
138: * @return <b>reference</b> to kids
139: */
140: public final TreeObjectList getChildNodes() {
141: return childList;
142: }
143:
144: //
145: // read only
146: //
147:
148: /**
149: */
150: protected void setReadOnly(boolean newReadOnly) {
151: super .setReadOnly(newReadOnly);
152:
153: childList.setReadOnly(newReadOnly);
154: }
155:
156: //
157: // Children manipulation
158: //
159:
160: /**
161: */
162: public final TreeChild getFirstChild() {
163: if (childList.size() == 0) {
164: return null;
165: }
166: return (TreeChild) childList.get(0);
167: }
168:
169: /**
170: */
171: public final TreeChild getLastChild() {
172: if (childList.size() == 0) {
173: return null;
174: }
175: return (TreeChild) childList.get(childList.size() - 1);
176: }
177:
178: /**
179: * @throws ReadOnlyException
180: */
181: public final void insertBefore(TreeChild newChild,
182: TreeChild refChild) throws ReadOnlyException {
183: /*
184: if (refChild == null) {
185: // For semantic compatibility with DOM.
186: appendChild(newChild);
187: return;
188: }
189: */
190: childList.checkReadOnly();
191: int index = childList.indexOf(refChild);
192: if (index < 0) {
193: return;
194: }
195: childList.add(index, newChild);
196: }
197:
198: /**
199: * @throws ReadOnlyException
200: */
201: public final void replaceChild(TreeChild oldChild,
202: TreeChild newChild) throws ReadOnlyException {
203: if (Util.THIS.isLoggable()) /* then */
204: Util.THIS
205: .debug("\nTreeParentNode::replaceChild: oldChild = "
206: + oldChild); // NOI18N
207: if (Util.THIS.isLoggable()) /* then */
208: Util.THIS.debug(" ::replaceChild: newChild = "
209: + newChild); // NOI18N
210:
211: childList.checkReadOnly();
212: int index = childList.indexOf(oldChild);
213:
214: if (Util.THIS.isLoggable()) /* then */
215: Util.THIS
216: .debug(" ::replaceChild: childList [oldChild] = "
217: + index); // NOI18N
218:
219: if (index < 0) {
220: return;
221: }
222: childList.set(index, newChild);
223: }
224:
225: /**
226: * @throws ReadOnlyException
227: */
228: public final void removeChild(TreeChild oldChild)
229: throws ReadOnlyException {
230: childList.checkReadOnly();
231: childList.remove(oldChild);
232: }
233:
234: /**
235: * @throws ReadOnlyException
236: */
237: public final void appendChild(TreeChild newChild)
238: throws ReadOnlyException {
239: childList.checkReadOnly();
240: childList.add(newChild);
241: }
242:
243: /**
244: * Insert child at specified position and set its parent and owner document.
245: * @throws ReadOnlyException
246: */
247: public final void insertChildAt(TreeChild child, int index)
248: throws ReadOnlyException {
249: childList.checkReadOnly();
250: childList.add(index, child);
251: }
252:
253: /**
254: */
255: public final int indexOf(TreeChild node) {
256: return childList.indexOf(node);
257: }
258:
259: /**
260: */
261: public final TreeChild item(int index) {
262: return (TreeChild) childList.get(index);
263: }
264:
265: /**
266: */
267: public final int getChildrenNumber() {
268: return (childList.size());
269: }
270:
271: /**
272: */
273: public final boolean hasChildNodes() {
274: return (!!!childList.isEmpty());
275: }
276:
277: /**
278: */
279: public final boolean hasChildNodes(Class childClass) {
280: return hasChildNodes(childClass, false);
281: }
282:
283: /**
284: */
285: public boolean hasChildNodes(Class childClass, boolean recursive) {
286: Iterator it = getChildNodes().iterator();
287: while (it.hasNext()) {
288: TreeChild child = (TreeChild) it.next();
289:
290: // add matching leaf node
291:
292: if (childClass == null
293: || childClass.isAssignableFrom(child.getClass())) {
294: return true;
295: }
296:
297: // do recursive descent into kids
298:
299: if (recursive && (child instanceof TreeParentNode)) {
300: if (((TreeParentNode) child).hasChildNodes(childClass,
301: true) == true) {
302: return true;
303: }
304: }
305: }
306: return false;
307: }
308:
309: /**
310: * @return copy collection containing references
311: */
312: public final Collection getChildNodes(Class childClass) {
313: return getChildNodes(childClass, false);
314: }
315:
316: /**
317: * @return copy collection containing references
318: */
319: public Collection getChildNodes(Class childClass, boolean recursive) {
320:
321: // new RuntimeException(getClass().toString() + ".getChildNodes(" + childClass.toString() + "," + recursive + ")").printStackTrace(); // NOI18N
322:
323: Collection allChildNodes = new LinkedList();
324: Iterator it = getChildNodes().iterator();
325: while (it.hasNext()) {
326: TreeChild child = (TreeChild) it.next();
327:
328: // add matching leaf node
329:
330: if (childClass == null
331: || childClass.isAssignableFrom(child.getClass())) {
332: allChildNodes.add(child);
333: }
334:
335: // do recursive descent into kids
336:
337: if (recursive && (child instanceof TreeParentNode)) {
338: allChildNodes.addAll(((TreeParentNode) child)
339: .getChildNodes(childClass, true));
340: }
341: }
342: return allChildNodes;
343: }
344:
345: //
346: // TreeObjectList.ContentManager
347: //
348:
349: /**
350: */
351: protected abstract TreeObjectList.ContentManager createChildListContentManager();
352:
353: /**
354: *
355: */
356: protected abstract class ChildListContentManager extends
357: TreeObjectList.ContentManager {
358:
359: /**
360: */
361: public void checkAssignableObject(Object obj) {
362: super .checkAssignableObject(obj);
363: checkAssignableClass(TreeChild.class, obj);
364: }
365:
366: /**
367: */
368: public void objectInserted(TreeObject obj) {
369: ((TreeChild) obj).setParentNode(TreeParentNode.this );
370: TreeParentNode.this .firePropertyChange(
371: TreeParentNode.PROP_CHILD_LIST,
372: TreeParentNode.this .childList, obj);
373: }
374:
375: /**
376: */
377: public void objectRemoved(TreeObject obj) {
378: ((TreeChild) obj).setParentNode(null);
379: TreeParentNode.this .firePropertyChange(
380: TreeParentNode.PROP_CHILD_LIST,
381: TreeParentNode.this .childList, obj);
382: }
383:
384: /**
385: */
386: public void orderChanged(int[] permutation) {
387: TreeParentNode.this .firePropertyChange(
388: TreeParentNode.PROP_CHILD_LIST,
389: TreeParentNode.this .childList, permutation);
390: }
391:
392: } // end: class ChildListContentManager
393:
394: }
|