1 19 20 package org.netbeans.core.output2; 21 22 import java.awt.Component ; 23 import java.awt.Container ; 24 import java.awt.FileDialog ; 25 import java.awt.Frame ; 26 import java.awt.KeyboardFocusManager ; 27 import java.awt.Point ; 28 import java.awt.Toolkit ; 29 import java.awt.event.ActionEvent ; 30 import java.awt.event.KeyEvent ; 31 import java.beans.PropertyChangeListener ; 32 import java.io.CharConversionException ; 33 import java.io.File ; 34 import java.io.FileOutputStream ; 35 import java.io.IOException ; 36 import java.io.OutputStream ; 37 import java.util.HashSet ; 38 import java.util.Iterator ; 39 import java.util.regex.Matcher ; 40 import javax.swing.AbstractAction ; 41 import javax.swing.Action ; 42 import javax.swing.JCheckBoxMenuItem ; 43 import javax.swing.JComponent ; 44 import javax.swing.JFileChooser ; 45 import javax.swing.JOptionPane ; 46 import javax.swing.JPopupMenu ; 47 import javax.swing.JSeparator ; 48 import javax.swing.KeyStroke ; 49 import javax.swing.SwingUtilities ; 50 import javax.swing.UIManager ; 51 import javax.swing.event.PopupMenuEvent ; 52 import javax.swing.event.PopupMenuListener ; 53 import javax.swing.text.BadLocationException ; 54 import org.netbeans.core.output2.ui.AbstractOutputTab; 55 import org.openide.actions.FindAction; 56 import org.openide.util.Exceptions; 57 import org.openide.util.Mutex; 58 import org.openide.util.NbBundle; 59 import org.openide.util.Utilities; 60 import org.openide.windows.OutputEvent; 61 import org.openide.windows.OutputListener; 62 import org.openide.windows.WindowManager; 63 import org.openide.xml.XMLUtil; 64 65 73 public class Controller { 75 public static void ensureViewInDefault (final NbIO io, final boolean reuse) { 76 Mutex.EVENT.readAccess(new Runnable () { 77 public void run() { 78 OutputWindow.findDefault(); 79 IOEvent evt = new IOEvent (io, IOEvent.CMD_CREATE, reuse); 80 NbIO.post(evt); 81 } 82 }); 83 } 84 85 private static final int ACTION_COPY = 0; 86 private static final int ACTION_WRAP = 1; 87 private static final int ACTION_SAVEAS = 2; 88 private static final int ACTION_CLOSE = 3; 89 private static final int ACTION_NEXTERROR = 4; 90 private static final int ACTION_PREVERROR = 5; 91 private static final int ACTION_SELECTALL = 6; 92 private static final int ACTION_FIND = 7; 93 private static final int ACTION_FINDNEXT = 8; 94 private static final int ACTION_NAVTOLINE = 9; 95 private static final int ACTION_POSTMENU = 10; 96 private static final int ACTION_FINDPREVIOUS = 11; 97 private static final int ACTION_CLEAR = 12; 98 private static final int ACTION_NEXTTAB = 13; 99 private static final int ACTION_PREVTAB = 14; 100 103 104 Action copyAction = new ControllerAction (ACTION_COPY, 106 "ACTION_COPY"); Action wrapAction = new ControllerAction (ACTION_WRAP, 108 "ACTION_WRAP"); Action saveAsAction = new ControllerAction (ACTION_SAVEAS, 110 "ACTION_SAVEAS"); Action closeAction = new ControllerAction (ACTION_CLOSE, 112 "ACTION_CLOSE"); Action nextErrorAction = new ControllerAction (ACTION_NEXTERROR, 114 "ACTION_NEXT_ERROR" ); Action prevErrorAction = new ControllerAction (ACTION_PREVERROR, 116 "ACTION_PREV_ERROR" ); Action selectAllAction = new ControllerAction (ACTION_SELECTALL, 118 "ACTION_SELECT_ALL"); Action findAction = new ControllerAction (ACTION_FIND, 120 "ACTION_FIND"); Action findNextAction = new ControllerAction (ACTION_FINDNEXT, 122 "ACTION_FIND_NEXT"); Action findPreviousAction = new ControllerAction (ACTION_FINDPREVIOUS, 124 "ACTION_FIND_PREVIOUS"); Action navToLineAction = new ControllerAction (ACTION_NAVTOLINE, "navToLine", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)); 127 Action postMenuAction = new ControllerAction (ACTION_POSTMENU, "postMenu", KeyStroke.getKeyStroke(KeyEvent.VK_F10, KeyEvent.SHIFT_DOWN_MASK)); 129 Action clearAction = new ControllerAction (ACTION_CLEAR, "ACTION_CLEAR"); 130 131 Action nextTabAction = new ControllerAction (ACTION_NEXTTAB, "NextViewAction", (KeyStroke )null); 133 Action prevTabAction = new ControllerAction (ACTION_PREVTAB, "PreviousViewAction", (KeyStroke )null); 135 140 private Object [] popupItems = new Object [] { 141 copyAction, new JSeparator (), findAction, findNextAction, 142 new JSeparator (), 143 wrapAction, new JSeparator (), saveAsAction, clearAction, closeAction, 144 }; 145 146 private Action [] kbdActions = new Action [] { 147 copyAction, selectAllAction, findAction, findNextAction, 148 findPreviousAction, wrapAction, saveAsAction, closeAction, 149 navToLineAction, postMenuAction, clearAction, }; 151 152 Controller() {} 153 154 private OutputTab createOutputTab (OutputWindow win, NbIO io, boolean activateContainer, boolean reuse) { 155 AbstractOutputTab[] ov = win.getTabs(); 156 OutputTab result = null; 157 if (LOG) log ("Find or create component for nbio " + io); 158 159 for (int i=0; i < ov.length; i++) { 160 OutputTab oc = (OutputTab) ov[i]; 161 if (oc.getIO() == io) { 162 if (LOG) log ("Found an existing tab"); 163 result = oc; 164 break; 165 } 166 } 167 if (result == null) { 168 if (LOG) log ("Didn't find an existing open tab, checking hidden tabs"); 169 OutputTab[] hidden = win.getHiddenTabs(); 170 for (int i=0; i < hidden.length; i++) { 171 OutputTab oc = hidden[i]; 172 if (hidden[i].getIO() == io) { 173 if (LOG) log ("Found a hidden tab with the same IO. Unhiding it for reuse"); 174 result = oc; 175 unhideHiddenView (win, result); 176 break; 177 } 178 } 179 } 180 181 if (LOG) log ("FindOrCreate: " + io.getName() + " found=" + (result != 182 null) + " for io " + io); 183 184 if (result == null) { 185 if (LOG) log ("Find or create creating " + io.getName()); 186 result = createAndInstallView (win, io); 187 } 188 if (result != null) { 189 result.getActionMap ().put ("jumpPrev", this.prevErrorAction); result.getActionMap ().put ("jumpNext", this.nextErrorAction); result.getActionMap ().put (FindAction.class.getName (), this.findAction); 193 result.getActionMap ().put (javax.swing.text.DefaultEditorKit.copyAction, this.copyAction); 194 } 195 196 if (result != null) { 197 win.setSelectedTab(result); 198 } 199 200 return result; 201 } 202 203 210 private OutputTab createAndInstallView (OutputWindow win, NbIO io) { 211 if (LOG) log ("Create and install a new tab for : " + io.getName()); 212 OutputTab result = new OutputTab (io); 213 result.setName (io.getName() + " "); 214 Action [] a = io.getToolbarActions(); 215 if (a != null) { 216 result.setToolbarActions(a); 217 } 218 for (int i=0; i < kbdActions.length; i++) { 219 result.installKeyboardAction(kbdActions[i]); 220 } 221 222 if (LOG) log ("Adding and selecting new tab " + result); 223 win.add (result); 224 win.setSelectedTab(result); 225 AbstractOutputTab[] aot = win.getTabs(); 229 for (int i=0; i < aot.length; i++) { 230 updateName(win, (OutputTab) aot[i]); 231 } 232 return result; 233 } 234 235 244 private void unhideHiddenView (OutputWindow win, OutputTab hidden) { 245 if (LOG) log ("Unhiding hidden tab for " + hidden.getIO()); 246 win.add (hidden); 247 win.removeHiddenView(hidden); 248 } 249 250 259 private void updateName (OutputWindow win, OutputTab tab) { 260 if (nameUpdater == null) { 261 if (LOG) log ("Update name for " + tab.getIO() + " dispatching a name updater"); 262 nameUpdater = new CoalescedNameUpdater(win); 263 SwingUtilities.invokeLater(nameUpdater); 264 } 265 nameUpdater.add (tab); 266 } 267 268 private CoalescedNameUpdater nameUpdater = null; 269 282 private class CoalescedNameUpdater implements Runnable { 283 private HashSet components = new HashSet (); 284 private OutputWindow win; 285 CoalescedNameUpdater (OutputWindow win) { 286 this.win = win; 287 } 288 289 293 public void add (OutputTab tab) { 294 components.add (tab); 295 } 296 297 public void remove(OutputTab tab) { 298 components.remove(tab); 299 } 300 301 public void run() { 302 for (Iterator i=components.iterator(); i.hasNext();) { 303 OutputTab t = (OutputTab) i.next(); 304 NbIO io = t.getIO(); 305 if (LOG) { 306 log ("Update name for " + io.getName() + " stream " + 307 "closed is " + io.isStreamClosed()); 308 } 309 if (win.isAncestorOf(t)) { 310 String escaped; 311 try { 312 escaped = XMLUtil.toAttributeValue(io.getName()); 313 } catch (CharConversionException e) { 314 escaped = io.getName(); 315 } 316 boolean wasReset = io.checkReset(); 317 boolean useHtml = io.isStreamClosed() && !wasReset; 318 319 String name = useHtml ? io.getName() + " " : 320 "<html><b>" + escaped 321 + " </b> </html>"; 323 if (LOG) log (" set name to " + name); 324 win.setTabTitle (t, name.replace("'", "'")); 326 } 327 } 328 nameUpdater = null; 329 } 330 } 331 332 private void forceName(OutputWindow win, OutputTab tab) { 333 if (LOG) log ("ForceName ensuring non-html tab name"); 334 if (nameUpdater != null) { 335 if (LOG) log (" an update was queued, aborting it"); 336 nameUpdater.remove(tab); 337 } 338 if (win.isAncestorOf(tab)) { 339 String escaped; 340 try { 341 escaped = XMLUtil.toAttributeValue(tab.getIO().getName() + " "); 342 } catch (CharConversionException e) { 343 escaped = tab.getIO().getName() + " "; 344 } 345 if (LOG) log (" setting non-html name " + escaped); 346 win.setTabTitle (tab, escaped.replace("'", "'")); 348 } 349 } 350 351 359 public void actionPerformed(OutputWindow win, OutputTab tab, int id) { 360 switch (id) { 361 case ACTION_COPY: 362 tab.getOutputPane().copy(); 363 break; 364 case ACTION_WRAP: 365 boolean wrapped = tab.getOutputPane().isWrapped(); 366 tab.getOutputPane().setWrapped(!wrapped); 367 break; 368 case ACTION_SAVEAS: 369 saveAs (tab); 370 break; 371 case ACTION_CLOSE: 372 close (win, tab, false); 373 break; 374 case ACTION_NEXTERROR: 375 sendCaretToError(win, tab, false); 376 break; 377 case ACTION_PREVERROR: 378 sendCaretToError(win, tab, true); 379 break; 380 case ACTION_SELECTALL: 381 tab.getOutputPane().selectAll(); 382 break; 383 case ACTION_FIND: 384 int start = tab.getOutputPane().getSelectionStart(); 385 int end = tab.getOutputPane().getSelectionEnd(); 386 String str = null; 387 if (start > 0 && end > start) { 388 try { 389 str = tab.getOutputPane().getDocument().getText(start, end - start); 390 } catch (BadLocationException ex) { 391 ex.printStackTrace(); 392 } 393 } 394 FindDialogPanel.showFindDialog(tab.getFindActionListener(findNextAction, findPreviousAction, copyAction), str); 395 break; 396 case ACTION_FINDNEXT: 397 findNext (tab); 398 break; 399 case ACTION_FINDPREVIOUS : 400 findPrevious (tab); 401 break; 402 case ACTION_NAVTOLINE : 403 if (LOG) log ("Action NAVTOLINE received"); 404 openLineIfError (tab); 405 break; 406 case ACTION_POSTMENU : 407 if (LOG) log ("Action POSTMENU received"); 408 postPopupMenu(win, tab, new Point (0,0), tab); 409 break; 410 case ACTION_CLEAR : 411 if (LOG) log ("Action CLEAR receieved"); 412 NbIO io = tab.getIO(); 413 414 if (io != null) { 415 NbWriter writer = io.writer(); 416 if (writer != null) { 417 try { 418 if (LOG) log ("Resetting the writer for Clear"); 419 writer.reset(); 420 forceName(win, tab); 421 } catch (IOException ioe) { 422 Exceptions.printStackTrace(ioe); 423 } 424 } else if (LOG) { 425 log ("IO's NbWriter is null"); 426 } 427 } else if (LOG) { 428 log ("Clear on a tab with no IO"); 429 } 430 break; 431 case ACTION_NEXTTAB : 432 if (LOG) log ("Action NEXTTAB received"); 433 win.selectNextTab(tab); 434 break; 435 case ACTION_PREVTAB : 436 if (LOG) log ("Action PREVTAB received"); 437 win.selectPreviousTab(tab); 438 break; 439 451 default : 452 assert false; 453 } 454 } 455 456 461 private void openLineIfError(OutputTab tab) { 462 OutWriter out = tab.getIO().out(); 463 if (out != null) { 464 int line = tab.getOutputPane().getCaretLine(); 465 OutputListener lis = out.getLines().getListenerForLine(line); 466 if (lis != null) { 467 if (LOG) log (" Sending action for getLine " + line); 468 ignoreCaretChanges = true; 469 tab.getOutputPane().sendCaretToLine(line, true); 470 ignoreCaretChanges = false; 471 ControllerOutputEvent coe = new ControllerOutputEvent (tab.getIO(), line); 472 lis.outputLineAction(coe); 473 } 474 } 475 } 476 477 478 479 485 private void findNext (OutputTab tab) { 486 OutWriter out = tab.getIO().out(); 487 if (out != null) { 488 String lastPattern = FindDialogPanel.getPanel().getPattern(); 489 if (lastPattern != null) { 490 out.getLines().find(lastPattern); 491 } 492 Matcher matcher = out.getLines().getForwardMatcher(); 493 int pos = tab.getOutputPane().getCaretPos(); 494 if (pos >= tab.getOutputPane().getLength() || pos < 0) { 495 pos = 0; 496 } 497 498 if (matcher != null && matcher.find (pos)) { 499 tab.getOutputPane().setSelection(matcher.start(), matcher.end()); 500 copyAction.setEnabled(true); 501 } else { 502 Toolkit.getDefaultToolkit().beep(); 503 } 504 } 505 } 506 507 513 private void findPrevious (OutputTab tab) { 514 OutWriter out = tab.getIO().out(); 515 if (out != null) { 516 String lastPattern = FindDialogPanel.getPanel().getPattern(); 517 if (lastPattern != null) { 518 out.getLines().find(lastPattern); 519 } 520 Matcher matcher = out.getLines().getReverseMatcher(); 521 522 int length = tab.getOutputPane().getLength(); 523 int pos = length - tab.getOutputPane().getSelectionStart(); 524 525 if (pos >= tab.getOutputPane().getLength()-1 || pos < 0) { 526 pos = 0; 527 } 528 if (LOG) log ("Reverse search from " + pos); 529 if (matcher != null && matcher.find (pos)) { 530 int start = length - matcher.end(); 531 int end = length - matcher.start(); 532 tab.getOutputPane().setSelection(start, end); 533 copyAction.setEnabled(true); 534 } else { 535 Toolkit.getDefaultToolkit().beep(); 536 } 537 } 538 } 539 540 547 private void updateActions (OutputWindow win, OutputTab tab) { 548 if (tab == win.getSelectedTab()) { 549 OutputPane pane = (OutputPane) tab.getOutputPane(); 550 int len = pane.getLength(); 551 boolean enable = len > 0; 552 findAction.setEnabled (enable); 553 OutWriter out = tab.getIO().out(); 554 saveAsAction.setEnabled (enable); 557 selectAllAction.setEnabled(enable); 558 copyAction.setEnabled(pane.hasSelection()); 559 boolean hasErrors = out == null ? false : out.getLines().firstListenerLine() != -1; 560 nextErrorAction.setEnabled(hasErrors); 561 prevErrorAction.setEnabled(hasErrors); 562 } 563 } 564 565 573 public void close(OutputWindow win, OutputTab tab, boolean programmatic) { 574 Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner(); 577 boolean hadFocus = focusOwner != null && (focusOwner == win || win.isAncestorOf(focusOwner)); 578 579 win.remove(tab); boolean winClosed = false; 581 if (!programmatic && win.getTabs().length == 0) { 582 if (LOG) log ("Last tab closed by user, closing output window."); 583 win.close(); 584 winClosed = true; 585 } 586 if (hadFocus) { 587 if (!winClosed && win.getSelectedTab() != null) { 588 if (LOG) log ("Trying to send focus to the newly selected tab"); 589 win.getSelectedTab().requestFocus(); 590 } 591 } 592 if (LOG) log ("Close received, removing " + tab + " from component"); 593 } 594 595 598 private static String lastDir = null; 599 600 606 private void saveAs(OutputTab tab) { 607 OutWriter out = tab.getIO().out(); 608 if (out == null) { 609 return; 610 } 611 File f = showFileChooser (tab); 612 if (f != null) { 613 try { 614 synchronized (out) { 615 out.getLines().saveAs(f.getPath()); 616 } 617 } catch (IOException ioe) { 618 Exceptions.printStackTrace(ioe); 619 } 620 } 621 } 622 623 632 private static File showFileChooser (JComponent owner) { 633 File f = null; 634 String dlgTtl = NbBundle.getMessage (Controller.class, "TITLE_SAVE_DLG"); 636 boolean isAqua = "Aqua".equals(UIManager.getLookAndFeel().getID()); 638 if (isAqua) { 639 FileDialog fd = new FileDialog ((Frame ) owner.getTopLevelAncestor(), dlgTtl, FileDialog.SAVE); 641 if (lastDir != null && new File (lastDir).exists()) { 642 fd.setDirectory(lastDir); 643 } 644 fd.setModal(true); 645 fd.setVisible(true); 646 String s = fd.getDirectory() + fd.getFile(); 647 f = new File (s); 648 if (f.exists() && f.isDirectory()) { 649 f = null; 650 } 651 } else { 652 JFileChooser jfc = new JFileChooser (); 653 if (lastDir != null && new File (lastDir).exists()) { 654 File dir = new File (lastDir); 655 if (dir.exists()) { 656 jfc.setCurrentDirectory(dir); 657 } 658 } 659 jfc.setName(dlgTtl); 660 jfc.setDialogTitle(dlgTtl); 661 662 if (jfc.showSaveDialog(owner.getTopLevelAncestor()) == JFileChooser.APPROVE_OPTION) { 663 f = jfc.getSelectedFile(); 664 } 665 } 666 667 if (f != null && f.exists() && !isAqua) { String msg = NbBundle.getMessage(Controller.class, 669 "FMT_FILE_EXISTS", new Object [] { f.getName() }); String title = NbBundle.getMessage(Controller.class, 671 "TITLE_FILE_EXISTS"); if (JOptionPane.showConfirmDialog(owner.getTopLevelAncestor(), msg, title, 673 JOptionPane.OK_CANCEL_OPTION) != JOptionPane.OK_OPTION) { 674 f = null; 675 } 676 } 677 if (f != null) { 678 lastDir = f.getParent(); 679 } 680 return f; 681 } 682 683 690 public void selectionChanged(OutputWindow win, OutputTab former, 691 OutputTab current) { 692 if (former != null) { 693 former.updateTimestamp(); 694 } 695 if (current != null) { 696 current.updateTimestamp(); 697 updateActions (win, current); 698 } 699 } 700 701 705 public void notifyActivated(OutputWindow win) { 706 OutputTab tab = (OutputTab) win.getSelectedTab(); 707 if (tab != null) { 708 updateActions (win, tab); 709 } 710 } 711 712 private boolean firstF12 = true; 713 721 private void sendCaretToError(OutputWindow win, OutputTab tab, boolean backward) { 722 if (tab == null) { 723 tab = (OutputTab) win.getSelectedTab(); 725 if (tab == null) { 726 return; 727 } 728 } 729 OutWriter out = tab.getIO().out(); 730 if (out != null) { 731 int line = firstF12 ? 0 : Math.max(0, tab.getOutputPane().getCaretLine()); 732 if (line >= tab.getOutputPane().getLineCount()-1) { 733 line = 0; 734 } 735 int newline = out.getLines().nearestListenerLine(line, backward); 738 if (LOG) { 739 log ("sendCaretToError - caret line: " + line + 740 " nearest listener line " + newline); 741 } 742 if (newline == line) { 743 if (!backward && line != tab.getOutputPane().getLineCount()) { 744 newline = out.getLines().nearestListenerLine(line+1, backward); 745 } else if (backward && line > 0) { 746 newline = out.getLines().nearestListenerLine(line-1, backward); 747 } else { 748 return; 749 } 750 } 751 if (newline != -1) { 752 if (LOG) 753 log("Sending caret to error line " + newline); 754 tab.getOutputPane().sendCaretToLine(newline, true); 755 if (!win.isActivated()) { 756 OutputListener l = out.getLines().getListenerForLine(newline); 757 758 ControllerOutputEvent ce = new ControllerOutputEvent (tab.getIO(), newline); 759 l.outputLineAction(ce); 760 } 761 } 762 firstF12 = false; 763 } 764 } 765 766 772 public void notifyRemoved(OutputTab tab) { 773 assert SwingUtilities.isEventDispatchThread(); 774 if (LOG) log ("Tab " + tab + " has been CLOSED. Disposing its IO."); 775 NbIO io = tab.getIO(); 776 if (io != null) { 777 io.setClosed(true); 778 } 779 NbWriter w = io.writer(); 780 if (w != null && w.isClosed()) { 781 tab.setDocument(null); 783 } else if (w != null) { 784 tab.getDocument().disposeQuietly(); 787 } 788 } 789 790 797 public void notifyInput(OutputWindow win, OutputTab tab, String txt) { 798 if (Controller.LOG) Controller.log ("Notify input on " + tab + " - " + txt); 799 NbIO io = tab.getIO(); 800 if (io != null) { 801 NbIO.IOReader in = io.in(); 802 if (in != null) { 803 if (Controller.LOG) Controller.log ("Sending input to " + in); 804 805 in.pushText (txt + "\n"); 806 io.getOut().println(txt); 808 } 809 } 810 } 811 812 819 private OutputListener listenerForLine (OutputTab tab, int line) { 820 OutWriter out = tab.getIO().out(); 821 if (out != null) { 822 return out.getLines().getListenerForLine(line); 823 } 824 return null; 825 } 826 827 833 public void lineClicked(OutputWindow win, OutputTab tab, int line) { 834 OutputListener l = listenerForLine (tab, line); 835 if (l != null) { 836 ControllerOutputEvent oe = new ControllerOutputEvent (tab.getIO(), line); 837 l.outputLineAction(oe); 838 tab.getOutputPane().sendCaretToLine(line, true); 840 } 841 } 842 843 851 public void postPopupMenu(OutputWindow win, OutputTab tab, Point p, Component src) { 852 if (LOG) { 853 log ("post popup menu for " + tab.getName()); 854 } 855 JPopupMenu popup = new JPopupMenu (); 856 popup.putClientProperty ("container", win); popup.putClientProperty ("component", tab); Action [] a = tab.getToolbarActions(); 859 if (a.length > 0) { 860 boolean added = false; 861 for (int i=0; i < a.length; i++) { 862 if (a[i].getValue(Action.NAME) != null) { 863 popup.add (new ProxyAction(a[i])); 865 added = true; 866 } 867 } 868 if (added) { 869 popup.add (new JSeparator ()); 870 } 871 } 872 for (int i=0; i < popupItems.length; i++) { 873 if (popupItems[i] instanceof JSeparator ) { 874 popup.add ((JSeparator ) popupItems[i]); 875 } else { 876 if (popupItems[i] != wrapAction) { 877 popup.add ((Action ) popupItems[i]); 878 } else { 879 JCheckBoxMenuItem item = 880 new JCheckBoxMenuItem ((Action ) popupItems[i]); 881 882 item.setSelected(tab.getOutputPane().isWrapped()); 883 popup.add (item); 884 } 885 } 886 } 887 KeyStroke esc = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); 889 JComponent c = tab.getOutputPane().getTextView(); 890 Object escHandle = c.getInputMap().get(esc); 891 c.getInputMap().remove(esc); 892 tab.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).remove(esc); 893 894 popup.addPopupMenuListener(new PMListener(popupItems, escHandle)); 895 popup.show(src, p.x, p.y); 896 897 } 898 899 private static class ProxyAction implements Action { 900 private Action orig; 901 ProxyAction(Action original) { 902 orig = original; 903 } 904 905 public Object getValue(String key) { 906 if (Action.SMALL_ICON.equals(key)) { 907 return null; 908 } 909 return orig.getValue(key); 910 } 911 912 public void putValue(String key, Object value) { 913 orig.putValue(key, value); 914 } 915 916 public void setEnabled(boolean b) { 917 orig.setEnabled(b); 918 } 919 920 public boolean isEnabled() { 921 return orig.isEnabled(); 922 } 923 924 public void addPropertyChangeListener(PropertyChangeListener listener) { 925 orig.addPropertyChangeListener(listener); 926 } 927 928 public void removePropertyChangeListener(PropertyChangeListener listener) { 929 orig.removePropertyChangeListener(listener); 930 } 931 932 public void actionPerformed(ActionEvent e) { 933 orig.actionPerformed(e); 934 } 935 } 936 937 941 private static class PMListener implements PopupMenuListener { 942 private Object [] popupItems; 943 private Object handle; 944 PMListener (Object [] popupItems, Object escHandle) { 945 this.popupItems = popupItems; 946 handle = escHandle; 947 } 948 949 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { 950 JPopupMenu popup = (JPopupMenu ) e.getSource(); 951 popup.removeAll(); 952 popup.setInvoker(null); 953 AbstractOutputTab tab = (AbstractOutputTab)popup.getClientProperty("component"); 955 KeyStroke esc = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); 956 JComponent c = tab.getOutputPane().getTextView(); 957 c.getInputMap().put(esc, handle); 958 tab.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(esc, handle); 959 960 popup.putClientProperty ("container", null); popup.putClientProperty ("component", null); popup.removePopupMenuListener(this); 964 for (int i=0; i < popupItems.length; i++) { 965 if (popupItems[i] instanceof ControllerAction) { 966 ((ControllerAction) popupItems[i]).clearListeners(); 967 } 968 } 969 } 970 971 public void popupMenuCanceled(PopupMenuEvent e) { 972 popupMenuWillBecomeInvisible(e); 973 } 974 975 public void popupMenuWillBecomeVisible(PopupMenuEvent e) { 976 } 978 } 979 980 987 public void caretEnteredLine(OutputTab tab, int line) { 988 if (!ignoreCaretChanges) { 989 OutputListener l = listenerForLine (tab, line); 990 if (LOG) { 991 log ("Caret entered line " + line + " notifying listener " + l); 992 } 993 if (l != null) { 994 ControllerOutputEvent oe = new ControllerOutputEvent (tab.getIO(), line); 995 l.outputLineSelected(oe); 996 } 997 } else { 998 if (LOG) { 999 log ("Caret entered line " + line + " which has no listener"); 1000 } 1001 } 1002 } 1003 1004 1013 public void documentChanged(OutputWindow win, OutputTab tab) { 1014 if (tab.getIO().isFocusTaken()) { 1015 win.setSelectedTab(tab); 1017 win.requestVisible(); 1018 } 1019 updateName(win, tab); 1020 if (tab == win.getSelectedTab() && win.isActivated()) { 1021 updateActions(win, tab); 1022 } 1023 } 1024 1025 1038 public void performCommand(OutputWindow win, OutputTab tab, NbIO io, int command, 1039 boolean value, Object data) { 1040 1041 if (LOG) { 1042 log ("PERFORMING: " + IOEvent.cmdToString(command) + " value=" + value + " on " + io + " tob " + tab); 1043 } 1044 1045 OutWriter out = io.out(); 1046 1047 switch (command) { 1048 case IOEvent.CMD_CREATE : 1049 createOutputTab(win, io, io.isFocusTaken(), value); 1050 break; 1051 case IOEvent.CMD_INPUT_VISIBLE : 1052 if (value && tab == null) { 1053 tab = createOutputTab(win, io, io.isFocusTaken(), value); 1054 } 1055 if (tab != null) { 1056 tab.setInputVisible(value); 1057 win.setSelectedTab(tab); 1058 } 1059 break; 1060 case IOEvent.CMD_SELECT : 1061 if (tab == null) { 1062 tab = createOutputTab(win, io, io.isFocusTaken(), value); 1063 } 1064 if (!win.isOpened()) { 1065 win.open(); 1066 } 1067 if (!io.isFocusTaken()) { 1069 win.requestVisibleForNewTab(); 1070 } else { 1071 win.requestActiveForNewTab(); 1072 } 1073 if (win.getSelectedTab() != tab) { 1074 if (tab.getParent() == null) { 1075 win.add(tab); 1077 } 1078 win.setSelectedTab(tab); 1079 updateName(win,tab); 1080 } 1081 break; 1082 case IOEvent.CMD_SET_TOOLBAR_ACTIONS : 1083 if (tab == null && data != null) { 1084 tab = createOutputTab(win, io, io.isFocusTaken(), value); 1085 } 1086 Action [] a = (Action []) data; 1087 tab.setToolbarActions(a); 1088 break; 1089 case IOEvent.CMD_CLOSE : 1090 if (tab != null) { 1091 close(win, tab, true); 1092 win.revalidate(); 1093 win.repaint(); 1094 } else { 1095 io.dispose(); 1096 } 1097 break; 1098 case IOEvent.CMD_STREAM_CLOSED : 1099 if (value) { 1100 if (tab == null) { 1101 if (io.out() != null) { 1103 io.out().dispose(); 1104 } 1105 } else { 1106 if (tab.getParent() != null) { 1107 updateName(win, tab); 1108 if (tab.getIO().out() != null && tab.getIO().out().getLines().firstListenerLine() == -1) { 1109 tab.getOutputPane().ensureCaretPosition(); 1110 } 1111 if (tab == win.getSelectedTab()) { 1112 updateActions (win, tab); 1113 } 1114 } else { 1115 win.removeHiddenView(tab); 1117 if (io.out() != null) { 1118 io.out().dispose(); 1119 } 1120 } 1121 } 1122 } else { 1123 if (tab != null && tab.getParent() != null) { 1124 updateName(win, tab); 1125 } 1126 } 1127 break; 1128 case IOEvent.CMD_RESET : 1129 firstF12 = true; 1130 if (tab == null) { 1131 if (LOG) log ("Got a reset on an io with no tab. Creating a tab."); 1132 performCommand (win, null, io, IOEvent.CMD_CREATE, value, data); 1133 win.requestVisible(); 1134 return; 1135 } 1136 if (LOG) log ("Setting io " + io + " on tab " + tab); 1137 tab.setIO(io); 1139 win.setSelectedTab(tab); 1140 updateName(win, tab); 1141 if (LOG) log ("Reset on " + tab + " tab displayable " + tab.isDisplayable() + " io " + io + " io.out " + io.out()); 1143 break; 1144 case IOEvent.CMD_ICON : 1145 win.setTabIcon(tab, io.getIcon()); 1146 break; 1147 } 1148 } 1149 1150 1156 private void navigateToFirstErrorLine (OutputTab comp) { 1157 OutWriter out = comp.getIO().out(); 1158 if (out != null) { 1159 int line = comp.getFirstNavigableListenerLine(); 1160 if (Controller.LOG) Controller.log ("NAV TO FIRST LISTENER LINE: " + line); 1161 if (line > 0) { 1162 comp.getOutputPane().sendCaretToLine (line, false); 1163 if (isSDI(comp)) { 1164 comp.requestActive(); 1165 } 1166 } 1167 } 1168 } 1169 1170 1171 private static boolean isSDI (OutputTab comp) { 1172 Container c = comp.getTopLevelAncestor(); 1173 return (c != WindowManager.getDefault().getMainWindow()); 1174 } 1175 1176 1181 boolean ignoreCaretChanges = false; 1182 1183 public void hasSelectionChanged(OutputWindow outputWindow, OutputTab tab, boolean val) { 1184 if (tab == outputWindow.getSelectedTab()) { 1185 copyAction.setEnabled(val); 1186 selectAllAction.setEnabled(!tab.getOutputPane().isAllSelected()); 1187 } 1188 } 1189 1190 public void hasOutputListenersChanged(OutputWindow win, OutputTab tab, boolean hasOutputListeners) { 1191 if (hasOutputListeners && win.getSelectedTab() == tab && tab.isShowing()) { 1192 navigateToFirstErrorLine(tab); 1193 } 1194 } 1195 1196 1200 private static class ControllerAction extends AbstractAction { 1201 private int id; 1202 1213 ControllerAction (int id, String bundleKey) { 1214 if (bundleKey != null) { 1215 String name = NbBundle.getMessage(Controller.class, bundleKey); 1216 KeyStroke accelerator = getAcceleratorFor(bundleKey); 1217 this.id = id; 1218 putValue (NAME, name); 1219 putValue (ACCELERATOR_KEY, accelerator); 1220 } 1221 } 1222 1223 1231 ControllerAction (int id, String name, KeyStroke stroke) { 1232 this.id = id; 1233 putValue (NAME, name); 1234 putValue (ACCELERATOR_KEY, stroke); 1235 } 1236 1237 void clearListeners() { 1238 PropertyChangeListener [] l = changeSupport.getPropertyChangeListeners(); 1239 for (int i=0; i < l.length; i++) { 1240 removePropertyChangeListener (l[i]); 1241 } 1242 } 1243 1244 1251 private static KeyStroke getAcceleratorFor (String name) { 1252 String key = name + ".accel"; if (Utilities.isMac()) { 1254 key += ".mac"; } 1256 return Utilities.stringToKey(NbBundle.getMessage(Controller.class, key)); 1257 } 1258 1259 public int getID() { 1260 return id; 1261 } 1262 1263 public void actionPerformed(ActionEvent e) { 1264 if (LOG) log ("ACTION PERFORMED: " + getValue(NAME)); 1265 Component c = (Component ) e.getSource(); 1266 1267 OutputTab outComp = c instanceof OutputTab ? (OutputTab) c : 1268 c instanceof OutputWindow ? null : 1269 (OutputTab) SwingUtilities.getAncestorOfClass(OutputTab.class, c); 1270 1271 OutputWindow win= c instanceof OutputWindow ? (OutputWindow) c : 1272 (OutputWindow) SwingUtilities.getAncestorOfClass(OutputWindow.class, outComp); 1273 1274 if (win == null) { 1275 win = OutputWindow.findDefault(); 1276 } 1277 if (outComp == null && win != null) { 1278 outComp = (OutputTab) win.getSelectedTab(); 1279 } 1280 1281 if (win == null && outComp == null) { 1282 JPopupMenu jpm = (JPopupMenu ) SwingUtilities.getAncestorOfClass (JPopupMenu .class, c); 1285 if (jpm != null) { 1286 win = (OutputWindow) jpm.getClientProperty ("win"); outComp = (OutputTab) jpm.getClientProperty ("component"); } 1289 } 1290 Controller cont = win.getController(); 1291 if (cont != null) { 1292 cont.actionPerformed (win, outComp, getID()); 1293 } 1294 } 1295 } 1296 1297 1301 static class ControllerOutputEvent extends OutputEvent { 1302 private int line; 1303 ControllerOutputEvent (NbIO io, int line) { 1304 super (io); 1305 this.line = line; 1306 } 1307 1308 void setLine (int line) { 1309 this.line = line; 1310 } 1311 1312 public String getLine() { 1313 NbIO io = (NbIO) getSource(); 1314 OutWriter out = io.out(); 1315 try { 1316 if (out != null) { 1317 String s = out.getLines().getLine(line); 1318 if (s.endsWith("\n")) { s = s.substring(0, s.length()-1); 1321 } 1322 if (s.endsWith("\r")) { s = s.substring(0, s.length()-1); 1325 } 1326 return s; 1327 } 1328 } catch (IOException ioe) { 1329 IOException nue = new IOException ("Could not fetch line " + line + " on " + io.getName()); nue.initCause(ioe); 1331 Exceptions.printStackTrace(ioe); 1332 } 1333 return null; 1334 } 1335 } 1336 1337 public static final boolean LOG = Boolean.getBoolean("nb.output.log") || Boolean.getBoolean("nb.output.log.verbose"); public static final boolean VERBOSE = Boolean.getBoolean("nb.output.log.verbose"); 1339 static final boolean logStdOut = Boolean.getBoolean("nb.output.log.stdout"); public static void log (String s) { 1341 s = Long.toString(System.currentTimeMillis()) + ":" + s + "(" + Thread.currentThread() + ") "; 1342 if (logStdOut) { 1343 System.out.println(s); 1344 return; 1345 } 1346 OutputStream os = getLogStream(); 1347 byte b[] = new byte[s.length() + 1]; 1348 char[] c = s.toCharArray(); 1349 for (int i=0; i < c.length; i++) { 1350 b[i] = (byte) c[i]; 1351 } 1352 b[b.length-1] = (byte) '\n'; 1353 try { 1354 os.write(b); 1355 } catch (Exception e) { 1356 e.printStackTrace(); 1357 System.err.println(s); 1358 } 1359 try { 1360 os.flush(); 1361 } catch (Exception e ) {} 1362 } 1363 1364 public static void logStack() { 1365 if (logStdOut) { 1366 new Exception ().printStackTrace(); 1367 return; 1368 } 1369 Exception e = new Exception (); 1370 e.fillInStackTrace(); 1371 StackTraceElement [] ste = e.getStackTrace(); 1372 1373 for (int i=1; i < Math.min (22, ste.length); i++) { 1374 log (" * " + ste[i]); 1375 } 1376 } 1377 1378 private static OutputStream logStream = null; 1379 private static OutputStream getLogStream() { 1380 if (logStream == null) { 1381 String spec = System.getProperty ("java.io.tmpdir") + File.separator + "outlog.txt"; 1382 synchronized (Controller.class) { 1383 try { 1384 File f = new File (spec); 1385 if (f.exists()) { 1386 f.delete(); 1387 } 1388 f.createNewFile(); 1389 logStream = new FileOutputStream (f); 1390 } catch (Exception e) { 1391 e.printStackTrace(); 1392 logStream = System.err; 1393 } 1394 } 1395 } 1396 return logStream; 1397 } 1398 1399 public void inputEof(OutputTab tab) { 1400 if (Controller.LOG) Controller.log ("Input EOF"); 1401 NbIO io = tab.getIO(); 1402 NbIO.IOReader in = io.in(); 1403 if (in != null) { 1404 in.eof(); 1405 } 1406 } 1407} 1408 1409 | Popular Tags |