KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > nodes > Index


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.nodes;
20
21 import java.util.*;
22
23 import javax.swing.event.ChangeEvent JavaDoc;
24 import javax.swing.event.ChangeListener JavaDoc;
25
26
27 /** Index cookie providing operations useful for reordering
28 * child nodes. {@link IndexedNode} is the common implementation.
29 *
30 * @author Jaroslav Tulach, Dafe Simonek
31 */

32 public interface Index extends Node.Cookie {
33     /** Get the number of nodes.
34     * @return the count
35     */

36     public int getNodesCount();
37
38     /** Get the child nodes.
39     * @return array of nodes that can be sorted by this index
40     */

41     public Node[] getNodes();
42
43     /** Get the index of a given node.
44     * @param node node to find index of
45     * @return index of the node, or <code>-1</code> if no such node was found
46     */

47     public int indexOf(final Node node);
48
49     /** Invoke a dialog for reordering the children.
50     */

51     public void reorder();
52
53     /** Reorder all children with a given permutation.
54     * @param perm permutation with the length of current nodes. The permutation
55     * lists the new positions of the original nodes, that is, for nodes
56     * <code>[A,B,C,D]</code> and permutation <code>[0,3,1,2]</code>, the final
57     * order would be <code>[A,C,D,B]</code>.
58     * @exception IllegalArgumentException if the permutation is not valid
59     */

60     public void reorder(int[] perm);
61
62     /** Move the element at the <code>x</code>-th position to the <code>y</code>-th position. All
63     * elements after the <code>y</code>-th position are moved down.
64     *
65     * @param x the position to remove the element from
66     * @param y the position to insert the element to
67     * @exception IndexOutOfBoundsException if an index is out of bounds
68     */

69     public void move(int x, int y);
70
71     /** Exchange two elements.
72     * @param x position of the first element
73     * @param y position of the second element
74     * @exception IndexOutOfBoundsException if an index is out of bounds
75     */

76     public void exchange(int x, int y);
77
78     /** Move an element up.
79     * @param x index of element to move up
80     * @exception IndexOutOfBoundsException if an index is out of bounds
81     */

82     public void moveUp(int x);
83
84     /** Move an element down.
85     * @param x index of element to move down
86     * @exception IndexOutOfBoundsException if an index is out of bounds
87     */

88     public void moveDown(int x);
89
90     /** Add a new listener to the listener list. The listener will be notified of
91     * any change in the order of the nodes.
92     *
93     * @param chl new listener
94     */

95     public void addChangeListener(final ChangeListener JavaDoc chl);
96
97     /** Remove a listener from the listener list.
98     *
99     * @param chl listener to remove
100     */

101     public void removeChangeListener(final ChangeListener JavaDoc chl);
102
103     /*********************** Inner classes ***********************/
104     /** A support class implementing some methods of the <code>Index</code>
105     * cookie.
106     */

107     public static abstract class Support implements Index {
108         /** Registered listeners */
109         private HashSet<ChangeListener JavaDoc> listeners;
110
111         /** Default constructor. */
112         public Support() {
113         }
114
115         /* Moves element at x-th position to y-th position. All
116         * elements after the y-th position are moved down.
117         *
118         * @param x the position to remove the element from
119         * @param y the position to insert the element to
120         * @exception IndexOutOfBoundsException if an index is out of bounds
121         */

122         public void move(final int x, final int y) {
123             int[] perm = new int[getNodesCount()];
124
125             // if the positions are the same then no move
126
if (x == y) {
127                 return;
128             }
129
130             for (int i = 0; i < perm.length; i++) {
131                 if (((i < x) && (i < y)) || ((i > x) && (i > y))) {
132                     // this area w/o change
133
perm[i] = i;
134                 } else {
135                     if ((i > x) && (i < y)) {
136                         // i-th element moves backward
137
perm[i] = i - 1;
138                     } else {
139                         // i-th element moves forward
140
perm[i] = i + 1;
141                     }
142                 }
143             }
144
145             // set new positions for the elemets on x-th and y-th position
146
perm[x] = y;
147
148             if (x < y) {
149                 perm[y] = y - 1;
150             } else {
151                 perm[y] = y + 1;
152             }
153
154             reorder(perm);
155         }
156
157         /* Exchanges two elements.
158         * @param x position of the first element
159         * @param y position of the second element
160         * @exception IndexOutOfBoundsException if an index is out of bounds
161         */

162         public void exchange(final int x, final int y) {
163             int[] perm = new int[getNodesCount()];
164
165             for (int i = 0; i < perm.length; i++) {
166                 perm[i] = i;
167             }
168
169             perm[x] = y;
170             perm[y] = x;
171
172             reorder(perm);
173         }
174
175         /* Moves element up.
176         * @param x index of element to move up
177         * @exception IndexOutOfBoundsException if an index is out of bounds
178         */

179         public void moveUp(final int x) {
180             exchange(x, x - 1);
181         }
182
183         /* Moves element down.
184         * @param x index of element to move down
185         * @exception IndexOutOfBoundsException if an index is out of bounds
186         */

187         public void moveDown(final int x) {
188             exchange(x, x + 1);
189         }
190
191         /* Adds new listener to the listener list. Listener is notified of
192         * any change in ordering of nodes.
193         *
194         * @param chl new listener
195         */

196         public void addChangeListener(final ChangeListener JavaDoc chl) {
197             if (listeners == null) {
198                 listeners = new HashSet<ChangeListener JavaDoc>();
199             }
200
201             listeners.add(chl);
202         }
203
204         /* Removes listener from the listener list.
205         * Removed listener isn't notified no more.
206         *
207         * @param chl listener to remove
208         */

209         public void removeChangeListener(final ChangeListener JavaDoc chl) {
210             if (listeners == null) {
211                 return;
212             }
213
214             listeners.remove(chl);
215         }
216
217         /** Fires notification about reordering to all
218         * registered listeners.
219         *
220         * @param che change event to fire off
221         */

222         protected void fireChangeEvent(ChangeEvent JavaDoc che) {
223             if (listeners == null) {
224                 return;
225             }
226
227             HashSet cloned;
228
229             // clone listener list
230
synchronized (this) {
231                 cloned = (HashSet) listeners.clone();
232             }
233
234             // fire on cloned list to prevent from modifications when firing
235
for (Iterator iter = cloned.iterator(); iter.hasNext();) {
236                 ((ChangeListener JavaDoc) iter.next()).stateChanged(che);
237             }
238         }
239
240         /** Get the nodes; should be overridden if needed.
241         * @return the nodes
242         */

243         public abstract Node[] getNodes();
244
245         /** Get the index of a node. Simply scans through the array returned by {@link #getNodes}.
246         * @param node the node
247         * @return the index, or <code>-1</code> if the node was not found
248         */

249         public int indexOf(final Node node) {
250             Node[] arr = getNodes();
251
252             for (int i = 0; i < arr.length; i++) {
253                 if (node.equals(arr[i])) {
254                     return i;
255                 }
256             }
257
258             return -1;
259         }
260
261         /** Reorder the nodes with dialog; should be overridden if needed.
262         */

263         public void reorder() {
264             showIndexedCustomizer(this);
265         }
266
267         /** Utility method to create and show an indexed customizer.
268          * Displays some sort of dialog permitting the index cookie to be reordered.
269          * Blocks until the reordering is performed (or cancelled).
270          * @param idx the index cookie to reorder based on
271          * @since 1.37
272          */

273         public static void showIndexedCustomizer(Index idx) {
274             TMUtil.showIndexedCustomizer(idx);
275         }
276
277         /** Get the node count. Subclasses must provide this.
278         * @return the count
279         */

280         public abstract int getNodesCount();
281
282         /** Reorder by permutation. Subclasses must provide this.
283         * @param perm the permutation
284         */

285         public abstract void reorder(int[] perm);
286     }
287      // end of Support inner class
288

289     /** Reorderable children list stored in an array.
290     */

291     public static class ArrayChildren extends Children.Array implements Index {
292         /** Support instance for delegation of some <code>Index</code> methods. */
293         protected Index support;
294
295         /** Constructor for the support.
296         */

297         public ArrayChildren() {
298             this(null);
299         }
300
301         /** Constructor.
302         * @param ar the array
303         */

304         private ArrayChildren(List<Node> ar) {
305             super(ar);
306
307             // create support instance for delegation of common tasks
308
support = new Support() {
309                         public Node[] getNodes() {
310                             return ArrayChildren.this.getNodes();
311                         }
312
313                         public int getNodesCount() {
314                             return ArrayChildren.this.getNodesCount();
315                         }
316
317                         public void reorder(int[] perm) {
318                             ArrayChildren.this.reorder(perm);
319                             fireChangeEvent(new ChangeEvent JavaDoc(ArrayChildren.this));
320                         }
321                     };
322         }
323
324         /** If default constructor is used, then this method is called to lazily create
325         * the collection. Even it claims that it returns Collection only subclasses
326         * of List are valid values.
327         * <P>
328         * This implementation returns ArrayList.
329         *
330         * @return any List collection.
331         */

332         @Override JavaDoc
333         protected java.util.List JavaDoc<Node> initCollection() {
334             return new ArrayList<Node>();
335         }
336
337         /* Reorders all children with given permutation.
338         * @param perm permutation with the length of current nodes
339         * @exception IllegalArgumentException if the perm is not valid permutation
340         */

341         public void reorder(final int[] perm) {
342             try {
343                 PR.enterWriteAccess();
344
345                 Node[] n = nodes.toArray(new Node[nodes.size()]);
346                 List<Node> l = (List<Node>) nodes;
347
348                 for (int i = 0; i < n.length; i++) {
349                     l.set(perm[i], n[i]);
350                 }
351
352                 refresh();
353             } finally {
354                 PR.exitWriteAccess();
355             }
356         }
357
358         /** Invokes a dialog for reordering children using {@link IndexedCustomizer}.
359         */

360         public void reorder() {
361             try {
362                 PR.enterReadAccess();
363                 Support.showIndexedCustomizer(this);
364             } finally {
365                 PR.exitReadAccess();
366             }
367         }
368
369         /* Moves element at x-th position to y-th position. All
370         * elements after the y-th position are moved down.
371         * Delegates functionality to Index.Support.
372         *
373         * @param x the position to remove the element from
374         * @param y the position to insert the element to
375         * @exception IndexOutOfBoundsException if an index is out of bounds
376         */

377         public void move(final int x, final int y) {
378             support.move(x, y);
379         }
380
381         /* Exchanges two elements.
382         * Delegates functionality to Index.Support.
383         * @param x position of the first element
384         * @param y position of the second element
385         * @exception IndexOutOfBoundsException if an index is out of bounds
386         */

387         public void exchange(final int x, final int y) {
388             support.exchange(x, y);
389         }
390
391         /* Moves element up.
392         * Delegates functionality to Index.Support.
393         * @param x index of element to move up
394         * @exception IndexOutOfBoundsException if an index is out of bounds
395         */

396         public void moveUp(final int x) {
397             support.exchange(x, x - 1);
398         }
399
400         /* Moves element down.
401         * Delegates functionality to Index.Support.
402         * @param x index of element to move down
403         * @exception IndexOutOfBoundsException if an index is out of bounds
404         */

405         public void moveDown(final int x) {
406             support.exchange(x, x + 1);
407         }
408
409         /* Returns the index of given node.
410         * @param node Node to find index of.
411         * @return Index of the node, -1 if no such node was found.
412         */

413         public int indexOf(final Node node) {
414             try {
415                 PR.enterReadAccess();
416
417                 return ((List<Node>) nodes).indexOf(node);
418             } finally {
419                 PR.exitReadAccess();
420             }
421         }
422
423         /* Adds new listener to the listener list. Listener is notified of
424         * any change in ordering of nodes.
425         *
426         * @param chl new listener
427         */

428         public void addChangeListener(final ChangeListener JavaDoc chl) {
429             support.addChangeListener(chl);
430         }
431
432         /* Removes listener from the listener list.
433         * Removed listener isn't notified no more.
434         *
435         * @param chl listener to remove
436         */

437         public void removeChangeListener(final ChangeListener JavaDoc chl) {
438             support.removeChangeListener(chl);
439         }
440     }
441      // End of ArrayChildren inner class
442

443     /** Implementation of index interface that operates on an list of
444     * objects that are presented by given nodes.
445     */

446     public abstract class KeysChildren<T> extends Children.Keys<T> {
447         /** Support instance for delegation of some <code>Index</code> methods. */
448         private Index support; // JST: Maybe made protected
449

450         /** list of objects that should be manipulated with this keys */
451         protected final List<T> list;
452
453         /** Constructor.
454         * @param ar the array of any objects
455         */

456         public KeysChildren(List<T> ar) {
457             list = ar;
458             update();
459         }
460
461         /** Getter for the index that works with this children.
462         * @return the index
463         */

464         public Index getIndex() {
465             synchronized (this) {
466                 if (support == null) {
467                     support = createIndex();
468                 }
469
470                 return support;
471             }
472         }
473
474         /** The method that creates the supporting index for this
475         * children object.
476           */

477         protected Index createIndex() {
478             // create support instance for delegation of common tasks
479
return new Support() {
480                     /** Returns only nodes that are indexable. Not any fixed ones.
481                     */

482                     public Node[] getNodes() {
483                         List<Node> l = Arrays.asList(KeysChildren.this.getNodes());
484
485                         if (KeysChildren.this.nodes != null) {
486                             l.removeAll(KeysChildren.this.nodes);
487                         }
488
489                         return l.toArray(new Node[l.size()]);
490                     }
491
492                     public int getNodesCount() {
493                         return list.size();
494                     }
495
496                     public void reorder(int[] perm) {
497                         KeysChildren.this.reorder(perm);
498                         update();
499                         fireChangeEvent(new ChangeEvent JavaDoc(this));
500                     }
501                 };
502         }
503
504         /* Reorders the list with given permutation.
505         * @param perm permutation with the length of current nodes
506         * @exception IllegalArgumentException if the perm is not valid permutation
507         */

508         protected void reorder(final int[] perm) {
509             synchronized (lock()) {
510                 List<T> n = new ArrayList<T>(list);
511
512                 for (int i = 0; i < n.size(); i++) {
513                     list.set(perm[i], n.get(i));
514                 }
515             }
516         }
517
518         /** The lock to use when accessing the list.
519          * By default this implementation returns the list itself, but can
520          * be changed to lock more properly.
521          *
522          * @return lock to use for accessing the list
523          */

524         protected Object JavaDoc lock() {
525             return list;
526         }
527
528         /** Update the status of the list if it has changed.
529         */

530         public final void update() {
531             Collection<T> keys;
532
533             synchronized (lock()) {
534                 keys = new ArrayList<T>(list);
535             }
536
537             super.setKeys(keys);
538         }
539     }
540 }
541
Popular Tags