1 19 20 package org.netbeans.modules.subversion.ui.blame; 21 22 import org.netbeans.editor.*; 23 import org.netbeans.editor.Utilities; 24 import org.netbeans.api.editor.fold.*; 25 import org.netbeans.api.diff.*; 26 import org.netbeans.spi.diff.*; 27 import org.netbeans.modules.subversion.ui.update.RevertModifications; 28 import org.netbeans.modules.subversion.ui.update.RevertModificationsAction; 29 import org.netbeans.modules.subversion.ui.diff.DiffAction; 30 import org.netbeans.modules.subversion.RepositoryFile; 31 import org.netbeans.modules.subversion.Subversion; 32 import org.netbeans.modules.subversion.client.SvnProgressSupport; 33 import org.netbeans.modules.subversion.util.SvnUtils; 34 import org.netbeans.modules.subversion.util.Context; 35 import org.netbeans.modules.versioning.util.Utils; 36 import org.openide.*; 37 import org.openide.loaders.*; 38 import org.openide.filesystems.*; 39 import org.openide.text.*; 40 import org.openide.util.*; 41 import org.openide.xml.*; 42 import org.tigris.subversion.svnclientadapter.SVNUrl; 43 import org.tigris.subversion.svnclientadapter.SVNRevision; 44 45 import javax.swing.*; 46 import javax.swing.Timer ; 47 import javax.swing.event.*; 48 import javax.swing.text.*; 49 import javax.accessibility.Accessible ; 50 import java.awt.*; 51 import java.awt.event.*; 52 import java.beans.*; 53 import java.util.*; 54 import java.util.List ; 55 import java.io.*; 56 import java.text.DateFormat ; 57 import java.text.MessageFormat ; 58 59 70 final class AnnotationBar extends JComponent implements Accessible , PropertyChangeListener, DocumentListener, ChangeListener, ActionListener, Runnable , ComponentListener { 71 72 75 private final JTextComponent textComponent; 76 77 80 private final EditorUI editorUI; 81 82 85 private final FoldHierarchy foldHierarchy; 86 87 90 private final BaseDocument doc; 91 92 95 private final Caret caret; 96 97 101 private Timer caretTimer; 102 103 106 private boolean annotated; 107 108 117 private Map<Element, AnnotateLine> elementAnnotations; 118 119 123 private String elementAnnotationsSubstitute; 124 125 private Color backgroundColor = Color.WHITE; 126 private Color foregroundColor = Color.BLACK; 127 private Color selectedColor = Color.BLUE; 128 129 132 private String recentStatusMessage; 133 134 137 private String recentRevision; 138 139 142 RequestProcessor requestProcessor = null; 143 144 147 private RequestProcessor.Task latestAnnotationTask = null; 148 149 152 private boolean recentRevisionCanBeRolledBack; 153 154 157 public AnnotationBar(JTextComponent target) { 158 this.textComponent = target; 159 this.editorUI = Utilities.getEditorUI(target); 160 this.foldHierarchy = FoldHierarchy.get(editorUI.getComponent()); 161 this.doc = editorUI.getDocument(); 162 this.caret = textComponent.getCaret(); 163 } 164 165 167 172 public void annotate() { 173 annotated = true; 174 elementAnnotations = null; 175 176 doc.addDocumentListener(this); 177 textComponent.addComponentListener(this); 178 editorUI.addPropertyChangeListener(this); 179 180 revalidate(); } 182 183 public void setAnnotationMessage(String message) { 184 elementAnnotationsSubstitute = message; 185 revalidate(); 186 } 187 188 192 public void annotationLines(File file, List <AnnotateLine> annotateLines) { 193 List <AnnotateLine> lines = new LinkedList<AnnotateLine>(annotateLines); 194 int lineCount = lines.size(); 195 196 int ann2editorPermutation[] = new int[lineCount]; 197 for (int i = 0; i< lineCount; i++) { 198 ann2editorPermutation[i] = i+1; 199 } 200 201 DiffProvider diff = (DiffProvider) Lookup.getDefault().lookup(DiffProvider.class); 202 if (diff != null) { 203 Reader r = new LinesReader(lines); 204 Reader docReader = Utils.getDocumentReader(doc); 205 try { 206 207 Difference[] differences = diff.computeDiff(r, docReader); 208 209 212 for (int i = 0; i < differences.length; i++) { 213 Difference d = differences[i]; 214 if (d.getType() == Difference.ADD) continue; 215 216 int editorStart; 217 int firstShift = d.getFirstEnd() - d.getFirstStart() +1; 218 if (d.getType() == Difference.CHANGE) { 219 int firstLen = d.getFirstEnd() - d.getFirstStart(); 220 int secondLen = d.getSecondEnd() - d.getSecondStart(); 221 if (secondLen >= firstLen) continue; editorStart = d.getSecondStart(); 223 firstShift = firstLen - secondLen; 224 } else { editorStart = d.getSecondStart() + 1; 226 } 227 228 for (int c = editorStart + firstShift -1; c<lineCount; c++) { 229 ann2editorPermutation[c] -= firstShift; 230 } 231 } 232 233 for (int i = differences.length -1; i >= 0; i--) { 234 Difference d = differences[i]; 235 if (d.getType() == Difference.DELETE) continue; 236 237 int firstStart; 238 int firstShift = d.getSecondEnd() - d.getSecondStart() +1; 239 if (d.getType() == Difference.CHANGE) { 240 int firstLen = d.getFirstEnd() - d.getFirstStart(); 241 int secondLen = d.getSecondEnd() - d.getSecondStart(); 242 if (secondLen <= firstLen) continue; firstShift = secondLen - firstLen; 244 firstStart = d.getFirstStart(); 245 } else { 246 firstStart = d.getFirstStart() + 1; 247 } 248 249 for (int k = firstStart-1; k<lineCount; k++) { 250 ann2editorPermutation[k] += firstShift; 251 } 252 } 253 254 } catch (IOException e) { 255 ErrorManager err = ErrorManager.getDefault(); 256 err.annotate(e, "Cannot compute local diff required for annotations, ignoring..."); err.notify(ErrorManager.INFORMATIONAL, e); 258 } 259 } 260 261 try { 262 doc.atomicLock(); 263 StyledDocument sd = (StyledDocument) doc; 264 Iterator<AnnotateLine> it = lines.iterator(); 265 elementAnnotations = Collections.synchronizedMap(new HashMap<Element, AnnotateLine>(lines.size())); 266 while (it.hasNext()) { 267 AnnotateLine line = it.next(); 268 int lineNum = ann2editorPermutation[line.getLineNum() -1]; 269 try { 270 int lineOffset = NbDocument.findLineOffset(sd, lineNum -1); 271 Element element = sd.getParagraphElement(lineOffset); 272 elementAnnotations.put(element, line); 273 } catch (IndexOutOfBoundsException ex) { 274 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 277 } 278 } 279 } finally { 280 doc.atomicUnlock(); 281 } 282 283 caret.addChangeListener(this); 285 this.caretTimer = new Timer (500, this); 286 caretTimer.setRepeats(false); 287 288 onCurrentLine(); 289 revalidate(); 290 repaint(); 291 } 292 293 295 301 private File getCurrentFile() { 302 File result = null; 303 304 DataObject dobj = (DataObject)doc.getProperty(Document.StreamDescriptionProperty); 305 if (dobj != null) { 306 FileObject fo = dobj.getPrimaryFile(); 307 result = FileUtil.toFile(fo); 308 } 309 310 return result; 311 } 312 313 317 public void addNotify() { 318 super.addNotify(); 319 320 321 this.addMouseListener(new MouseAdapter() { 322 public void mousePressed(MouseEvent e) { 323 maybeShowPopup(e); 324 } 325 326 public void mouseReleased(MouseEvent e) { 327 maybeShowPopup(e); 328 } 329 330 private void maybeShowPopup(MouseEvent e) { 331 if (e.isPopupTrigger()) { 332 createPopup().show(e.getComponent(), 333 e.getX(), e.getY()); 334 } 335 } 336 }); 337 338 setToolTipText(""); 341 } 342 343 private JPopupMenu createPopup() { 344 final ResourceBundle loc = NbBundle.getBundle(AnnotationBar.class); 345 final JPopupMenu popupMenu = new JPopupMenu(); 346 347 final File file = getCurrentFile(); 348 349 final JMenuItem diffMenu = new JMenuItem(loc.getString("CTL_MenuItem_DiffToRevision")); 350 diffMenu.addActionListener(new ActionListener() { 351 public void actionPerformed(ActionEvent e) { 352 if (recentRevision != null) { 353 if (getPreviousRevision(recentRevision) != null) { 354 DiffAction.diff(file, getPreviousRevision(recentRevision), recentRevision); 355 } 356 } 357 } 358 }); 359 popupMenu.add(diffMenu); 360 361 JMenuItem rollbackMenu = new JMenuItem(loc.getString("CTL_MenuItem_Revert")); 362 rollbackMenu.addActionListener(new ActionListener() { 363 public void actionPerformed(ActionEvent e) { 364 revert(file, recentRevision); 365 } 366 }); 367 popupMenu.add(rollbackMenu); 368 rollbackMenu.setEnabled(recentRevisionCanBeRolledBack); 369 370 JMenuItem menu; 371 menu = new JMenuItem(loc.getString("CTL_MenuItem_CloseAnnotations")); 372 menu.addActionListener(new ActionListener() { 373 public void actionPerformed(ActionEvent e) { 374 hideBar(); 375 } 376 }); 377 popupMenu.add(new JSeparator()); 378 popupMenu.add(menu); 379 380 diffMenu.setVisible(false); 381 rollbackMenu.setVisible(false); 382 if (recentRevision != null) { 383 if (getPreviousRevision(recentRevision) != null) { 384 String format = loc.getString("CTL_MenuItem_DiffToRevision"); 385 diffMenu.setText(MessageFormat.format(format, new Object [] { recentRevision, getPreviousRevision(recentRevision) })); 386 diffMenu.setVisible(true); 387 } 388 rollbackMenu.setVisible(true); 389 } 390 391 return popupMenu; 392 } 393 394 private void revert(File file, String revision) { 395 final Context ctx = new Context(file); 396 final SVNUrl url = SvnUtils.getRepositoryRootUrl(file); 397 final RepositoryFile repositoryFile = new RepositoryFile(url, url, SVNRevision.HEAD); 398 399 final RevertModifications revertModifications = new RevertModifications(repositoryFile, revision); 400 if(!revertModifications.showDialog()) { 401 return; 402 } 403 404 RequestProcessor rp = Subversion.getInstance().getRequestProcessor(url); 405 SvnProgressSupport support = new SvnProgressSupport() { 406 public void perform() { 407 RevertModificationsAction.performRevert(ctx, revertModifications, this); 408 } 409 }; 410 support.start(rp, url, NbBundle.getMessage(AnnotationBar.class, "MSG_Revert_Progress")); } 412 413 private String getPreviousRevision(String revision) { 414 return Long.toString(Long.parseLong(revision) - 1); 415 } 416 417 420 void hideBar() { 421 annotated = false; 422 revalidate(); 423 release(); 424 } 425 426 429 private RequestProcessor getRequestProcessor() { 430 if (requestProcessor == null) { 431 requestProcessor = new RequestProcessor("AnnotationBarRP", 1, true); } 433 434 return requestProcessor; 435 } 436 437 442 private void onCurrentLine() { 443 if (latestAnnotationTask != null) { 444 latestAnnotationTask.cancel(); 445 } 446 447 latestAnnotationTask = getRequestProcessor().post(this); 448 } 449 450 public void run() { 452 ResourceBundle loc = NbBundle.getBundle(AnnotationBar.class); 454 StatusBar statusBar = editorUI.getStatusBar(); 456 recentStatusMessage = loc.getString("CTL_StatusBar_WaitFetchAnnotation"); 457 statusBar.setText(StatusBar.CELL_MAIN, recentStatusMessage); 458 459 recentRevisionCanBeRolledBack = false; 460 int line = -1; 462 int offset = caret.getDot(); 463 try { 464 line = Utilities.getLineOffset(doc, offset); 465 } catch (BadLocationException ex) { 466 ErrorManager err = ErrorManager.getDefault(); 467 err.annotate(ex, "Can not get line for caret at offset " + offset); err.notify(ex); 469 clearRecentFeedback(); 470 return; 471 } 472 473 AnnotateLine al = getAnnotateLine(line); 475 if (al == null) { 476 AnnotationMarkProvider amp = AnnotationMarkInstaller.getMarkProvider(textComponent); 477 if (amp != null) { 478 amp.setMarks(Collections.<AnnotationMark>emptyList()); 479 } 480 clearRecentFeedback(); 481 if (recentRevision != null) { 482 recentRevision = null; 483 repaint(); 484 } 485 return; 486 } 487 488 String revision = al.getRevision(); 490 if (revision.equals(recentRevision) == false) { 491 recentRevision = revision; 492 recentRevisionCanBeRolledBack = al.canBeRolledBack(); 493 repaint(); 494 495 AnnotationMarkProvider amp = AnnotationMarkInstaller.getMarkProvider(textComponent); 496 if (amp != null) { 497 498 List <AnnotationMark> marks = new ArrayList<AnnotationMark>(elementAnnotations.size()); 499 Iterator<Map.Entry<Element, AnnotateLine>> it2; 502 synchronized(elementAnnotations) { 503 it2 = new HashSet<Map.Entry<Element, AnnotateLine>>(elementAnnotations.entrySet()).iterator(); 504 } 505 while (it2.hasNext()) { 506 Map.Entry<Element, AnnotateLine> next = it2.next(); 507 AnnotateLine annotateLine = next.getValue(); 508 if (revision.equals(annotateLine.getRevision())) { 509 Element element = next.getKey(); 510 if (elementAnnotations.containsKey(element) == false) { 511 continue; 512 } 513 int elementOffset = element.getStartOffset(); 514 int lineNumber = NbDocument.findLineNumber((StyledDocument)doc, elementOffset); 515 AnnotationMark mark = new AnnotationMark(lineNumber, revision); 516 marks.add(mark); 517 } 518 519 if (Thread.interrupted()) { 520 clearRecentFeedback(); 521 return; 522 } 523 } 524 amp.setMarks(marks); 525 } 526 } 527 528 if (al.getCommitMessage() != null) { 529 recentStatusMessage = al.getCommitMessage(); 530 statusBar.setText(StatusBar.CELL_MAIN, al.getAuthor() + ": " + recentStatusMessage); } else { 532 clearRecentFeedback(); 533 }; 534 } 535 536 540 private void clearRecentFeedback() { 541 StatusBar statusBar = editorUI.getStatusBar(); 542 if (statusBar.getText(StatusBar.CELL_MAIN) == recentStatusMessage) { 543 statusBar.setText(StatusBar.CELL_MAIN, ""); } 545 } 546 547 556 public Dimension getPreferredSize() { 557 Dimension dim = textComponent.getSize(); 558 int width = annotated ? getBarWidth() : 0; 559 dim.width = width; 560 dim.height *=2; return dim; 562 } 563 564 569 public Dimension getMaximumSize() { 570 return getPreferredSize(); 571 } 572 573 578 private int getBarWidth() { 579 String longestString = ""; if (elementAnnotations == null) { 581 longestString = elementAnnotationsSubstitute; 582 } else { 583 synchronized(elementAnnotations) { 584 Iterator<AnnotateLine> it = elementAnnotations.values().iterator(); 585 while (it.hasNext()) { 586 AnnotateLine line = it.next(); 587 String displayName = getDisplayName(line); if (displayName.length() > longestString.length()) { 589 longestString = displayName; 590 } 591 } 592 } 593 } 594 char[] data = longestString.toCharArray(); 595 int w = getGraphics().getFontMetrics().charsWidth(data, 0, data.length); 596 return w + 4; 597 } 598 599 private String getDisplayName(AnnotateLine line) { 600 return line.getRevision() + " " + line.getAuthor(); } 602 603 607 private void release() { 608 editorUI.removePropertyChangeListener(this); 609 textComponent.removeComponentListener(this); 610 doc.removeDocumentListener(this); 611 caret.removeChangeListener(this); 612 if (caretTimer != null) { 613 caretTimer.removeActionListener(this); 614 } 615 elementAnnotations = null; 616 if(latestAnnotationTask != null) { 618 latestAnnotationTask.cancel(); 619 } 620 AnnotationMarkProvider amp = AnnotationMarkInstaller.getMarkProvider(textComponent); 621 if (amp != null) { 622 amp.setMarks(Collections.<AnnotationMark>emptyList()); 623 } 624 625 clearRecentFeedback(); 626 } 627 628 632 private void paintView(View view, Graphics g, int yBase) { 633 JTextComponent component = editorUI.getComponent(); 634 if (component == null) return; 635 BaseTextUI textUI = (BaseTextUI)component.getUI(); 636 637 Element rootElem = textUI.getRootView(component).getElement(); 638 int line = rootElem.getElementIndex(view.getStartOffset()); 639 640 String annotation = ""; AnnotateLine al = null; 642 if (elementAnnotations != null) { 643 al = getAnnotateLine(line); 644 if (al != null) { 645 annotation = getDisplayName(al); } 647 } else { 648 annotation = elementAnnotationsSubstitute; 649 } 650 651 if (al != null && al.getRevision().equals(recentRevision)) { 652 g.setColor(selectedColor()); 653 } else { 654 g.setColor(foregroundColor()); 655 } 656 g.drawString(annotation, 2, yBase + editorUI.getLineAscent()); 657 } 658 659 662 public String getToolTipText (MouseEvent e) { 663 if (editorUI == null) 664 return null; 665 int line = getLineFromMouseEvent(e); 666 667 StringBuffer annotation = new StringBuffer (); 668 if (elementAnnotations != null) { 669 AnnotateLine al = getAnnotateLine(line); 670 671 if (al != null) { 672 String escapedAuthor = NbBundle.getMessage(AnnotationBar.class, "TT_Annotation"); try { 674 escapedAuthor = XMLUtil.toElementContent(al.getAuthor()); 675 } catch (CharConversionException e1) { 676 ErrorManager err = ErrorManager.getDefault(); 677 err.annotate(e1, "CVS.AB: can not HTML escape: " + al.getAuthor()); err.notify(ErrorManager.INFORMATIONAL, e1); 679 } 680 681 annotation.append("<html><!-- line=" + line++ + " -->" + al.getRevision() + " - <b>" + escapedAuthor + "</b>"); if (al.getDate() != null) { 684 annotation.append(" " + DateFormat.getDateInstance().format(al.getDate())); } 686 if (al.getCommitMessage() != null) { 687 String escaped = null; 688 try { 689 escaped = XMLUtil.toElementContent(al.getCommitMessage()); 690 } catch (CharConversionException e1) { 691 ErrorManager err = ErrorManager.getDefault(); 692 err.annotate(e1, "CVS.AB: can not HTML escape: " + al.getCommitMessage()); err.notify(ErrorManager.INFORMATIONAL, e1); 694 } 695 if (escaped != null) { 696 String lined = escaped.replaceAll(System.getProperty("line.separator"), "<br>"); annotation.append("<p>" + lined); } 699 } 700 } 701 } else { 702 annotation.append(elementAnnotationsSubstitute); 703 } 704 705 return annotation.toString(); 706 } 707 708 720 private AnnotateLine getAnnotateLine(int line) { 721 StyledDocument sd = (StyledDocument) doc; 722 int lineOffset = NbDocument.findLineOffset(sd, line); 723 Element element = sd.getParagraphElement(lineOffset); 724 AnnotateLine al = elementAnnotations.get(element); 725 726 if (al != null) { 727 int startOffset = element.getStartOffset(); 728 int endOffset = element.getEndOffset(); 729 try { 730 int len = endOffset - startOffset; 731 String text = doc.getText(startOffset, len -1); 732 String content = al.getContent(); 733 if (text.equals(content)) { 734 return al; 735 } 736 } catch (BadLocationException e) { 737 ErrorManager err = ErrorManager.getDefault(); 738 err.annotate(e, "CVS.AB: can not locate line annotation."); err.notify(ErrorManager.INFORMATIONAL, e); 740 } 741 } 742 743 return null; 744 } 745 746 751 public void paintComponent(Graphics g) { 752 super.paintComponent(g); 753 754 Rectangle clip = g.getClipBounds(); 755 756 JTextComponent component = editorUI.getComponent(); 757 if (component == null) return; 758 759 BaseTextUI textUI = (BaseTextUI)component.getUI(); 760 View rootView = Utilities.getDocumentView(component); 761 if (rootView == null) return; 762 763 g.setColor(backgroundColor()); 764 g.fillRect(clip.x, clip.y, clip.width, clip.height); 765 766 AbstractDocument doc = (AbstractDocument)component.getDocument(); 767 doc.readLock(); 768 try{ 769 foldHierarchy.lock(); 770 try{ 771 int startPos = textUI.getPosFromY(clip.y); 772 int startViewIndex = rootView.getViewIndex(startPos,Position.Bias.Forward); 773 int rootViewCount = rootView.getViewCount(); 774 775 if (startViewIndex >= 0 && startViewIndex < rootViewCount) { 776 Rectangle rec = textUI.modelToView(component, rootView.getView(startViewIndex).getStartOffset()); 778 int y = (rec == null) ? 0 : rec.y; 779 780 int clipEndY = clip.y + clip.height; 781 for (int i = startViewIndex; i < rootViewCount; i++){ 782 View view = rootView.getView(i); 783 paintView(view, g, y); 784 y += editorUI.getLineHeight(); 785 if (y >= clipEndY) { 786 break; 787 } 788 } 789 } 790 791 } finally { 792 foldHierarchy.unlock(); 793 } 794 } catch (BadLocationException ble){ 795 ErrorManager.getDefault().notify(ble); 796 } finally { 797 doc.readUnlock(); 798 } 799 } 800 801 private Color backgroundColor() { 802 if (textComponent != null) { 803 return textComponent.getBackground(); 804 } 805 return backgroundColor; 806 } 807 808 private Color foregroundColor() { 809 if (textComponent != null) { 810 return textComponent.getForeground(); 811 } 812 return foregroundColor; 813 } 814 815 private Color selectedColor() { 816 if (backgroundColor == backgroundColor()) { 817 return selectedColor; 818 } 819 if (textComponent != null) { 820 return textComponent.getForeground(); 821 } 822 return selectedColor; 823 824 } 825 826 827 828 private int getLineFromMouseEvent(MouseEvent e){ 829 int line = -1; 830 if (editorUI != null) { 831 try{ 832 JTextComponent component = editorUI.getComponent(); 833 BaseTextUI textUI = (BaseTextUI)component.getUI(); 834 int clickOffset = textUI.viewToModel(component, new Point(0, e.getY())); 835 line = Utilities.getLineOffset(doc, clickOffset); 836 }catch (BadLocationException ble){ 837 } 838 } 839 return line; 840 } 841 842 843 public void propertyChange(PropertyChangeEvent evt) { 844 if (evt == null) return; 845 String id = evt.getPropertyName(); 846 if (EditorUI.COMPONENT_PROPERTY.equals(id)) { if (evt.getNewValue() == null){ 848 release(); 850 } 851 } 852 853 } 854 855 856 public void changedUpdate(DocumentEvent e) { 857 } 858 859 860 public void insertUpdate(DocumentEvent e) { 861 if (elementAnnotations != null) { 867 Element[] elements = e.getDocument().getRootElements(); 868 synchronized(elementAnnotations) { for (int i = 0; i < elements.length; i++) { 870 Element element = elements[i]; 871 DocumentEvent.ElementChange change = e.getChange(element); 872 if (change == null) continue; 873 Element[] removed = change.getChildrenRemoved(); 874 Element[] added = change.getChildrenAdded(); 875 876 if (removed.length == added.length) { 877 for (int c = 0; c<removed.length; c++) { 878 AnnotateLine recent = elementAnnotations.get(removed[c]); 879 if (recent != null) { 880 elementAnnotations.remove(removed[c]); 881 elementAnnotations.put(added[c], recent); 882 } 883 } 884 } else if (removed.length == 1 && added.length > 0) { 885 Element key = removed[0]; 886 AnnotateLine recent = elementAnnotations.get(key); 887 if (recent != null) { 888 elementAnnotations.remove(key); 889 elementAnnotations.put(added[0], recent); 890 } 891 } 892 } 893 } 894 } 895 repaint(); 896 } 897 898 899 public void removeUpdate(DocumentEvent e) { 900 if (e.getDocument().getLength() == 0) { hideBar(); 902 } 903 repaint(); 904 } 905 906 907 public void stateChanged(ChangeEvent e) { 908 assert e.getSource() == caret; 909 caretTimer.restart(); 910 } 911 912 913 public void actionPerformed(ActionEvent e) { 914 assert e.getSource() == caretTimer; 915 onCurrentLine(); 916 } 917 918 919 public void componentHidden(ComponentEvent e) { 920 } 921 922 923 public void componentMoved(ComponentEvent e) { 924 } 925 926 927 public void componentResized(ComponentEvent e) { 928 revalidate(); 929 } 930 931 932 public void componentShown(ComponentEvent e) { 933 } 934 } 935 | Popular Tags |