1 19 20 package edu.umd.cs.findbugs.gui2; 21 22 import java.awt.BorderLayout ; 23 import java.awt.Color ; 24 import java.awt.event.ActionEvent ; 25 import java.awt.event.ActionListener ; 26 import java.awt.event.ItemEvent ; 27 import java.awt.event.ItemListener ; 28 import java.util.ArrayList ; 29 import java.util.Iterator ; 30 import java.util.LinkedList ; 31 32 import javax.swing.JComboBox ; 33 import javax.swing.JMenu ; 34 import javax.swing.JMenuItem ; 35 import javax.swing.JOptionPane ; 36 import javax.swing.JPanel ; 37 import javax.swing.JScrollPane ; 38 import javax.swing.JTextArea ; 39 import javax.swing.SwingUtilities ; 40 import javax.swing.event.DocumentEvent ; 41 import javax.swing.event.DocumentListener ; 42 import javax.swing.tree.TreePath ; 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 53 public class CommentsArea { 54 55 private JTextArea userCommentsText = new JTextArea (); 56 57 private Color userCommentsTextUnenabledColor; 58 59 private JComboBox designationComboBox; 60 61 private ArrayList <String > designationKeys; 62 63 LinkedList <String > prevCommentsList = new LinkedList <String >(); 64 65 final static private int prevCommentsMaxSize = 10; 66 67 private JComboBox prevCommentsComboBox = new JComboBox (); 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 81 JPanel createCommentsInputPanel() { 82 JPanel centerPanel = new JPanel (); 83 BorderLayout centerLayout = new BorderLayout (); 84 centerLayout.setVgap(10); 85 centerPanel.setLayout(centerLayout); 86 87 userCommentsText.getDocument().addDocumentListener( 88 new DocumentListener () { 89 90 public void insertUpdate(DocumentEvent e) { 91 frame.setProjectChanged(true); 92 changed = true; 93 } 94 95 public void removeUpdate(DocumentEvent e) { 96 frame.setProjectChanged(true); 97 changed = true; 98 } 99 100 public void changedUpdate(DocumentEvent 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 commentsScrollP = new JScrollPane (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 () { 120 public void itemStateChanged(ItemEvent 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 (); 131 designationKeys = new ArrayList <String >(); 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 () { 137 public void itemStateChanged(ItemEvent 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 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 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); } 182 183 189 void setUserCommentInputEnable(final boolean isEnabled) { 190 SwingUtilities.invokeLater(new Runnable () { 191 public void run() { 192 setUserCommentInputEnableFromSwingThread(isEnabled); 193 } 194 }); 195 } 196 197 203 void setUserCommentInputEnableFromSwingThread(final boolean isEnabled) { 204 frame.userInputEnabled = isEnabled; 205 if (!isEnabled) { 206 userCommentsText.setText(""); 207 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 224 void updateCommentsFromLeafInformation(final BugLeafNode node) { 225 SwingUtilities.invokeLater(new Runnable () { 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 () { 240 public void run() { 241 updateCommentsFromNonLeafInformationFromSwingThread(theAspects); 242 setUserCommentInputEnableFromSwingThread(true); 243 changed = false; 244 } 245 }); 246 } 247 248 256 private void saveCommentsToBug(BugLeafNode node) { 257 if (node == null) 258 return; 259 260 String 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 [] 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 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 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 336 void loadPrevCommentsList(String [] list) { 337 int count = 0; 338 for (String str : list) { 339 if (str.equals("")) 340 count++; 341 } 342 343 String [] ary = new String [list.length - count]; 344 int j = 0; 345 for (String str : list) { 346 if (!str.equals("")) { 347 ary[j] = str; 348 j++; 349 } 350 } 351 352 String [] temp; 353 prevCommentsList = new LinkedList <String >(); 354 if ((ary.length) > prevCommentsMaxSize) { 355 temp = new String [prevCommentsMaxSize]; 356 for (int i = 0; i < temp.length && i < ary.length; i++) 357 temp[i] = ary[i]; 358 } else { 359 temp = new String [ary.length]; 360 for (int i = 0; i < ary.length; i++) 361 temp[i] = ary[i]; 362 } 363 364 for (String str : temp) 365 prevCommentsList.add(str); 366 367 resetPrevCommentsComboBox(); 368 } 369 370 377 private void addToPrevComments(String 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 401 private void resetPrevCommentsComboBox() { 402 prevCommentsComboBox.removeAllItems(); 403 404 prevCommentsComboBox.addItem(""); 405 406 for (String str : prevCommentsList) { 407 if (str.length() < 20) 408 prevCommentsComboBox.addItem(str); 409 else 410 prevCommentsComboBox.addItem(str.substring(0, 17) + "..."); 411 } 412 } 413 414 419 private String getCurrentUserCommentsText() { 420 return userCommentsText.getText(); 421 } 422 423 428 private void setCurrentUserCommentsText(String comment) { 429 changed = true; 430 userCommentsText.setText(comment); 431 } 432 433 436 private String getCurrentPrevCommentsSelection() { 437 return prevCommentsList 438 .get(prevCommentsComboBox.getSelectedIndex() - 1); 439 } 440 441 void addDesignationItem(JMenu menu, final String menuName, int keyEvent) { 442 JMenuItem toggleItem = new JMenuItem (menuName); 443 444 toggleItem.addActionListener(new ActionListener () { 445 public void actionPerformed(ActionEvent 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 designationName) { 457 if (frame.currentSelectedBugLeaf == null) 458 return; 459 String 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 designationName) { 468 String 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 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 } 525 526 protected String getNonLeafCommentsText(BugAspects theAspects) 527 { if (theAspects == null) 528 return ""; 529 BugSet filteredSet = theAspects.getMatchingBugs(BugSet.getMainBugSet()); 530 boolean allSame = true; 531 String comments = null; 532 for (BugLeafNode nextNode : filteredSet) { 533 String 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 566 protected void setDesignationComboBox(String designationKey) { 567 int numItems = designationComboBox.getItemCount(); 568 for (int i = 0; i < numItems; i++) { 569 String 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 selection) { 580 581 if (!getSorter().getOrder().contains(Sortables.DESIGNATION)) { 582 584 theNode.getBug().getNonnullUserDesignation().setDesignationKey( 585 selection); 586 587 } else if (getSorter().getOrderBeforeDivider().contains( 588 Sortables.DESIGNATION)) { 589 590 BugTreeModel model = getModel(); 591 TreePath path = model.getPathToBug(theNode.getBug()); 592 if (path == null) { 593 theNode.getBug().getNonnullUserDesignation().setDesignationKey( 594 selection); 595 return; 596 } 597 Object [] objPath = path.getParentPath().getPath(); 598 ArrayList <Object > reconstruct = new ArrayList <Object >(); 599 ArrayList <TreePath > listOfNodesToReconstruct = new ArrayList <TreePath >(); 600 for (int x = 0; x < objPath.length; x++) { 601 Object o = objPath[x]; 602 reconstruct.add(o); 603 if (o instanceof BugAspects) { 604 if (((BugAspects) o).getCount() == 1) { 605 break; 607 } 608 } 609 TreePath pathToNode = new TreePath (reconstruct.toArray()); 610 listOfNodesToReconstruct.add(pathToNode); 611 } 612 613 theNode.getBug().getNonnullUserDesignation().setDesignationKey( 614 selection); 615 model.suppressBug(path); 616 TreePath unsuppressPath = model.getPathToBug(theNode.getBug()); 617 if (unsuppressPath != null) { 620 model.unsuppressBug(unsuppressPath); 621 } 623 for (TreePath 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 path = model.getPathToBug(theNode.getBug()); 634 if (path != null) 635 model.sortBranch(path.getParentPath()); 636 637 } 638 } 639 640 protected @CheckForNull 641 String convertDesignationNameToDesignationKey(String name) { 642 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 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 |