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.openide.explorer.view;
042:
043: import org.openide.nodes.*;
044:
045: import java.util.*;
046:
047: /** List of Visualizers. This is holded by parent visualizer by a
048: * weak reference,
049: *
050: * @author Jaroslav Tulach
051: */
052: final class VisualizerChildren extends Object {
053: /** parent visualizer */
054: public final VisualizerNode parent;
055:
056: /** list of all objects here (VisualizerNode) */
057: public final List<VisualizerNode> list = new ArrayList<VisualizerNode>();
058:
059: /** Creates new VisualizerChildren.
060: * Can be called only from EventQueue.
061: */
062: public VisualizerChildren(VisualizerNode parent, Node[] nodes) {
063: this .parent = parent;
064:
065: int s = nodes.length;
066:
067: for (int i = 0; i < s; i++) {
068: VisualizerNode v = VisualizerNode.getVisualizer(this ,
069: nodes[i]);
070: list.add(v);
071: }
072: }
073:
074: /** Notification of children addded event. Modifies the list of nodes
075: * and fires info to all listeners.
076: */
077: public void added(VisualizerEvent.Added ev) {
078: ListIterator<VisualizerNode> it = list.listIterator();
079: boolean empty = !it.hasNext();
080:
081: int[] indxs = ev.getArray();
082: Node[] nodes = ev.getAdded();
083:
084: int current = 0;
085: int inIndxs = 0;
086:
087: while (inIndxs < indxs.length) {
088: while (current++ < indxs[inIndxs]) {
089: it.next();
090: }
091:
092: it.add(VisualizerNode.getVisualizer(this , nodes[inIndxs]));
093: inIndxs++;
094: }
095:
096: VisualizerNode parent = this .parent;
097:
098: while (parent != null) {
099: Object[] listeners = parent.getListenerList();
100:
101: for (int i = listeners.length - 1; i >= 0; i -= 2) {
102: ((NodeModel) listeners[i]).added(ev);
103: }
104:
105: parent = (VisualizerNode) parent.getParent();
106: }
107:
108: if (empty) {
109: // change of state
110: this .parent.notifyVisualizerChildrenChange(list.size(),
111: this );
112: }
113: }
114:
115: private static boolean sameContains(List l, Object elem) {
116: for (Iterator it = l.iterator(); it.hasNext();) {
117: if (it.next() == elem) {
118: return true;
119: }
120: }
121:
122: return false;
123: }
124:
125: /** Notification that children has been removed. Modifies the list of nodes
126: * and fires info to all listeners.
127: */
128: public void removed(VisualizerEvent.Removed ev) {
129: List remList = Arrays.asList(ev.getRemovedNodes());
130:
131: Iterator it = list.iterator();
132:
133: VisualizerNode vis;
134:
135: int[] indx = new int[remList.size()];
136: int count = 0;
137: int remSize = 0;
138:
139: while (it.hasNext()) {
140: // take visualizer node
141: vis = (VisualizerNode) it.next();
142:
143: // check if it will removed
144: if (sameContains(remList, vis.node)) {
145: indx[remSize++] = count;
146:
147: // remove this VisualizerNode from children
148: it.remove();
149:
150: // bugfix #36389, add the removed node to VisualizerEvent
151: ev.removed.add(vis);
152: }
153:
154: count++;
155: }
156:
157: // notify event about changed indexes
158: ev.setRemovedIndicies(indx);
159:
160: VisualizerNode parent = this .parent;
161:
162: while (parent != null) {
163: Object[] listeners = parent.getListenerList();
164:
165: for (int i = listeners.length - 1; i >= 0; i -= 2) {
166: ((NodeModel) listeners[i]).removed(ev);
167: }
168:
169: parent = (VisualizerNode) parent.getParent();
170: }
171:
172: if (list.isEmpty()) {
173: // now is empty
174: this .parent.notifyVisualizerChildrenChange(0, this );
175: }
176: }
177:
178: /**
179: * Issue 37802, sort the actual list of children with the comparator,
180: * rather than expecting it to match the current children of the node,
181: * which may be in an inconsistent state.
182: */
183: private int[] reorderByComparator(Comparator<VisualizerNode> c) {
184: VisualizerNode[] old = list.toArray(new VisualizerNode[list
185: .size()]);
186: Arrays.sort(old, c);
187:
188: int[] idxs = new int[old.length];
189:
190: for (int i = 0; i < idxs.length; i++) {
191: idxs[i] = list.indexOf(old[i]);
192: }
193:
194: list.clear();
195: list.addAll(Arrays.asList(old));
196:
197: return idxs;
198: }
199:
200: /** Notification that children has been reordered. Modifies the list of nodes
201: * and fires info to all listeners.
202: */
203: public void reordered(VisualizerEvent.Reordered ev) {
204: if (ev.getComparator() != null) {
205: //#37802
206: ev.array = reorderByComparator(ev.getComparator());
207: } else {
208: int[] indxs = ev.getArray();
209: VisualizerNode[] old = list.toArray(new VisualizerNode[list
210: .size()]);
211: VisualizerNode[] arr = new VisualizerNode[old.length];
212:
213: int s = indxs.length;
214:
215: try {
216: for (int i = 0; i < s; i++) {
217: // arr[indxs[i]] = old[i];
218: VisualizerNode old_i = old[i];
219: int indxs_i = indxs[i];
220:
221: if (arr[indxs_i] != null) {
222: // this is bad <-- we are rewriting some old value --> there will remain some null somewhere
223: System.err
224: .println("Writing to this index for the second time: "
225: + indxs_i); // NOI18N
226: System.err.println("Length of indxs array: "
227: + indxs.length); // NOI18N
228: System.err.println("Length of actual array: "
229: + old.length); // NOI18N
230: System.err.println("Indices of reorder event:"); // NOI18N
231:
232: for (int j = 0; i < indxs.length; j++)
233: System.err.println("\t" + indxs[j]); // NOI18N
234:
235: Thread.dumpStack();
236:
237: return;
238: }
239:
240: arr[indxs_i] = old_i;
241: }
242: } catch (ArrayIndexOutOfBoundsException e) {
243: e.printStackTrace();
244: System.err.println("Length of actual array: "
245: + old.length); // NOI18N
246: System.err.println("Indices of reorder event:"); // NOI18N
247:
248: for (int i = 0; i < indxs.length; i++)
249: System.err.println("\t" + indxs[i]); // NOI18N
250:
251: return;
252: }
253:
254: assert !Arrays.asList(arr).contains(null) : "Null element in reorderer list "
255: + Arrays.asList(arr)
256: + "; list="
257: + list
258: + " indxs="
259: + Arrays.asList(org.openide.util.Utilities
260: .toObjectArray(indxs));
261: list.clear();
262: list.addAll(Arrays.asList(arr));
263: assert !list.contains(null);
264: }
265:
266: VisualizerNode parent = this .parent;
267:
268: while (parent != null) {
269: Object[] listeners = parent.getListenerList();
270:
271: for (int i = listeners.length - 1; i >= 0; i -= 2) {
272: ((NodeModel) listeners[i]).reordered(ev);
273: }
274:
275: parent = (VisualizerNode) parent.getParent();
276: }
277: }
278: }
|