KickJava   Java API By Example, From Geeks To Geeks.

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


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.awt.BorderLayout JavaDoc;
23 import java.awt.Color JavaDoc;
24 import java.awt.event.ActionEvent JavaDoc;
25 import java.awt.event.ActionListener JavaDoc;
26 import java.awt.event.ItemEvent JavaDoc;
27 import java.awt.event.ItemListener JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.LinkedList JavaDoc;
31
32 import javax.swing.JComboBox JavaDoc;
33 import javax.swing.JMenu JavaDoc;
34 import javax.swing.JMenuItem JavaDoc;
35 import javax.swing.JOptionPane JavaDoc;
36 import javax.swing.JPanel JavaDoc;
37 import javax.swing.JScrollPane JavaDoc;
38 import javax.swing.JTextArea JavaDoc;
39 import javax.swing.SwingUtilities JavaDoc;
40 import javax.swing.event.DocumentEvent JavaDoc;
41 import javax.swing.event.DocumentListener JavaDoc;
42 import javax.swing.tree.TreePath JavaDoc;
43
44 import edu.umd.cs.findbugs.BugDesignation;
45 import edu.umd.cs.findbugs.BugInstance;
46 import edu.umd.cs.findbugs.BugDesignation;
47 import edu.umd.cs.findbugs.I18N;
48 import edu.umd.cs.findbugs.annotations.CheckForNull;
49
50 /**
51  * @author pugh
52  */

53 public class CommentsArea {
54
55     private JTextArea JavaDoc userCommentsText = new JTextArea JavaDoc();
56
57     private Color JavaDoc userCommentsTextUnenabledColor;
58
59     private JComboBox JavaDoc designationComboBox;
60
61     private ArrayList JavaDoc<String JavaDoc> designationKeys;
62
63     LinkedList JavaDoc<String JavaDoc> prevCommentsList = new LinkedList JavaDoc<String JavaDoc>();
64
65     final static private int prevCommentsMaxSize = 10;
66
67     private JComboBox JavaDoc prevCommentsComboBox = new JComboBox JavaDoc();
68
69     private boolean dontShowAnnotationConfirmation = false;
70
71     private boolean changed;
72     final MainFrame frame;
73
74     CommentsArea(MainFrame frame) {
75         this.frame = frame;
76     }
77
78     /**
79      * Create center panel that holds the user input combo boxes and TextArea.
80      */

81     JPanel JavaDoc createCommentsInputPanel() {
82         JPanel JavaDoc centerPanel = new JPanel JavaDoc();
83         BorderLayout JavaDoc centerLayout = new BorderLayout JavaDoc();
84         centerLayout.setVgap(10);
85         centerPanel.setLayout(centerLayout);
86
87         userCommentsText.getDocument().addDocumentListener(
88                 new DocumentListener JavaDoc() {
89
90                     public void insertUpdate(DocumentEvent JavaDoc e) {
91                         frame.setProjectChanged(true);
92                         changed = true;
93                     }
94
95                     public void removeUpdate(DocumentEvent JavaDoc e) {
96                         frame.setProjectChanged(true);
97                         changed = true;
98                     }
99
100                     public void changedUpdate(DocumentEvent JavaDoc e) {
101                         changed = true;
102                     }
103
104                 });
105
106         userCommentsTextUnenabledColor = centerPanel.getBackground();
107
108         userCommentsText.setLineWrap(true);
109         userCommentsText
110                 .setToolTipText(edu.umd.cs.findbugs.L10N.getLocalString("tooltip.enter_comments", "Enter your comments about this bug here"));
111         userCommentsText.setWrapStyleWord(true);
112         userCommentsText.setEnabled(false);
113         userCommentsText.setBackground(userCommentsTextUnenabledColor);
114         JScrollPane JavaDoc commentsScrollP = new JScrollPane JavaDoc(userCommentsText);
115
116         prevCommentsComboBox.setEnabled(false);
117         prevCommentsComboBox
118                 .setToolTipText(edu.umd.cs.findbugs.L10N.getLocalString("tooltip.reuse_comments", "Use this to reuse a previous textual comment for this bug"));
119         prevCommentsComboBox.addItemListener(new ItemListener JavaDoc() {
120             public void itemStateChanged(ItemEvent JavaDoc e) {
121                 if (e.getStateChange() == ItemEvent.SELECTED
122                         && prevCommentsComboBox.getSelectedIndex() != 0) {
123                     setCurrentUserCommentsText(getCurrentPrevCommentsSelection());
124
125                     prevCommentsComboBox.setSelectedIndex(0);
126                 }
127             }
128         });
129
130         designationComboBox = new JComboBox JavaDoc();
131         designationKeys = new ArrayList JavaDoc<String JavaDoc>();
132
133         designationComboBox.setEnabled(false);
134         designationComboBox
135                 .setToolTipText(edu.umd.cs.findbugs.L10N.getLocalString("tooltip.select_designation", "Select a user designation for this bug"));
136         designationComboBox.addItemListener(new ItemListener JavaDoc() {
137             public void itemStateChanged(ItemEvent JavaDoc e) {
138                 if (frame.userInputEnabled
139                         && e.getStateChange() == ItemEvent.SELECTED) {
140                     if (frame.currentSelectedBugLeaf == null)
141                         setDesignationNonLeaf(designationComboBox
142                                 .getSelectedItem().toString());
143                     else if (!alreadySelected())
144                         setDesignation(designationComboBox.getSelectedItem()
145                                 .toString());
146                 }
147             }
148
149             /*
150              * Checks to see if the designation is already selected as that.
151              * This was created because it was found the itemStateChanged method
152              * is called when the combo box is set when a bug is clicked.
153              */

154             private boolean alreadySelected() {
155                 return designationKeys.get(
156                         designationComboBox.getSelectedIndex()).equals(
157                         frame.currentSelectedBugLeaf.getBug()
158                                 .getNonnullUserDesignation()
159                                 .getDesignationKey());
160             }
161         });
162
163         designationKeys.add("");
164         designationComboBox.addItem("");
165         for (String JavaDoc s : I18N.instance().getUserDesignationKeys(true)) {
166             designationKeys.add(s);
167             designationComboBox.addItem(Sortables.DESIGNATION.formatValue(s));
168         }
169         setUnknownDesignation();
170
171         centerPanel.add(designationComboBox, BorderLayout.NORTH);
172         centerPanel.add(commentsScrollP, BorderLayout.CENTER);
173         centerPanel.add(prevCommentsComboBox, BorderLayout.SOUTH);
174
175         return centerPanel;
176     }
177
178     void setUnknownDesignation() {
179         designationComboBox.setSelectedIndex(0); // WARNING: this is hard
180
// coded in here.
181
}
182
183     /**
184      * Sets the user comment panel to whether or not it is enabled. If isEnabled
185      * is false will clear the user comments text pane.
186      *
187      * @param isEnabled
188      */

189     void setUserCommentInputEnable(final boolean isEnabled) {
190         SwingUtilities.invokeLater(new Runnable JavaDoc() {
191             public void run() {
192                 setUserCommentInputEnableFromSwingThread(isEnabled);
193             }
194         });
195     }
196
197     /**
198      * Sets the user comment panel to whether or not it is enabled. If isEnabled
199      * is false will clear the user comments text pane.
200      *
201      * @param isEnabled
202      */

203     void setUserCommentInputEnableFromSwingThread(final boolean isEnabled) {
204         frame.userInputEnabled = isEnabled;
205         if (!isEnabled) {
206             userCommentsText.setText("");
207             // WARNING: this is hard coded in here, but needed
208
// so when not enabled shows default setting of designation
209
setUnknownDesignation();
210             userCommentsText.setBackground(userCommentsTextUnenabledColor);
211         } else
212             userCommentsText.setBackground(Color.WHITE);
213         userCommentsText.setEnabled(isEnabled);
214         prevCommentsComboBox.setEnabled(isEnabled);
215         designationComboBox.setEnabled(isEnabled);
216     }
217
218     /**
219      * Updates comments tab. Takes node passed and sets the designation and
220      * comments.
221      *
222      * @param node
223      */

224     void updateCommentsFromLeafInformation(final BugLeafNode node) {
225         SwingUtilities.invokeLater(new Runnable JavaDoc() {
226             public void run() {
227                 BugInstance bug = node.getBug();
228                 setCurrentUserCommentsText(bug.getAnnotationText());
229                 designationComboBox.setSelectedIndex(designationKeys
230                         .indexOf(bug.getNonnullUserDesignation()
231                                 .getDesignationKey()));
232                 setUserCommentInputEnableFromSwingThread(true);
233                 changed = false;
234             }
235         });
236     }
237
238     void updateCommentsFromNonLeafInformation(final BugAspects theAspects) {
239         SwingUtilities.invokeLater(new Runnable JavaDoc() {
240             public void run() {
241                 updateCommentsFromNonLeafInformationFromSwingThread(theAspects);
242                 setUserCommentInputEnableFromSwingThread(true);
243                 changed = false;
244             }
245         });
246     }
247
248     /**
249      * Saves the current comments to the BugLeafNode passed in. If the passed in
250      * node's annotation is already equal to the current user comment then will
251      * not do anything so setProjectedChanged is not made true. Will also add
252      * the comment if it is new to the previous comments list.
253      *
254      * @param node
255      */

256     private void saveCommentsToBug(BugLeafNode node) {
257         if (node == null)
258             return;
259
260         String JavaDoc comments = getCurrentUserCommentsText();
261         if (node.getBug().getAnnotationText().equals(comments))
262             return;
263
264         node.getBug().setAnnotationText(comments);
265         setProjectChanged(true);
266         changed = false;
267         addToPrevComments(comments);
268     }
269
270     private boolean confirmAnnotation() {
271
272         String JavaDoc[] options = { edu.umd.cs.findbugs.L10N.getLocalString("dlg.yes_btn", "Yes"), edu.umd.cs.findbugs.L10N.getLocalString("dlg.no_btn", "No"), edu.umd.cs.findbugs.L10N.getLocalString("dlg.yes_dont_ask_btn", "Yes, and don't ask me this again")};
273         if (dontShowAnnotationConfirmation)
274             return true;
275         int choice = JOptionPane
276                 .showOptionDialog(
277                         frame,
278                         edu.umd.cs.findbugs.L10N.getLocalString("dlg.changing_text_lbl", "Changing this text box will overwrite the annotations associated with all bugs in this folder and subfolders. Are you sure?"),
279                         edu.umd.cs.findbugs.L10N.getLocalString("dlg.annotation_change_ttl", "Annotation Change"), JOptionPane.DEFAULT_OPTION,
280                         JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
281         switch (choice) {
282         case 0:
283             return true;
284         case 1:
285             return false;
286         case 2:
287             dontShowAnnotationConfirmation = true;
288             return true;
289         default:
290             return true;
291         }
292
293     }
294
295     private void saveCommentsToNonLeaf(BugAspects aspects) {
296         if (aspects == null)
297             return;
298         if (!changed) return;
299         String JavaDoc newComment = getCurrentUserCommentsText();
300         if (newComment.equals(getNonLeafCommentsText(aspects)))
301             return;
302         else if (confirmAnnotation()) {
303             BugSet filteredSet = aspects
304                     .getMatchingBugs(BugSet.getMainBugSet());
305             for (BugLeafNode nextNode : filteredSet) {
306                 saveCommentsToBug(nextNode);
307             }
308         }
309         changed = false;
310
311     }
312
313     /**
314      * Saves comments to the current selected bug.
315      *
316      */

317
318     public void saveComments() {
319         saveComments(frame.currentSelectedBugLeaf,
320                 frame.currentSelectedBugAspects);
321     }
322
323     public void saveComments(BugLeafNode theNode, BugAspects theAspects) {
324         if (theNode != null)
325             saveCommentsToBug(theNode);
326         else
327             saveCommentsToNonLeaf(theAspects);
328     }
329
330     /**
331      * Deletes the list have already. Then loads from list. Will load from the
332      * list until run out of room in the prevCommentsList.
333      *
334      * @param list
335      */

336     void loadPrevCommentsList(String JavaDoc[] list) {
337         int count = 0;
338         for (String JavaDoc str : list) {
339             if (str.equals(""))
340                 count++;
341         }
342
343         String JavaDoc[] ary = new String JavaDoc[list.length - count];
344         int j = 0;
345         for (String JavaDoc str : list) {
346             if (!str.equals("")) {
347                 ary[j] = str;
348                 j++;
349             }
350         }
351
352         String JavaDoc[] temp;
353         prevCommentsList = new LinkedList JavaDoc<String JavaDoc>();
354         if ((ary.length) > prevCommentsMaxSize) {
355             temp = new String JavaDoc[prevCommentsMaxSize];
356             for (int i = 0; i < temp.length && i < ary.length; i++)
357                 temp[i] = ary[i];
358         } else {
359             temp = new String JavaDoc[ary.length];
360             for (int i = 0; i < ary.length; i++)
361                 temp[i] = ary[i];
362         }
363
364         for (String JavaDoc str : temp)
365             prevCommentsList.add(str);
366
367         resetPrevCommentsComboBox();
368     }
369
370     /**
371      * Adds the comment into the list. If the comment is already in the list
372      * then simply moves to the front. If the list is too big when adding the
373      * comment then deletes the last comment on the list.
374      *
375      * @param comment
376      */

377     private void addToPrevComments(String JavaDoc comment) {
378         if (comment.equals(""))
379             return;
380
381         if (prevCommentsList.contains(comment)) {
382             int index = prevCommentsList.indexOf(comment);
383             if (index == 0)
384                 return;
385             prevCommentsList.remove(index);
386         }
387
388         prevCommentsList.addFirst(comment);
389
390         while (prevCommentsList.size() > prevCommentsMaxSize)
391             prevCommentsList.removeLast();
392
393         resetPrevCommentsComboBox();
394     }
395
396     /**
397      * Removes all items in the comboBox for previous comments. Then refills it
398      * using prevCommentsList.
399      *
400      */

401     private void resetPrevCommentsComboBox() {
402         prevCommentsComboBox.removeAllItems();
403
404         prevCommentsComboBox.addItem("");
405
406         for (String JavaDoc str : prevCommentsList) {
407             if (str.length() < 20)
408                 prevCommentsComboBox.addItem(str);
409             else
410                 prevCommentsComboBox.addItem(str.substring(0, 17) + "...");
411         }
412     }
413
414     /**
415      * Returns the text in the current user comments textArea.
416      *
417      * @return
418      */

419     private String JavaDoc getCurrentUserCommentsText() {
420         return userCommentsText.getText();
421     }
422
423     /**
424      * Sets the current user comments text area to comment.
425      *
426      * @param comment
427      */

428     private void setCurrentUserCommentsText(String JavaDoc comment) {
429         changed = true;
430         userCommentsText.setText(comment);
431     }
432
433     /**
434      * Returns the current selected previous comments. Returns as an object.
435      */

436     private String JavaDoc getCurrentPrevCommentsSelection() {
437         return prevCommentsList
438                 .get(prevCommentsComboBox.getSelectedIndex() - 1);
439     }
440
441     void addDesignationItem(JMenu JavaDoc menu, final String JavaDoc menuName, int keyEvent) {
442         JMenuItem JavaDoc toggleItem = new JMenuItem JavaDoc(menuName);
443
444         toggleItem.addActionListener(new ActionListener JavaDoc() {
445             public void actionPerformed(ActionEvent JavaDoc arg0) {
446                 if (frame.currentSelectedBugLeaf == null)
447                     setDesignationNonLeaf(menuName);
448                 else
449                     setDesignation(menuName);
450             }
451         });
452         MainFrame.attachAccelaratorKey(toggleItem, keyEvent);
453         menu.add(toggleItem);
454     }
455
456     void setDesignation(String JavaDoc designationName) {
457         if (frame.currentSelectedBugLeaf == null)
458             return;
459         String JavaDoc designationKey = convertDesignationNameToDesignationKey(designationName);
460         if (designationKey == null)
461             return;
462         if (changeDesignationOfBug(frame.currentSelectedBugLeaf, designationKey))
463             changed = true;
464         setDesignationComboBox(designationKey);
465     }
466
467     protected void setDesignationNonLeaf(String JavaDoc designationName) {
468         String JavaDoc designationKey = convertDesignationNameToDesignationKey(designationName);
469         if (designationKey == null || frame.currentSelectedBugAspects == null)
470             return;
471
472         BugSet filteredSet = frame.currentSelectedBugAspects
473                 .getMatchingBugs(BugSet.getMainBugSet());
474         for (BugLeafNode nextNode : filteredSet)
475             if (changeDesignationOfBug(nextNode, designationKey)) changed = true;
476         setDesignationComboBox(designationKey);
477     }
478
479     protected boolean changeDesignationOfBug(BugLeafNode theNode, String JavaDoc selection) {
480         BugDesignation userDesignation = theNode.getBug().getNonnullUserDesignation();
481         if (userDesignation.getDesignationKey().equals(selection)) return false;
482         userDesignation.setDesignationKey(selection);
483         return true;
484     }
485
486     protected void updateDesignationComboBox() {
487         if (frame.currentSelectedBugLeaf == null)
488             updateCommentsFromNonLeafInformationFromSwingThread(frame.currentSelectedBugAspects);
489         else {
490             int selectedIndex = designationComboBox
491                                 .getSelectedIndex();
492             if (selectedIndex >= 0) setDesignationComboBox(designationKeys.get(selectedIndex));
493             else
494                 Debug.println("Couldn't find selected index in designationComboBox: " + designationComboBox.getSelectedItem());
495         }
496     }
497
498     protected void updateCommentsFromNonLeafInformationFromSwingThread(BugAspects theAspects) {
499         if (theAspects == null)
500             return;
501         BugSet filteredSet = theAspects.getMatchingBugs(BugSet.getMainBugSet());
502         boolean allSame = true;
503         int first = -1;
504         for (BugLeafNode nextNode : filteredSet) {
505
506             int designationIndex = designationKeys.indexOf(nextNode.getBug()
507                     .getNonnullUserDesignation().getDesignationKey());
508             if (first == -1) {
509                 first = designationIndex;
510             } else {
511                 if (designationIndex != first)
512                     allSame = false;
513             }
514         }
515         ;
516         if (allSame) {
517             designationComboBox.setSelectedIndex(first);
518         } else {
519             designationComboBox.setSelectedIndex(0);
520         }
521         userCommentsText.setText(getNonLeafCommentsText(theAspects));
522         changed = false;
523         // setUserCommentInputEnableFromSwingThread(true);
524
}
525     
526     protected String JavaDoc getNonLeafCommentsText(BugAspects theAspects)
527     { if (theAspects == null)
528             return "";
529         BugSet filteredSet = theAspects.getMatchingBugs(BugSet.getMainBugSet());
530         boolean allSame = true;
531         String JavaDoc comments = null;
532         for (BugLeafNode nextNode : filteredSet) {
533         String JavaDoc commentsOnThisBug = nextNode.getBug().getAnnotationText();
534             if (comments == null) {
535                 comments = commentsOnThisBug;
536             } else {
537                 if (!commentsOnThisBug.equals(comments))
538                     allSame = false;
539             }
540         }
541         if((comments == null) || (allSame == false))
542             return "";
543         else return comments;
544     }
545     /*
546     protected String getNonLeafCommentsText(BugAspects theAspects)
547     { if (theAspects == null)
548             return "";
549         BugSet filteredSet = theAspects.getMatchingBugs(BugSet.getMainBugSet());
550         boolean allSame = true;
551         String comments = null;
552         for (BugLeafNode nextNode : filteredSet) {
553         String commentsOnThisBug = nextNode.getBug().getAnnotationText();
554             if (comments == null) {
555                 comments = commentsOnThisBug;
556             } else {
557                 if (!commentsOnThisBug.equals(comments))
558                     allSame = false;
559             }
560         }
561         if((comments == null) || (allSame == false))
562             return "";
563         else return comments;
564     }
565     */

566     protected void setDesignationComboBox(String JavaDoc designationKey) {
567         int numItems = designationComboBox.getItemCount();
568         for (int i = 0; i < numItems; i++) {
569             String JavaDoc value = designationKeys.get(i);
570             if (designationKey.equals(value)) {
571                 designationComboBox.setSelectedIndex(i);
572                 return;
573                 }
574         }
575         if (MainFrame.DEBUG) System.out.println("Couldn't find combo box for " + designationKey);
576     }
577
578     public void moveNodeAccordingToDesignation(BugLeafNode theNode,
579             String JavaDoc selection) {
580
581         if (!getSorter().getOrder().contains(Sortables.DESIGNATION)) {
582             // designation not sorted on at all
583

584             theNode.getBug().getNonnullUserDesignation().setDesignationKey(
585                     selection);
586
587         } else if (getSorter().getOrderBeforeDivider().contains(
588                 Sortables.DESIGNATION)) {
589
590             BugTreeModel model = getModel();
591             TreePath JavaDoc path = model.getPathToBug(theNode.getBug());
592             if (path == null) {
593                 theNode.getBug().getNonnullUserDesignation().setDesignationKey(
594                         selection);
595                 return;
596             }
597             Object JavaDoc[] objPath = path.getParentPath().getPath();
598             ArrayList JavaDoc<Object JavaDoc> reconstruct = new ArrayList JavaDoc<Object JavaDoc>();
599             ArrayList JavaDoc<TreePath JavaDoc> listOfNodesToReconstruct = new ArrayList JavaDoc<TreePath JavaDoc>();
600             for (int x = 0; x < objPath.length; x++) {
601                 Object JavaDoc o = objPath[x];
602                 reconstruct.add(o);
603                 if (o instanceof BugAspects) {
604                     if (((BugAspects) o).getCount() == 1) {
605                         // Debug.println((BugAspects)(o));
606
break;
607                     }
608                 }
609                 TreePath JavaDoc pathToNode = new TreePath JavaDoc(reconstruct.toArray());
610                 listOfNodesToReconstruct.add(pathToNode);
611             }
612
613             theNode.getBug().getNonnullUserDesignation().setDesignationKey(
614                     selection);
615             model.suppressBug(path);
616             TreePath JavaDoc unsuppressPath = model.getPathToBug(theNode.getBug());
617             if (unsuppressPath != null)// If choosing their designation has not
618
// moved the bug under any filters
619
{
620                 model.unsuppressBug(unsuppressPath);
621                 // tree.setSelectionPath(unsuppressPath);
622
}
623             for (TreePath JavaDoc pathToNode : listOfNodesToReconstruct) {
624                 model.treeNodeChanged(pathToNode);
625             }
626             setProjectChanged(true);
627         } else if (getSorter().getOrderAfterDivider().contains(
628                 Sortables.DESIGNATION)) {
629
630             theNode.getBug().getNonnullUserDesignation().setDesignationKey(
631                     selection);
632             BugTreeModel model = getModel();
633             TreePath JavaDoc path = model.getPathToBug(theNode.getBug());
634             if (path != null)
635                 model.sortBranch(path.getParentPath());
636
637         }
638     }
639
640     protected @CheckForNull
641     String JavaDoc convertDesignationNameToDesignationKey(String JavaDoc name) {
642         /*
643          * This converts a designation name from human-readable format ("mostly
644          * harmless", "critical") to the program's internal format
645          * ("MOSTLY_HARMLESS", "CRITICAL") etc. This uses the
646          * DesignationComboBox (this should probably be changed)
647          */

648         int itemCount = designationComboBox.getItemCount();
649         for (int i = 1; i < itemCount; i++)
650             if (name.equals(designationComboBox.getItemAt(i)))
651                 return designationKeys.get(i);
652         return null;
653     }
654
655     private void setProjectChanged(boolean b) {
656         frame.setProjectChanged(b);
657     }
658
659     /**
660      * Returns the SorterTableColumnModel of the MainFrame.
661      *
662      * @return
663      */

664     SorterTableColumnModel getSorter() {
665         return frame.getSorter();
666     }
667
668     public void resized() {
669         resetPrevCommentsComboBox();
670         userCommentsText.validate();
671     }
672
673     BugTreeModel getModel() {
674         return (BugTreeModel) frame.tree.getModel();
675     }
676
677     public boolean hasFocus() {
678         return userCommentsText.hasFocus();
679     }
680 }
681
Popular Tags