KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > gui2 > BugTreeModel


1 /*
2  * FindBugs - Find Bugs in Java programs
3  * Copyright (C) 2006, University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA
18  */

19
20 package edu.umd.cs.findbugs.gui2;
21
22 import java.lang.management.ManagementFactory JavaDoc;
23 import java.lang.management.ThreadMXBean JavaDoc;
24 import java.lang.reflect.InvocationTargetException JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.Arrays JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Vector JavaDoc;
31
32 import javax.swing.JTree JavaDoc;
33 import javax.swing.SwingUtilities JavaDoc;
34 import javax.swing.event.ChangeEvent JavaDoc;
35 import javax.swing.event.ListSelectionEvent JavaDoc;
36 import javax.swing.event.TableColumnModelEvent JavaDoc;
37 import javax.swing.event.TableColumnModelListener JavaDoc;
38 import javax.swing.event.TreeExpansionEvent JavaDoc;
39 import javax.swing.event.TreeExpansionListener JavaDoc;
40 import javax.swing.event.TreeModelEvent JavaDoc;
41 import javax.swing.event.TreeModelListener JavaDoc;
42 import javax.swing.tree.DefaultTreeModel JavaDoc;
43 import javax.swing.tree.TreeModel JavaDoc;
44 import javax.swing.tree.TreeNode JavaDoc;
45 import javax.swing.tree.TreePath JavaDoc;
46
47
48 import edu.umd.cs.findbugs.BugInstance;
49 import edu.umd.cs.findbugs.gui2.BugAspects.StringPair;
50
51 /*
52  * Our TreeModel. Once upon a time it was a simple model, that queried data, its BugSet, for what to show under each branch
53  * Then it got more and more complicated, no one knows why it still seems to work... or why it doesn't if it in fact doesn't.
54  *
55  * Here's a tip, Dont even attempt to deal with suppressions or filtering and their related tree model events without the API
56  * for TreeModelEvents open. And read it three times first. Ignore the fact that its inconsistent for sending events about the root, just pick one of the things it says and go with it
57  *
58  * Heres the order things MUST be done when dealing with suppressions, filtering, unsuppressions... unfiltering... all that fun stuff
59  *
60  * Inserts:
61  * Update model
62  * Get Path
63  * Make Event
64  * Send Event
65  * ResetData
66  *
67  * Removes:
68  * Get Path
69  * Make Event
70  * Update Model
71  * Send Event
72  * ResetData
73  *
74  * Restructure:
75  * Update Model
76  * Get Path
77  * Make Event
78  * Send Event
79  * resetData? hmmm
80  *
81  * These may or may not be the orders of events used in suppressBug, unsuppressBug, branchOperations and so forth
82  * if they seem to work anyway, I wouldn't touch them.
83  *
84  * changeSet() is what to do when the data set is completely different (loaded a new collection, reran the analysis what have you)
85  * changeSet calls rebuild(), which does a very tricky thing, where it makes a new model, and a new JTree, and swaps them in in place of this one, as well as
86  * turning off user input in hopefully every place it needs to be turned off
87  *
88  */

89
90 /**
91  * The treeModel for our JTree
92  */

93     public class BugTreeModel implements TreeModel JavaDoc, TableColumnModelListener JavaDoc, FilterListener, TreeExpansionListener JavaDoc
94     {
95         private BugAspects root = new BugAspects();
96         private SorterTableColumnModel st;
97         private BugSet data;
98         private ArrayList JavaDoc<TreeModelListener JavaDoc> listeners = new ArrayList JavaDoc<TreeModelListener JavaDoc>();
99         private JTree JavaDoc tree;
100         static Vector JavaDoc<BugLeafNode> selectedBugLeafNodes = new Vector JavaDoc<BugLeafNode>();
101
102         
103         private volatile Thread JavaDoc rebuildingThread;
104         private boolean sortOrderChanged;
105         private boolean sortsAddedOrRemoved;
106         
107         
108         public BugTreeModel(JTree JavaDoc tree, SorterTableColumnModel st, BugSet data)
109         {
110             st.addColumnModelListener(this);
111             this.tree = tree;
112             this.st = st;
113             this.data = data;
114             BugSet.setAsRootAndCache(this.data);
115             root.setCount(data.size());
116             FilterMatcher.addFilterListener(this);
117             tree.addTreeExpansionListener(this);
118         }
119         
120         public BugTreeModel(BugTreeModel other)
121         {
122             this.root = new BugAspects(other.root);
123             this.st = other.st;
124             this.data = new BugSet(other.data);
125             //this.listeners = other.listeners;
126
this.tree = other.tree;
127         }
128         
129         public void getOffListenerList()
130         {
131             FilterMatcher.removeFilterListener(this);
132             st.removeColumnModelListener(this);
133             tree.removeTreeExpansionListener(this);
134         }
135         
136         public Object JavaDoc getRoot()
137         {
138             return root;
139         }
140
141         public Object JavaDoc getChild(Object JavaDoc o, int index)
142         {
143             BugAspects a = (BugAspects) o;
144             if (st.getOrderBeforeDivider().size()==0 && a.size()==0)//Root without any sortables
145
return data.get(index);
146
147             if ((a.size() == 0) || (a.last().key != st.getOrderBeforeDivider().get(st.getOrderBeforeDivider().size() - 1)))
148             {
149                 BugAspects child=a.addToNew(enumsThatExist(a).get(index));
150                 child.setCount(data.query(child).size());
151                 return child;
152             }
153             else
154                 return data.query(a).get(index);
155         }
156
157         public int getChildCount(Object JavaDoc o)
158         {
159 // long start = bean.getCurrentThreadCpuTime();
160
// try
161
// {
162
// System.out.println("# getChildCount [o = " + o + "]");
163
// System.out.println("getChildCount: " + Thread.currentThread().toString());
164
BugAspects a = (BugAspects) o;
165                     
166                     if (st.getOrderBeforeDivider().size()==0 && a.size() == 0)//If its the root and we aren't sorting by anything
167
return data.size();
168                     
169                     if ((a.size() == 0) || (a.last().key != st.getOrderBeforeDivider().get(st.getOrderBeforeDivider().size() - 1)))
170 // {
171
// System.out.println("# before enumsThatExist: " + (bean.getCurrentThreadCpuTime() - start));
172
return enumsThatExist(a).size();
173 // }
174
else
175 // {
176
// System.out.println("# before query: " + (bean.getCurrentThreadCpuTime() - start));
177
return data.query(a).size();
178 // }
179
// }
180
// finally
181
// {
182
// System.out.println("# finished: " + (bean.getCurrentThreadCpuTime() - start));
183
// }
184
}
185
186         
187         /*This contract has been changed to return a HashList of Stringpair, our own data structure in which finding the index of an object in the list is very fast*/
188         
189         private HashList<StringPair> enumsThatExist(BugAspects a)
190         {
191         // long start = bean.getCurrentThreadCpuTime();
192
// System.out.println(" ## enumsThatExist [a = " + a + "]");
193
// try
194
// {
195
//StringPair[] toCheck = null;
196
if (st.getOrderBeforeDivider().size()==0)
197                         return null;
198                     
199 // if (a.size() == 0) // root
200
// toCheck = getValues(st.getOrder().get(0));
201
// else if (st.getOrder().indexOf(a.get(a.size() - 1).key) == st.getOrder().size() - 1) // last branch
202
// return null;
203
// else // somewhere in between
204
// toCheck = getValues(st.getOrder().get(st.getOrder().indexOf(a.get(a.size() - 1).key) + 1));
205
// BugSet set = data.query(a);
206
// System.out.println(" ## after query: " + (bean.getCurrentThreadCpuTime() - start));
207
// for (StringPair sp : toCheck)
208
// if (set.contains(sp))
209
// result.add(sp);
210
// System.out.println(" ## after loop (" + toCheck.length + " elements): " + (bean.getCurrentThreadCpuTime() - start));
211
// return result;
212

213                     Sortables key = (a.size() == 0 ?
214                             st.getOrderBeforeDivider().get(0) :
215                                 st.getOrderBeforeDivider().get(st.getOrderBeforeDivider().indexOf(a.last().key) + 1));
216                     
217                     String JavaDoc[] all = key.getAll(data.query(a));
218                     ArrayList JavaDoc<StringPair> result = new ArrayList JavaDoc<StringPair>();
219                     for (String JavaDoc i : all)
220                         result.add(new StringPair(key, i));
221 // System.out.println(" ## before sort: " + (bean.getCurrentThreadCpuTime() - start));
222
// Collections.sort(result, key);
223
// System.out.println(" ## after sort: " + (bean.getCurrentThreadCpuTime() - start));
224
return new HashList<StringPair>(result);
225 // }
226
// finally
227
// {
228
// System.out.println(" ## finished: " + (bean.getCurrentThreadCpuTime() - start));
229
// }
230
}
231         
232         public boolean isLeaf(Object JavaDoc o)
233         {
234             return (o instanceof BugLeafNode);
235         }
236
237         public void valueForPathChanged(TreePath JavaDoc arg0, Object JavaDoc arg1) {}
238
239         public int getIndexOfChild(Object JavaDoc parent, Object JavaDoc child)
240         {
241             if (parent == null || child == null || isLeaf(parent))
242                 return -1;
243             
244             if (isLeaf(child))
245             {
246                 return data.query((BugAspects) parent).indexOf((BugLeafNode) child);
247             }
248             else
249             {
250                 HashList<StringPair> stringPairs = enumsThatExist((BugAspects) parent);
251                 if (stringPairs==null)
252                 {
253                     //XXX-Threading difficulties-stringpairs is null somehow
254
assert(false);
255                     return -1;
256                 }
257
258                 return stringPairs.indexOf(((BugAspects)child).last());
259 // for (int i = 0; i < stringPairs.size(); i++)
260
// if (stringPairs.get(i).equals(((BugAspects)child).get(((BugAspects)child).size() -1)))
261
// return i;
262
//
263
// if (stringPairArray[i] == ((BugAspects)child).get(((BugAspects)child).size() - 1))
264
// return i;
265
// return -1;
266
}
267         }
268
269         public void addTreeModelListener(TreeModelListener JavaDoc listener)
270         {
271             listeners.add(listener);
272         }
273         
274         public void removeTreeModelListener(TreeModelListener JavaDoc listener)
275         {
276             listeners.remove(listener);
277         }
278
279         /*private static <T extends Enum> T[] getValues(Class<T> c) {
280             try
281             {
282                 Method getValues = c.getMethod("values");
283                 return (T[]) getValues.invoke(null);
284             }
285             catch (SecurityException e)
286             {
287                 assert false;
288                 return null;
289             }
290             catch (IllegalAccessException e)
291             {
292                 assert false;
293                 return null;
294             }
295             catch (NoSuchMethodException e)
296             {
297                 assert false;
298                 return null;
299             }
300             catch (InvocationTargetException e)
301             {
302                 throw new RuntimeException(e.getCause());
303             }
304         }*/

305         private static StringPair[] getValues(Sortables key)
306         {
307             String JavaDoc[] values= key.getAllSorted();
308             StringPair[] result = new StringPair[values.length];
309             for (int i = 0; i < values.length; i++)
310             {
311                 result[i] = new StringPair(key, values[i]);
312             }
313             return result;
314             
315 /* try
316             {
317                 Method m = BugSet.class.getMethod("getAll" + key, new Class[0]);
318                 String[] values = (String[]) m.invoke(null, new Object[0]);
319                 StringPair[] result = new StringPair[values.length];
320                 for (int i = 0; i < values.length; i++)
321                 {
322                     result[i] = new StringPair(key, values[i]);
323                 }
324                 return result;
325             }
326             catch(SecurityException e)
327             {
328                 System.err.println("NoOoOOOooOoOo000!!!1!!!1one!");
329             } catch (NoSuchMethodException e) {
330                 throw new IllegalArgumentException("getAll" + key + " does not exist");
331             } catch (IllegalArgumentException e) {
332                 e.printStackTrace();
333             } catch (IllegalAccessException e) {
334                 System.err.println("Make the method getAll" + key + " public or package or ... something. .. Now.");
335                 e.printStackTrace();
336             } catch (InvocationTargetException e) {
337                 e.printStackTrace();
338             }
339             
340             return null; */

341             
342         }
343         
344         public void columnAdded(TableColumnModelEvent JavaDoc e)
345         {
346             sortsAddedOrRemoved=true;
347             //rebuild();
348
}
349         
350         public void columnRemoved(TableColumnModelEvent JavaDoc e)
351         {
352             sortsAddedOrRemoved=true;
353             //rebuild();
354
}
355         
356         public void columnMoved(final TableColumnModelEvent JavaDoc evt)
357         {
358             if (evt.getFromIndex() == evt.getToIndex())
359                 return;
360             sortOrderChanged=true;
361             //rebuild();
362
}
363         
364         
365         void changeSet(BugSet set)
366         {
367             BugSet.setAsRootAndCache(set);
368             data=new BugSet(set);
369             root.setCount(data.size());
370             rebuild();
371         }
372         
373         
374         /**
375          * Swaps in a new BugTreeModel and a new JTree
376          *
377          */

378         private void rebuild()
379         {
380             PreferencesFrame.getInstance().freeze();
381             st.freezeOrder();
382             MainFrame.getInstance().setRebuilding(true);
383             NewFilterFromBug.closeAll();
384
385             //If this thread is not interrupting a previous thread, set the paths to be opened when the new tree is complete
386
//If the thread is interrupting another thread, dont do this, because you dont have the tree with the correct paths selected
387

388             //As of now, it should be impossible to interrupt a rebuilding thread, in another version this may change, so this if statement check is left in, even though it should always be true.
389
if (rebuildingThread==null)
390                 setOldSelectedBugs();
391             
392 // if (rebuildingThread != null)
393
// {
394
// System.out.println(rebuildingThread + " interrupted");
395
// System.out.println("Paths to open: " + getOldPaths());
396
// try
397
// {
398
// rebuildingThread.interrupt();
399
// }
400
// catch(NullPointerException e)
401
// {
402
// //Consume- The rebuilding thread was set to null as it finished just before we could interrupt it
403
// }
404
// }
405
Debug.println("Please Wait called right before starting rebuild thread");
406             pleaseWait();
407             rebuildingThread = new Thread JavaDoc()
408             {
409                 public void run()
410                 {
411                     try
412                     {
413                         /* Start Time */
414                         
415
416                         Debug.println(Thread.currentThread() + " start");
417 // System.out.println(st.getOrder());
418
BugTreeModel newModel = new BugTreeModel(BugTreeModel.this);
419                                                 
420                         newModel.listeners = listeners;
421                         newModel.resetData();
422                         newModel.data.sortList();
423                         
424 // if (rebuildingThread != this)
425
// {
426
// System.out.println(this + " quitting before new JTree()");
427
// return;
428
// }
429
JTree JavaDoc newTree = new JTree JavaDoc(newModel);
430                         
431                         // if (rebuildingThread != this)
432
// {
433
// System.out.println(this + " quitting after new JTree()");
434
// return;
435
// }
436
newModel.tree = newTree;
437                         Debug.println("Making new tree from Rebuild, this happens in swing thread");
438                         MainFrame.getInstance().newTree(newTree,newModel);
439                         
440                         rebuildingThread = null;
441 // System.out.println(Thread.currentThread() + " finish");
442
}
443                     catch(NullPointerException JavaDoc e)
444                     {
445                         if (rebuildingThread==this)
446                         {
447 // Our design has been changed such that the rebuilding thread is never interrupted, if this happens, its a Major error.
448
// However, I dont think it happens anymore
449
// System.err.println("We got hosed tommy, we got hosed");
450
Debug.println(e);
451                         }
452                         else
453                         {
454                             //This should also never happen
455
Debug.println("Interrupted Thread " + this + " encountered exception, exception was consumed. However, this thread should never have been interrupted");
456                         }
457                     }
458                     catch(ArrayIndexOutOfBoundsException JavaDoc e)
459                     {
460                         if (rebuildingThread==this)
461                         {
462 // This no longer happens since the rebuilding thread is never interrupted... I hope.
463
// System.err.println("We got hosed timmy, we got hosed");
464
Debug.println(e);
465                         }
466                         else
467                         {
468                             //This should also never happen
469
Debug.println("Interrupted Thread " + this + " encountered exception, exception was consumed. However, this thread should never have been interrupted");
470                         }
471                     }
472 //This horrible code here should no longer be necessary, if the rebuilding thread is never interrupted
473
//and we dont mess with the tree while its running, what could possibly go wrong?
474
// catch(Exception e)
475
// {
476
// if (rebuildingThread==this)
477
// {
478
// System.err.println("We're toast.");
479
// e.printStackTrace();
480
// }
481
// else
482
// {/*burrp*/}
483
// }
484
finally
485                     {
486                         getOffListenerList();
487                         MainFrame.getInstance().setRebuilding(false);
488                         PreferencesFrame.getInstance().thaw();
489                         //st.thawOrder should be the last thing that happens, otherwise a very determined user could slip a new order in before we allow him to rebuild the tree, things get out of sync, nothing bad happens, it just looks wrong until he resorts.
490
st.thawOrder();
491                         Debug.println(Thread.currentThread() + " finally");
492                     }
493                 }
494             };
495             rebuildingThread.start();
496         }
497         
498         public void crawl(final ArrayList JavaDoc<BugAspects> path, final int depth)
499         {
500             for (int i = 0; i < getChildCount(path.get(path.size() - 1)); i++)
501                 if (depth > 0)
502                 {
503                     ArrayList JavaDoc<BugAspects> newPath = new ArrayList JavaDoc<BugAspects>(path);
504                     newPath.add((BugAspects) getChild(path.get(path.size() - 1), i));
505                     crawl(newPath, depth - 1);
506                 }
507                 else
508                 {
509                     for (TreeModelListener JavaDoc l : listeners)
510                         l.treeStructureChanged(new TreeModelEvent JavaDoc(this, path.toArray()));
511                 }
512         }
513         
514         
515         
516         
517         void openPreviouslySelected(List JavaDoc<BugLeafNode> selected)
518         {
519             BugInstance bug=null;
520             TreePath JavaDoc path=null;
521             Debug.println("Starting Open Previously Selected");
522                 for (BugLeafNode b: selected)
523                 {
524                     try
525                     {
526                         bug=b.getBug();
527                         path=getPathToBug(bug);
528                         tree.expandPath(path.getParentPath());
529                         tree.addSelectionPath(path);
530                     }
531                     catch(NullPointerException JavaDoc e)
532                     {
533                         //Try to recover!
534
if (MainFrame.DEBUG) System.err.println("Failure opening a selected node, node will not be opened in new tree");
535 // System.err.println(b); This will be accurate
536
// System.err.println(bug); This will be accurate
537
//System.err.println(path);
538
// e.printStackTrace();
539
continue;
540                     }
541                     catch(ArrayIndexOutOfBoundsException JavaDoc e)
542                     {
543                         //System.err.println("Failure opening a selected node");
544
//System.err.println(b);
545
//System.err.println(bug);
546
//System.err.println(path);
547
if (MainFrame.DEBUG) System.err.println("Failure opening a selected node, node will not be opened in new tree");
548 // e.printStackTrace();
549
continue;
550                     }
551                 }
552     
553         }
554         
555         /* Recursively traverses the tree, opens all nodes matching any bug
556          * in the list, then creates the full paths to the bugs that are selected
557          * This keeps whatever bugs were selected selected when sorting
558          * DEPRECATED--Too Slow, use openPreviouslySelected
559          */

560         
561         public void crawlToOpen(TreePath JavaDoc path, ArrayList JavaDoc<BugLeafNode> bugLeafNodes, ArrayList JavaDoc<TreePath JavaDoc> treePaths)
562         {
563             for (int i = 0; i < getChildCount(path.getLastPathComponent()); i++)
564             {
565                 if (!isLeaf(getChild(path.getLastPathComponent(), i)))
566                     for (BugLeafNode p : bugLeafNodes)
567                     {
568                         if (p.matches((BugAspects) getChild(path.getLastPathComponent(), i)))
569                         {
570                             tree.expandPath(path);
571                             crawlToOpen(path.pathByAddingChild(getChild(path.getLastPathComponent(), i)), bugLeafNodes, treePaths);
572                             break;
573                         }
574                     }
575                 else
576                 {
577                     for (BugLeafNode b: bugLeafNodes)
578                     {
579                         if (getChild(path.getLastPathComponent(),i).equals(b) )
580                         {
581                             tree.expandPath(path);
582                             treePaths.add(path.pathByAddingChild(getChild(path.getLastPathComponent(), i)));
583                         }
584                     }
585                 }
586             }
587         }
588         
589         public void resetData()//FIXME: Does this need a setAsRootAndCache() on the new BugSet?
590
{
591             data=new BugSet(data);
592         }
593         
594         public void clearCache()
595         {
596             resetData();
597             BugSet.setAsRootAndCache(data);//FIXME: Should this be in resetData? Does this allow our main list to not be the same as the data in our tree?
598
root.setCount(data.size());
599
600 // for (TreeModelListener l: listeners)
601
// l.treeStructureChanged(new TreeModelEvent(this,new Object[]{root}));
602
rebuild();
603         }
604                 
605         public void unsuppressBug(TreePath JavaDoc path)
606         {
607             if (path==null)
608                 return;
609             TreePath JavaDoc pathToFirstDeleted=null;
610             Object JavaDoc[] objPath=path.getParentPath().getPath();
611             ArrayList JavaDoc<Object JavaDoc> reconstruct=new ArrayList JavaDoc<Object JavaDoc>();
612             boolean earlyStop=false;
613             for (int x=0; x<objPath.length;x++)
614             {
615                 Object JavaDoc o=objPath[x];
616                 reconstruct.add(o);
617                 if (o instanceof BugAspects)
618                 {
619                     pathToFirstDeleted=new TreePath JavaDoc(reconstruct.toArray());
620                     ((BugAspects)o).setCount(((BugAspects)o).getCount()+1);
621
622                     if (((BugAspects)o).getCount()==2 && reconstruct.size() >1)
623                     {
624                         earlyStop=true;
625                         break;
626                     }
627                     
628                     for (TreeModelListener JavaDoc l: listeners)
629                     {
630                         if (pathToFirstDeleted.getParentPath()!=null)
631                             l.treeNodesChanged(new TreeModelEvent JavaDoc(this, pathToFirstDeleted.getParentPath(),new int[]{getIndexOfChild(pathToFirstDeleted.getParentPath().getLastPathComponent(),pathToFirstDeleted.getLastPathComponent())}, new Object JavaDoc[]{pathToFirstDeleted.getLastPathComponent()}));
632                     }
633                 }
634             }
635                         
636
637             if (path.getParentPath()==null)//They are unsuppressing from the root, but we don't allow root to be suppressed, Dont know what to do here
638
{
639                 throw new RuntimeException JavaDoc();
640             }
641
642             if (pathToFirstDeleted==null)
643             {
644                 pathToFirstDeleted=path;
645             }
646             
647             if (earlyStop==false)
648             {
649                 pathToFirstDeleted=pathToFirstDeleted.pathByAddingChild(path.getLastPathComponent());
650             }
651             
652             Object JavaDoc parent=pathToFirstDeleted.getParentPath().getLastPathComponent();
653             Object JavaDoc child=pathToFirstDeleted.getLastPathComponent();
654             
655             TreeModelEvent JavaDoc insertionEvent=new TreeModelEvent JavaDoc(this, pathToFirstDeleted.getParentPath(),new int[]{getIndexOfChild(parent,child)}, new Object JavaDoc[]{child});
656             for (TreeModelListener JavaDoc l: listeners)
657             {
658                 l.treeNodesInserted(insertionEvent);
659             }
660             if (!isLeaf(child))
661             {
662                 TreeModelEvent JavaDoc structureEvent=new TreeModelEvent JavaDoc(this, pathToFirstDeleted,new int[0], new Object JavaDoc[0]);
663                 for (TreeModelListener JavaDoc l: listeners)
664                 {
665                     l.treeStructureChanged(structureEvent);
666                 }
667             }
668         }
669
670         public void suppressBug(TreePath JavaDoc path)
671         {
672             Debug.println(path);
673             Object JavaDoc[] objPath=path.getParentPath().getPath();
674             ArrayList JavaDoc<Object JavaDoc> reconstruct=new ArrayList JavaDoc<Object JavaDoc>();
675             for (int x=0; x< objPath.length;x++)
676             {
677                 Object JavaDoc o=objPath[x];
678                 ((BugAspects)o).setCount(((BugAspects)o).getCount()-1);
679             }
680
681             for (int x=0; x< objPath.length;x++)
682             {
683                 Object JavaDoc o=objPath[x];
684                 reconstruct.add(o);
685                 if (o instanceof BugAspects)
686                 {
687                     if (((BugAspects)o).getCount()==0)
688                     {
689                         path=new TreePath JavaDoc(reconstruct.toArray());
690                         break;
691                     }
692                 }
693             }
694             
695             TreeModelEvent JavaDoc event;
696         
697             if (path.getParentPath()==null)//They are suppressing the last bug in the tree
698
{
699                 event=new TreeModelEvent JavaDoc(this,path,new int[]{0},new Object JavaDoc[]{this.getChild(root,0)});
700                 root.setCount(0);
701             }
702             else
703             {
704                 Object JavaDoc parent = path.getParentPath().getLastPathComponent();
705                 Object JavaDoc child = path.getLastPathComponent();
706                 int indexOfChild=getIndexOfChild(parent,child);
707                 if (indexOfChild!=-1)
708                 {
709                     event=new TreeModelEvent JavaDoc(this, path.getParentPath(),new int[]{indexOfChild}, new Object JavaDoc[]{child});
710                     resetData();
711                 }
712                 else//They are suppressing something that has already been filtered out by setting a designation of a bug to a type that has been filtered out.
713
{
714                     resetData();
715                     for (TreeModelListener JavaDoc l: listeners)
716                     {
717                         l.treeStructureChanged(new TreeModelEvent JavaDoc(this, path.getParentPath()));
718                     }
719                     return;
720                 }
721             }
722             
723             for (TreeModelListener JavaDoc l: listeners)
724             {
725                 l.treeNodesRemoved(event);
726             }
727         }
728
729         void treeNodeChanged(TreePath JavaDoc path)
730         {
731             Debug.println("Tree Node Changed: " + path);
732             if (path.getParentPath()==null)
733             {
734                 TreeModelEvent JavaDoc event=new TreeModelEvent JavaDoc(this,path,null,null);
735                 for (TreeModelListener JavaDoc l:listeners)
736                 {
737                     l.treeNodesChanged(event);
738                 }
739                 return;
740             }
741             
742             TreeModelEvent JavaDoc event=new TreeModelEvent JavaDoc(this,path.getParentPath(),new int[]{getIndexOfChild(path.getParentPath().getLastPathComponent(),path.getLastPathComponent())},new Object JavaDoc[] {path.getLastPathComponent()});
743             for (TreeModelListener JavaDoc l: listeners)
744             {
745                 l.treeNodesChanged(event);
746             }
747         }
748         
749         public TreePath JavaDoc getPathToBug(BugInstance b)
750         {
751             //ArrayList<Sortables> order=MainFrame.getInstance().getSorter().getOrder();
752
List JavaDoc<Sortables> order=st.getOrderBeforeDivider();
753             //Create an array of BugAspects of lengths from one to the full BugAspect list of the bugInstance
754
BugAspects[] toBug=new BugAspects[order.size()];
755             for (int i=0; i < order.size(); i++)
756                 toBug[i]=new BugAspects();
757                 
758             for (int x=0; x< order.size();x++)
759             {
760                 for (int y=0; y<=x;y++)
761                 {
762                     Sortables s = order.get(y);
763                     toBug[x].add(new StringPair(s,s.getFrom(b)));
764                 }
765             }
766             //Add this array as elements of the path
767
TreePath JavaDoc pathToBug=new TreePath JavaDoc(root);
768             for (int x=0;x<order.size();x++)
769             {
770                 int index=getIndexOfChild(pathToBug.getLastPathComponent(),toBug[x]);
771
772                 if (index==-1)
773                 {
774                     if (MainFrame.DEBUG) System.err.println("Node does not exist in the tree");//For example, not a bug bugs are filtered, they set a bug to be not a bug it filters out
775
return null;
776                 }
777                 
778                 pathToBug=pathToBug.pathByAddingChild(getChild(pathToBug.getLastPathComponent(),index));
779             }
780             //Using a hashlist to store bugs in BugSet will make getIndexOfChild Waaaaaay faster, thus making this O(1) (best case)
781
int index=getIndexOfChild(pathToBug.getLastPathComponent(),new BugLeafNode(b));
782             if(index == -1)
783                 return null;
784             pathToBug=pathToBug.pathByAddingChild(getChild(pathToBug.getLastPathComponent(),index));
785             return pathToBug;
786
787         }
788         
789         public TreePath JavaDoc getPathToNewlyUnsuppressedBug(BugInstance b)
790         {
791             resetData();
792             return getPathToBug(b);
793         }
794         
795         protected void finalize() throws Throwable JavaDoc
796         {
797             super.finalize();
798             
799             //this will inform us when the garbage collector finds our old bug tree models and deletes them, thus preventing obnoxiously hard to find bugs from not remember to remove the model from our listeners
800
Debug.println("The BugTreeModel has been DELETED! This means there are no more references to it, and its finally off all of the stupid listener lists");
801         }
802         
803         public void columnMarginChanged(ChangeEvent JavaDoc arg0) {}
804         public void columnSelectionChanged(ListSelectionEvent JavaDoc arg0) {}
805
806         public void treeExpanded(TreeExpansionEvent JavaDoc event) {
807             TreePath JavaDoc path=event.getPath();
808             
809             //If a node with only one child has been expanded, automatically expand its child as well (This will recursively expand out until it opens the next node with multiple children)
810
//Note, if a node below has been expanded in the past, new events will not be called, and thus it will NOT re-expand
811
//This means that if the user has expanded a long path down and then closed the second to last node in that path, and then closed the top, and then re opened the top the second to last node will not reopen.
812
//If the user chooses not to have something opened, it will NOT reopen, this is the behavior we want.
813
if (getChildCount((BugAspects)(path.getLastPathComponent()))==1)
814                 tree.expandPath(path.pathByAddingChild(getChild(path.getLastPathComponent(),0)));
815             
816             //If a node has only one child and its last child is a leaf, select that leaf, this means that the first time you select a high up node with only a single bug instance in it, that bug instance will be selected,
817
//however, due to the fact that we do not receieve tree expansions on nodes that were previously expanded, this wont work the second time it was expanded.
818
if (((BugAspects)path.getLastPathComponent()).getCount()==1 && isLeaf(getChild(path.getLastPathComponent(),0)))
819             {
820                 tree.setSelectionPath(path.pathByAddingChild(getChild(path.getLastPathComponent(),0)));
821             }
822             //Thus this if statement is required, if the the node below has been expanded, and theres only a single child, and it wasn't taken care of in the previous statement,
823
//recursively travel down the tree and select the leaf, this way the final bug instance is selected both the first time and every other time.
824
//Note, this ignores the design of if statement #1, where if a node between the node being opened and the leaf has been collapsed, it does not open the full path,
825
//if we wish to add this functionality, it would be done in this third if statement.
826

827             else if (((BugAspects)path.getLastPathComponent()).getCount()==1 && tree.isExpanded(path.pathByAddingChild(getChild(path.getLastPathComponent(),0))))
828             {
829                 TreePath JavaDoc fullPath=path;
830                 while (!isLeaf(fullPath.getLastPathComponent()))
831                     fullPath=fullPath.pathByAddingChild(getChild(fullPath.getLastPathComponent(),0));
832                 tree.setSelectionPath(fullPath);
833             }
834         }
835         
836         public void treeCollapsed(TreeExpansionEvent JavaDoc event) {
837         }
838         
839         private void setOldSelectedBugs()
840         {
841             selectedBugLeafNodes.clear();
842             if (tree.getSelectionPaths() != null) // Who the cussword wrote this API anyway?
843
for (TreePath JavaDoc path : tree.getSelectionPaths())
844                     if (isLeaf(path.getLastPathComponent()))
845                         selectedBugLeafNodes.add((BugLeafNode) path.getLastPathComponent());
846         }
847         Vector JavaDoc<BugLeafNode> getOldSelectedBugs()
848         {
849             return selectedBugLeafNodes;
850         }
851         
852         public static class PleaseWaitTreeModel implements TreeModel JavaDoc
853         {
854             private String JavaDoc root = "Please wait...";
855             public PleaseWaitTreeModel() {}
856             public PleaseWaitTreeModel(String JavaDoc message) {if (message!=null) root=message;}
857             
858             public void addTreeModelListener(TreeModelListener JavaDoc l) {}
859             public Object JavaDoc getChild(Object JavaDoc parent, int index) {return null;}
860             public int getChildCount(Object JavaDoc parent) {return 0;}
861             public int getIndexOfChild(Object JavaDoc parent, Object JavaDoc child) {return -1;}
862             public Object JavaDoc getRoot() {return root;}
863             public boolean isLeaf(Object JavaDoc node) {return true;}
864             public void removeTreeModelListener(TreeModelListener JavaDoc l) {}
865             public void valueForPathChanged(TreePath JavaDoc path, Object JavaDoc newValue) {}
866         }
867         
868         void checkSorter()
869         {
870             if (sortOrderChanged==true)
871             {
872                 sortOrderChanged=false;
873                 rebuild();
874             }
875             if (sortsAddedOrRemoved==true)
876             {
877                 sortsAddedOrRemoved=false;
878                 rebuild();
879             }
880         }
881         
882         static void pleaseWait()
883         {
884             pleaseWait(null);
885         }
886         static void pleaseWait(final String JavaDoc message)
887         {
888             SwingUtilities.invokeLater(new Runnable JavaDoc()
889             {
890                 public void run()
891                 {
892                     MainFrame.getInstance().pleaseWait = true;
893                     Debug.println("Please Wait! " + (message==null?"":message));
894                     MainFrame.getInstance().getTree().setModel(new PleaseWaitTreeModel(message));
895                     MainFrame.getInstance().pleaseWait = false;
896                     //MainFrame.getInstance().setSorting(false);
897
Debug.println("Please Stop Waiting");
898                 }
899             });
900         }
901         
902         public TreeModelEvent JavaDoc restructureBranch(ArrayList JavaDoc<String JavaDoc> stringsToBranch, boolean removing) throws BranchOperationException
903         {
904             if (removing)
905                 return branchOperations(stringsToBranch, 2);
906             else
907                 return branchOperations(stringsToBranch, 3);
908         }
909         
910         public TreeModelEvent JavaDoc insertBranch(ArrayList JavaDoc<String JavaDoc> stringsToBranch) throws BranchOperationException
911         {
912             return branchOperations(stringsToBranch, 1);
913         }
914         
915         public TreeModelEvent JavaDoc removeBranch(ArrayList JavaDoc<String JavaDoc> stringsToBranch) throws BranchOperationException
916         {
917             return branchOperations(stringsToBranch, 0);
918         }
919         
920         public void sortBranch(TreePath JavaDoc pathToBranch)
921         {
922             BugSet bs=data.query((BugAspects)pathToBranch.getLastPathComponent());
923             bs.sortList();
924             Debug.println("Data in sorted branch: " + pathToBranch.getLastPathComponent());
925             for (BugLeafNode b: bs)
926             {
927                 Debug.println(b);
928             }
929         
930             Object JavaDoc[] children=new Object JavaDoc[getChildCount(pathToBranch.getLastPathComponent())];
931             int[] childIndices=new int[children.length];
932             for (int x=0; x<children.length; x++)
933             {
934                 children[x]=getChild(pathToBranch.getLastPathComponent(),x);
935                 childIndices[x]=x;
936             }
937             for (TreeModelListener JavaDoc l: listeners)
938             {
939                 TreeModelEvent JavaDoc event=new TreeModelEvent JavaDoc(this,pathToBranch,childIndices,children);
940                 l.treeNodesChanged(event);
941             }
942
943         }
944         
945         @SuppressWarnings JavaDoc("serial")
946         static class BranchOperationException extends Exception JavaDoc
947         {
948             public BranchOperationException(String JavaDoc s)
949             {
950                 super(s);
951             }
952         }
953         
954         private TreeModelEvent JavaDoc branchOperations(ArrayList JavaDoc<String JavaDoc> stringsToBranch, int whatToDo) throws BranchOperationException
955         {
956             TreeModelEvent JavaDoc event=null;
957             final int REMOVE=0;
958             final int INSERT=1;
959             final int REMOVERESTRUCTURE=2;
960             final int INSERTRESTRUCTURE=3;
961             if (whatToDo==REMOVE)
962                 Debug.println("Removing a branch......");
963             else if (whatToDo==INSERT)
964                 Debug.println("Inserting a branch......");
965             else if (whatToDo==REMOVERESTRUCTURE)
966                 Debug.println("Restructuring from branch to remove......");
967             else if (whatToDo==INSERTRESTRUCTURE)
968                 Debug.println("Restructuring from branch to insert......");
969             else
970                 throw new UnsupportedOperationException JavaDoc("BranchOperations can only take 0 to remove, 1 to insert, or 2 or 3 to restructure... It spits on your integer, the pathetic little " + whatToDo);
971             Debug.println(stringsToBranch);
972             
973             if (whatToDo==INSERT || whatToDo==INSERTRESTRUCTURE)
974             {
975                 resetData();
976             }
977             //ArrayList<Sortables> order=MainFrame.getInstance().getSorter().getOrder();
978
List JavaDoc<Sortables> order=st.getOrderBeforeDivider();
979             //Create an array of BugAspects of lengths from one to the full BugAspect list of the bugInstance
980
BugAspects[] toBug=new BugAspects[stringsToBranch.size()];
981             for (int x=0; x < stringsToBranch.size(); x++) {
982                 toBug[x]=new BugAspects();
983     
984                 for (int y=0; y<=x;y++)
985                 {
986                     Sortables s = order.get(y);
987                     toBug[x].add(new StringPair(s,stringsToBranch.get(y)));
988                 }
989             }
990             
991             //Add this array as elements of the path
992
TreePath JavaDoc pathToBranch=new TreePath JavaDoc(root);
993             for (int x=0;x<stringsToBranch.size();x++)
994             {
995                 BugAspects child=toBug[x];
996                 BugAspects parent=(BugAspects) pathToBranch.getLastPathComponent();
997                 if (getIndexOfChild(parent,child)!=-1)
998                 {
999                     pathToBranch=pathToBranch.pathByAddingChild(child);
1000                }
1001                else
1002                {
1003                    Debug.println(parent + " does not contain " + child);
1004                    throw new BranchOperationException("Branch has been filtered out by another filter.");
1005// break;
1006
}
1007            }
1008            if (pathToBranch.getParentPath()!=null)
1009                while (getChildCount(pathToBranch.getParentPath().getLastPathComponent())==1)
1010                {
1011                    if (pathToBranch.getParentPath().getLastPathComponent().equals(root))
1012                        break;
1013                    pathToBranch=pathToBranch.getParentPath();
1014                }
1015            Debug.println(pathToBranch);
1016
1017            
1018            if (whatToDo==INSERT)
1019            {
1020                event=new TreeModelEvent JavaDoc(this,pathToBranch.getParentPath(),new int[]{getIndexOfChild(pathToBranch.getParentPath().getLastPathComponent(),pathToBranch.getLastPathComponent())}, new Object JavaDoc[]{pathToBranch.getLastPathComponent()});
1021            }
1022            else if (whatToDo==INSERTRESTRUCTURE)
1023            {
1024                event=new TreeModelEvent JavaDoc(this,pathToBranch);
1025            }
1026            
1027            if (whatToDo==REMOVE)
1028            {
1029                event=new TreeModelEvent JavaDoc(this,pathToBranch.getParentPath(),new int[]{getIndexOfChild(pathToBranch.getParentPath().getLastPathComponent(),pathToBranch.getLastPathComponent())}, new Object JavaDoc[]{pathToBranch.getLastPathComponent()});
1030            
1031            }
1032            else if (whatToDo==REMOVERESTRUCTURE)
1033            {
1034                event=new TreeModelEvent JavaDoc(this,pathToBranch);
1035            }
1036
1037            if (whatToDo==REMOVE || whatToDo==REMOVERESTRUCTURE)
1038                resetData();
1039            
1040            return event;
1041        }
1042        
1043        void sendEvent(TreeModelEvent JavaDoc event, int whatToDo)
1044        {
1045            final int REMOVE=0;
1046            final int INSERT=1;
1047            final int RESTRUCTURE=2;
1048            if (event==null)
1049            {
1050                throw new IllegalStateException JavaDoc("Dont throw null events.");
1051            }
1052            resetData();
1053            for (TreeModelListener JavaDoc l: listeners)
1054            {
1055                if (whatToDo==REMOVE)
1056                    l.treeNodesRemoved(event);
1057                else if (whatToDo==INSERT)
1058                {
1059                    l.treeNodesInserted(event);
1060                    l.treeStructureChanged(new TreeModelEvent JavaDoc(this,new TreePath JavaDoc(event.getPath()).pathByAddingChild(event.getChildren()[0])));
1061                }
1062                else if (whatToDo==RESTRUCTURE)
1063                {
1064                    l.treeStructureChanged(event);
1065                }
1066            }
1067            
1068            root.setCount(data.size());
1069            TreePath JavaDoc changedPath=new TreePath JavaDoc(root);
1070            treeNodeChanged(changedPath);
1071            changedPath=new TreePath JavaDoc(event.getPath());
1072            while (changedPath.getParentPath()!=null)
1073            {
1074                treeNodeChanged(changedPath);
1075                changedPath=changedPath.getParentPath();
1076            }
1077        }
1078    }
Popular Tags