KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > debug > internal > ui > viewers > model > FilterTransform


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11
12 package org.eclipse.debug.internal.ui.viewers.model;
13
14 import java.util.Arrays JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Map JavaDoc;
17
18 import org.eclipse.jface.viewers.TreePath;
19
20
21 /**
22  * Helper class to support filtering in virtual tree viewer.
23  * Translates indexes from viewer to model coordinate space (and visa versa).
24  * <p>
25  * This filter transform maintains a tree representing filtered elements in the
26  * viewer. The filtering is performed dynamically as elements are 'replaced' in the tree
27  * by a lazy tree content provider.
28  * </p>
29  * <p>
30  * This class not intended to be subclassed or instantiated. For internal use only.
31  * </p>
32  * @since 3.3
33  */

34 public class FilterTransform {
35
36     private Node root = new Node();
37     
38     class Node {
39         private int[] filteredIndexes = null;
40         private Object JavaDoc[] filteredElements = null;
41         private Map JavaDoc children = null; // only set for parent nodes, indexed by child
42

43         Node() {
44         }
45         
46         boolean addFilter(TreePath path, int childIndex, int pathIndex, Object JavaDoc filtered) {
47             if (pathIndex == path.getSegmentCount()) {
48                 if (filteredIndexes == null) {
49                     filteredIndexes = new int[]{childIndex};
50                     filteredElements = new Object JavaDoc[]{filtered};
51                     return true;
52                 }
53                 int location = Arrays.binarySearch(filteredIndexes, childIndex);
54                 if (location >= 0) {
55                     return false;
56                 }
57                 location = 0 - (location + 1);
58                 int[] next = new int[filteredIndexes.length + 1];
59                 Object JavaDoc[] filt = new Object JavaDoc[next.length];
60                 if (location == 0) {
61                     next[0] = childIndex;
62                     filt[0] = filtered;
63                     System.arraycopy(filteredIndexes, 0, next, 1, filteredIndexes.length);
64                     System.arraycopy(filteredElements, 0, filt, 1, filteredElements.length);
65                 } else if (location == filteredIndexes.length) {
66                     next[filteredIndexes.length] = childIndex;
67                     filt[filteredElements.length] = filtered;
68                     System.arraycopy(filteredIndexes, 0, next, 0, filteredIndexes.length);
69                     System.arraycopy(filteredElements, 0, filt, 0, filteredElements.length);
70                 } else {
71                     System.arraycopy(filteredIndexes, 0, next, 0, location);
72                     System.arraycopy(filteredElements, 0, filt, 0, location);
73                     next[location] = childIndex;
74                     filt[location] = filtered;
75                     System.arraycopy(filteredIndexes, location, next, location + 1, filteredIndexes.length - location);
76                     System.arraycopy(filteredElements, location, filt, location + 1, filteredElements.length - location);
77                 }
78                 filteredIndexes = next;
79                 filteredElements = filt;
80                 return true;
81             }
82             
83             if (children == null) {
84                 children = new HashMap JavaDoc();
85             }
86             Object JavaDoc element = path.getSegment(pathIndex);
87             Node node = (Node) children.get(element);
88             if (node == null) {
89                 node = new Node();
90                 children.put(element, node);
91             }
92             return node.addFilter(path, childIndex, pathIndex + 1, filtered);
93         }
94         
95         boolean clear(TreePath path, int pathIndex) {
96             if (pathIndex == path.getSegmentCount()) {
97                 return true;
98             }
99             if (children == null) {
100                 return false;
101             }
102             Object JavaDoc child = path.getSegment(pathIndex);
103             Node node = (Node) children.get(child);
104             if (node != null) {
105                 if (node.clear(path, pathIndex + 1)) {
106                     children.remove(child);
107                 }
108             }
109             return children.isEmpty() && (filteredIndexes == null || filteredIndexes.length == 0);
110         }
111         
112         boolean clear(TreePath path, int childIndex, int pathIndex) {
113             if (pathIndex == path.getSegmentCount()) {
114                 if (filteredIndexes != null) {
115                     int location = Arrays.binarySearch(filteredIndexes, childIndex);
116                     if (location >= 0) {
117                         // remove it
118
if (location == 0 && filteredIndexes.length == 1) {
119                             filteredIndexes = null;
120                             filteredElements = null;
121                             return true;
122                         }
123                         int[] next = new int[filteredIndexes.length - 1];
124                         Object JavaDoc[] filt = new Object JavaDoc[next.length];
125                         if (location == 0) {
126                             System.arraycopy(filteredIndexes, 1, next, 0, next.length);
127                             System.arraycopy(filteredElements, 1, filt, 0, filt.length);
128                         } else if (location == (filteredIndexes.length - 1)) {
129                             System.arraycopy(filteredIndexes, 0, next, 0, location);
130                             System.arraycopy(filteredElements, 0, filt, 0, location);
131                         } else {
132                             System.arraycopy(filteredIndexes, 0, next, 0, location);
133                             System.arraycopy(filteredElements, 0, filt, 0, location);
134                             System.arraycopy(filteredIndexes, location + 1, next, location, next.length - location);
135                             System.arraycopy(filteredElements, location + 1, filt, location, filt.length - location);
136                         }
137                         filteredIndexes = next;
138                         filteredElements = filt;
139                         return false;
140                     }
141                 } else {
142                     return false;
143                 }
144             }
145             if (children == null) {
146                 return false;
147             }
148             Object JavaDoc element = path.getSegment(pathIndex);
149             Node node = (Node) children.get(element);
150             if (node == null) {
151                 return false;
152             }
153             boolean remove = node.clear(path, childIndex, pathIndex + 1);
154             if (remove) {
155                 children.remove(element);
156                 return filteredIndexes == null && children.isEmpty();
157             } else {
158                 return false;
159             }
160         }
161         
162         Node find(TreePath path, int pathIndex) {
163             if (pathIndex == path.getSegmentCount())
164                 return this;
165             if (children == null) {
166                 return null;
167             }
168             Object JavaDoc child = path.getSegment(pathIndex);
169             Node node = (Node) children.get(child);
170             if (node != null) {
171                 return node.find(path, pathIndex + 1);
172             }
173             return null;
174         }
175         
176         int viewToModel(int childIndex) {
177             if (filteredIndexes == null) {
178                 return childIndex;
179             }
180             // If there are filtered children, then we want to find the
181
// (n+1)th missing number in the list of filtered indexes (missing
182
// entries are visible in the view). For example, if the request
183
// has asked for the model index corresponding to the 4th viewer
184
// index, then we want to find the 5th missing number in the
185
// filtered index sequence.
186

187             int count = -1; // count from 0, 1, 2...
188
int missingNumbers = 0; // how many numbers missing from the filtered index
189
int offset = 0; // offset into the filtered index
190

191             while (missingNumbers < (childIndex + 1)) {
192                 count++;
193                 if (offset < filteredIndexes.length) {
194                     if (filteredIndexes[offset] == count) {
195                         // not missing
196
offset++;
197                     } else {
198                         // missing
199
missingNumbers++;
200                     }
201                 } else {
202                     missingNumbers++;
203                 }
204             }
205             return count;
206         }
207         
208         int modelToView(int childIndex) {
209             if (filteredIndexes == null) {
210                 return childIndex;
211             }
212             int offset = 0;
213             for (int i = 0; i < filteredIndexes.length; i++) {
214                 if (childIndex == filteredIndexes[i] ) {
215                     return -1;
216                 } else if (childIndex > filteredIndexes[i]) {
217                     offset++;
218                 } else {
219                     break;
220                 }
221             }
222             return childIndex - offset;
223         }
224         
225         int modelToViewCount(int childCount) {
226             if (filteredIndexes == null) {
227                 return childCount;
228             }
229             return childCount - filteredIndexes.length;
230         }
231         
232         boolean isFiltered(int index) {
233             if (filteredIndexes != null) {
234                 int location = Arrays.binarySearch(filteredIndexes, index);
235                 return location >= 0;
236             }
237             return false;
238         }
239         
240         int indexOfFilteredElement(Object JavaDoc element) {
241             if (filteredElements != null) {
242                 for (int i = 0; i < filteredElements.length; i++) {
243                     if (element.equals(filteredElements[i])) {
244                         return filteredIndexes[i];
245                     }
246                 }
247             }
248             return -1;
249         }
250         
251         /**
252          * Sets the child count for this element, trimming any filtered elements
253          * that were above this count.
254          *
255          * @param childCount new child count
256          */

257         void setModelChildCount(int childCount) {
258             if (filteredIndexes != null) {
259                 for (int i = 0; i < filteredIndexes.length; i++) {
260                     if (filteredIndexes[i] >= childCount) {
261                         // trim
262
if (i == 0) {
263                             filteredIndexes = null;
264                             return;
265                         } else {
266                             int[] temp = new int[i + 1];
267                             System.arraycopy(filteredIndexes, 0, temp, 0, temp.length);
268                             filteredIndexes = temp;
269                         }
270                     }
271                 }
272             }
273         }
274         
275         /**
276          * Updates filter index for a removed element at the given index
277          *
278          * @param index index at which an element was removed
279          */

280         void removeElementFromFilters(int index) {
281             if (filteredIndexes != null) {
282                 int location = Arrays.binarySearch(filteredIndexes, index);
283                 if (location >= 0) {
284                     // remove a filtered item
285
if (filteredIndexes.length == 1) {
286                         // only filtered item
287
filteredIndexes = null;
288                         filteredElements = null;
289                     } else {
290                         int[] next = new int[filteredIndexes.length - 1];
291                         Object JavaDoc[] filt = new Object JavaDoc[next.length];
292                         if (location == 0) {
293                             // first
294
System.arraycopy(filteredIndexes, 1, next, 0, next.length);
295                             System.arraycopy(filteredElements, 1, filt, 0, filt.length);
296                         } else if (location == (filteredIndexes.length - 1)) {
297                             // last
298
System.arraycopy(filteredIndexes, 0, next, 0, next.length);
299                             System.arraycopy(filteredElements, 0, filt, 0, filt.length);
300                         } else {
301                             // middle
302
System.arraycopy(filteredIndexes, 0, next, 0, location);
303                             System.arraycopy(filteredElements, 0, filt, 0, location);
304                             System.arraycopy(filteredIndexes, location + 1, next, location, next.length - location);
305                             System.arraycopy(filteredElements, location + 1, filt, location, filt.length - location);
306                         }
307                         filteredIndexes = next;
308                         filteredElements = filt;
309                     }
310                 } else {
311                     location = 0 - (location + 1);
312                 }
313                 if (filteredIndexes != null) {
314                     // decrement remaining indexes
315
for (int i = location; i < filteredIndexes.length; i ++) {
316                         filteredIndexes[i]--;
317                     }
318                 }
319             }
320         }
321     }
322
323     /**
324      * Filters the specified child of the given parent and returns
325      * whether the child was already filtered.
326      *
327      * @param parentPath path to parent element
328      * @param childIndex index of filtered child relative to parent (in model coordinates)
329      * @param element the filtered element
330      * @return whether the child was already filtered
331      */

332     public synchronized boolean addFilteredIndex(TreePath parentPath, int childIndex, Object JavaDoc element) {
333         return root.addFilter(parentPath, childIndex, 0, element);
334     }
335     
336     /**
337      * Clears all filtered elements.
338      */

339     public synchronized void clear() {
340         root = new Node();
341     }
342     
343     /**
344      * Clears all filters in the subtree of the given element.
345      *
346      * @param path element path
347      */

348     public synchronized void clear(TreePath path) {
349         root.clear(path, 0);
350     }
351     
352     /**
353      * Clears the given filtered index of the specified parent. I.e.
354      * the child still exists, but is no longer filtered.
355      *
356      * @param path parent path
357      * @param index index to clear
358      */

359     public synchronized void clear(TreePath parentPath, int index) {
360         root.clear(parentPath, index, 0);
361     }
362     
363     /**
364      * Translates and returns the given model index (raw index) into
365      * a view index (filtered index), or -1 if filtered.
366      *
367      * @param parentPath path to parent element
368      * @param childIndex index of child element in model space
369      * @return the given index in view coordinates, or -1 if filtered.
370      */

371     public synchronized int modelToViewIndex(TreePath parentPath, int childIndex) {
372         Node parentNode = root.find(parentPath, 0);
373         if (parentNode == null) {
374             return childIndex;
375         }
376         return parentNode.modelToView(childIndex);
377     }
378     
379     /**
380      * Translates and returns the given view index (filtered) into
381      * a model index (raw index).
382      *
383      * @param parentPath path to parent element
384      * @param childIndex index of child element in view space
385      * @return the given index in model coordinates
386      */

387     public synchronized int viewToModelIndex(TreePath parentPath, int childIndex) {
388         Node parentNode = root.find(parentPath, 0);
389         if (parentNode == null) {
390             return childIndex;
391         }
392         return parentNode.viewToModel(childIndex);
393     }
394     
395     /**
396      * Returns the number of children for the given parent, in the model.
397      *
398      * @param parentPath path to parent element
399      * @param viewCount number of children in the view
400      * @return number of children in the model
401      */

402     public synchronized int viewToModelCount(TreePath parentPath, int viewCount) {
403         Node parentNode = root.find(parentPath, 0);
404         if (parentNode != null) {
405             if (parentNode.filteredIndexes != null) {
406                 return viewCount + parentNode.filteredIndexes.length;
407             }
408         }
409         return viewCount;
410     }
411     
412     /**
413      * Translates and returns the given model child count (raw) into
414      * a view count (filtered).
415      *
416      * @param parentPath path to parent element
417      * @param count child count in model space
418      * @return the given count in view coordinates
419      */

420     public synchronized int modelToViewCount(TreePath parentPath, int count) {
421         Node parentNode = root.find(parentPath, 0);
422         if (parentNode == null) {
423             return count;
424         }
425         return parentNode.modelToViewCount(count);
426     }
427     
428     /**
429      * Returns whether the given index of the specified parent is currently filtered.
430      *
431      * @param parentPath path to parent element
432      * @param index index of child element
433      * @return whether the child is currently filtered
434      */

435     public synchronized boolean isFiltered(TreePath parentPath, int index) {
436         Node parentNode = root.find(parentPath, 0);
437         if (parentNode == null) {
438             return false;
439         }
440         return parentNode.isFiltered(index);
441     }
442     
443     /**
444      * Returns filtered children of the given parent, or <code>null</code> if none.
445      *
446      * @param parentPath
447      * @return filtered children or <code>null</code>
448      */

449     public int[] getFilteredChildren(TreePath parentPath) {
450         Node parentNode = root.find(parentPath, 0);
451         if (parentNode == null) {
452             return null;
453         }
454         return parentNode.filteredIndexes;
455     }
456     
457     /**
458      * Clears any filters for the given parent above the given count.
459      *
460      * @param parentPath path to parent element
461      * @param childCount child count
462      */

463     public synchronized void setModelChildCount(TreePath parentPath, int childCount) {
464         Node parentNode = root.find(parentPath, 0);
465         if (parentNode != null) {
466             parentNode.setModelChildCount(childCount);
467         }
468     }
469     
470     /**
471      * The element at the given index has been removed from the parent. Update
472      * indexes.
473      *
474      * @param parentPath path to parent element
475      * @param index index of child element in model coordinates
476      */

477     public synchronized void removeElementFromFilters(TreePath parentPath, int index) {
478         Node parentNode = root.find(parentPath, 0);
479         if (parentNode != null) {
480             parentNode.removeElementFromFilters(index);
481         }
482     }
483     
484     /**
485      * The element has been removed from the parent. Update
486      * filtered indexes, in case it was a filtered object.
487      *
488      * @param parentPath path to parent element
489      * @param element removed element
490      */

491     public synchronized boolean removeElementFromFilters(TreePath parentPath, Object JavaDoc element) {
492         Node parentNode = root.find(parentPath, 0);
493         if (parentNode != null) {
494             int index = parentNode.indexOfFilteredElement(element);
495             if (index >= 0) {
496                 parentNode.removeElementFromFilters(index);
497                 return true;
498             }
499         }
500         return false;
501     }
502 }
503
Popular Tags