Package bsh.util

Source Code of bsh.util.JConsole

/*****************************************************************************
*                                                                           *
*  This file is part of the BeanShell Java Scripting distribution.          *
*  Documentation and updates may be found at http://www.beanshell.org/      *
*                                                                           *
*  Sun Public License Notice:                                               *
*                                                                           *
*  The contents of this file are subject to the Sun Public License Version  *
*  1.0 (the "License"); you may not use this file except in compliance with *
*  the License. A copy of the License is available at http://www.sun.com    *
*                                                                           *
*  The Original Code is BeanShell. The Initial Developer of the Original    *
*  Code is Pat Niemeyer. Portions created by Pat Niemeyer are Copyright     *
*  (C) 2000.  All Rights Reserved.                                          *
*                                                                           *
*  GNU Public License Notice:                                               *
*                                                                           *
*  Alternatively, the contents of this file may be used under the terms of  *
*  the GNU Lesser General Public License (the "LGPL"), in which case the    *
*  provisions of LGPL are applicable instead of those above. If you wish to *
*  allow use of your version of this file only under the  terms of the LGPL *
*  and not to allow others to use your version of this file under the SPL,  *
*  indicate your decision by deleting the provisions above and replace      *
*  them with the notice and other provisions required by the LGPL.  If you  *
*  do not delete the provisions above, a recipient may use your version of  *
*  this file under either the SPL or the LGPL.                              *
*                                                                           *
*  Patrick Niemeyer (pat@pat.net)                                           *
*  Author of Learning Java, O'Reilly & Associates                           *
*  http://www.pat.net/~pat/                                                 *
*                                                                           *
*****************************************************************************/

package bsh.util;

import java.awt.Component;
import java.awt.Font;
import java.awt.Color;
import java.awt.Insets;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.*;
import java.util.Vector;
import java.awt.Cursor;
import javax.swing.text.*;
import javax.swing.*;

// ksuzuki 2010/10/06 >>>
import java.awt.FontMetrics;
import java.awt.Point;
import java.awt.Rectangle;
// ksuzuki 2010/10/06 <<<

// ksuzuki 2010/12/14 >>>
import java.awt.EventQueue;
import javax.swing.event.*;
// ksuzuki 2010/12/14 <<<

// Things that are not in the core packages

import bsh.util.NameCompletion;

/**
    A JFC/Swing based console for the BeanShell desktop.
    This is a descendant of the old AWTConsole.

    Improvements by: Mark Donszelmann <Mark.Donszelmann@cern.ch>
        including Cut & Paste

    Improvements by: Daniel Leuck
        including Color and Image support, key press bug workaround
*/
public class JConsole extends JScrollPane
    implements GUIConsoleInterface, Runnable, KeyListener,
    MouseListener, ActionListener, PropertyChangeListener,
    MouseMotionListener // ksuzuki 2010/10/06
{
    private final static String CUT = "Cut";
    private final static String COPY = "Copy";
    private final static String PASTE = "Paste";

    // ksuzuki 2010/09/28 add 'transient'
    private transient OutputStream outPipe;
    private transient InputStream inPipe;
    private transient InputStream in;
    private transient PrintStream out;

    public InputStream getInputStream() { return in; }
    public Reader getIn() { return new InputStreamReader(in); }
    public PrintStream getOut() { return out;   }
    public PrintStream getErr() { return out;   }

    private int cmdStart = 0;
    private Vector <String>history = new Vector<String>();
    private String startedLine;
    private int histLine = 0;

    private JPopupMenu menu;
    private JTextPane text;
    private DefaultStyledDocument doc;

    NameCompletion nameCompletion;
    final int SHOW_AMBIG_MAX = 10;

    // hack to prevent key repeat for some reason?
    private boolean gotUp = true;


    // ksuzuki 2010/10/24, 2011/01/28 >>>
    private boolean closingIO = false;
    private Color promptColor = Color.black;
    public Color getPromptColor() { return promptColor; }
    public void setPromptColor(Color c) { promptColor = c; }
    private String promptString = "";
    public String getPromptString() { return promptString; }
    public void setPromptString(String ps) { promptString = ps; }
    private int promptCharacter = 0x16;
    public int getPromptCharacter() { return promptCharacter; }
    public void setPromptCharacter(int pc) { promptCharacter = pc; }
    // ksuzuki 2010/10/24, 2011/01/28 <<<

    // ksuzuki 2010/12/14 >>>
    private int promptStart = 0;
    private String pppInfoKey = null;
    public JTextPane getTextPane() { return text; }
    public DefaultStyledDocument getDocument() { return doc; }
    public int getPromptStartPosition() { return promptStart; }
    public void setPPPInfoKey(String key) { pppInfoKey = key; }
    // ksuzuki 2010/12/14 <<<

    public JConsole() {
        this(null, null);
    }

    public JConsole( InputStream cin, OutputStream cout
    {
        super();

        // Special TextPane which catches for cut and paste, both L&F keys and
        // programmatic behaviour
        text = new JTextPane( doc=new DefaultStyledDocument() )
            {
                public void cut() {
                    if (text.getCaretPosition() < cmdStart) {
                        super.copy();
                    } else {
                        super.cut();
                    }
                }

                public void paste() {
                    forceCaretMoveToEnd();
                    super.paste();
                }
            };

        Font font = new Font("Monospaced",Font.PLAIN,14);
        text.setText("");
        text.setFont( font );
        text.setMargin( new Insets(7,5,7,5) );
        text.addKeyListener(this);
        setViewportView(text);

        // create popup menu
        menu = new JPopupMenu("JConsole Menu");
        menu.add(new JMenuItem(CUT)).addActionListener(this);
        menu.add(new JMenuItem(COPY)).addActionListener(this);
        menu.add(new JMenuItem(PASTE)).addActionListener(this);

        text.addMouseListener(this);
        text.setCaretColor(promptColor); // ksuzuki 2010/08/29
        text.addMouseMotionListener(this); // ksuzuki 2010/10/06
        assignTextInputToAction(); // ksuzuki 2010/12/02

        // make sure popup menu follows Look & Feel
        UIManager.addPropertyChangeListener(this);

        outPipe = cout;
        if ( outPipe == null ) {
            outPipe = new PipedOutputStream();
            try {
                in = new PipedInputStream((PipedOutputStream)outPipe);
            } catch ( IOException e ) {
                print("Console internal error (1)...", Color.red);
            }
        }

        inPipe = cin;
        if ( inPipe == null ) {
            PipedOutputStream pout = new PipedOutputStream();
            out = new PrintStream( pout );
            try {
                inPipe = new BlockingPipedInputStream(pout);
            } catch ( IOException e ) { print("Console internal error: "+e); }
        }
        // Start the inpipe watcher
        new Thread( this ).start();

        requestFocus();
    }

    public void requestFocus()
    {
        super.requestFocus();
        text.requestFocus();
    }

    public void keyPressed( KeyEvent e ) {
        type( e );
        gotUp=false;
    }

    public void keyTyped(KeyEvent e) {
        type( e );
    }

    public void keyReleased(KeyEvent e) {
        gotUp=true;
        type( e );
    }

    private synchronized void type( KeyEvent e ) {
        switch ( e.getKeyCode() )
        {
            case ( KeyEvent.VK_ENTER ):
                if (e.getID() == KeyEvent.KEY_PRESSED) {
                    if (gotUp) {
                        enter();
                        resetCommandStart();
                        text.setCaretPosition(cmdStart);
                    }
                }
                e.consume();
                text.repaint();
                break;

            case ( KeyEvent.VK_UP ):
                // ksuzuki 2010/12/02
                // Do historyUp only when the caret is on the command prompt
                // line and META key is not pressed.
                if (e.getID() == KeyEvent.KEY_PRESSED) {
                    if ( (getCommandLineStartOffset() <= text.getCaretPosition())
                          && ((e.getModifiers() & InputEvent.META_MASK) == 0) ) {
                        historyUp();
                        e.consume();
                    }
                }
                break;

            case ( KeyEvent.VK_DOWN ):
                // ksuzuki 2010/12/02: Do historyUp only when the caret is on
                // the command prompt line.
                if (e.getID() == KeyEvent.KEY_PRESSED) {
                    if ( getCommandLineStartOffset() <= text.getCaretPosition() ) {
                        historyDown();
                        e.consume();
                    }
                }
                break;

            // ksuzuki 2010/12/02 case ( KeyEvent.VK_LEFT ):
            case ( KeyEvent.VK_BACK_SPACE ):
            case ( KeyEvent.VK_DELETE ):
                if (text.getCaretPosition() <= cmdStart) {
                    // This doesn't work for backspace.
                    // See default case for workaround
                    e.consume();
                }
                break;

            case ( KeyEvent.VK_LEFT ): // ksuzuki 2010/12/02
            case ( KeyEvent.VK_RIGHT ):
                forceCaretMoveToStart();
                break;

            // ksuzuki 2010/12/02 >>>
            case ( KeyEvent.VK_HOME ):
                //text.setCaretPosition(cmdStart);
                //e.consume();
                scrollToHome(e);
                break;

            case ( KeyEvent.VK_SEMICOLON ):
                if ( (e.getModifiers() & InputEvent.CTRL_MASK) > 0 ) {
                    scrollToHome(e);
                }
                break;

            case ( KeyEvent.VK_A ):
                // Do the same as VK_HOME only when the caret is on the
                // command prompt line.
                if ( (e.getModifiers() & InputEvent.CTRL_MASK) > 0 ) {
                    if ( getCommandLineStartOffset() <= text.getCaretPosition() ) {
                        scrollToHome(e);
                    }
                }
                break;
            // ksuzuki 2010/12/14 <<<

            // ksuzuki 2010/12/14 >>>
            case ( KeyEvent.VK_CLOSE_BRACKET ):
                if ( ((e.getModifiers() & InputEvent.META_MASK) > 0) && pppInfoKey != null ) {
                    Position[] ppp = (Position[])text.getClientProperty(pppInfoKey);
                    if ( ppp != null ) {
                        int pp1 = ppp[0].getOffset();
                        int pp2 = ppp[1].getOffset();
                        int len = text.getDocument().getLength();
                        if ( (pp1 < len) && (pp2 < len) ) {
                            int cpos = text.getCaretPosition();
                            if ( cpos == pp1 ) {
                                setCaretLater(pp2 + 1);
                                e.consume();
                            } else if ( cpos == (pp2 + 1) ) {
                                setCaretLater(pp1);
                                e.consume();
                            }
                        }
                    }
                }
                break;
            // ksuzuki 2010/12/14 <<<

            case ( KeyEvent.VK_U ): // clear line
                if ( (e.getModifiers() & InputEvent.CTRL_MASK) > 0 ) {
                    replaceRange( "", cmdStart, textLength());
                    histLine = 0;
                    e.consume();
                }
                break;

            case ( KeyEvent.VK_ALT ):
            case ( KeyEvent.VK_CAPS_LOCK ):
            case ( KeyEvent.VK_CONTROL ):
            case ( KeyEvent.VK_META ):
            case ( KeyEvent.VK_SHIFT ):
            case ( KeyEvent.VK_PRINTSCREEN ):
            case ( KeyEvent.VK_SCROLL_LOCK ):
            case ( KeyEvent.VK_PAUSE ):
            case ( KeyEvent.VK_INSERT ):
            case ( KeyEvent.VK_F1):
            case ( KeyEvent.VK_F2):
            case ( KeyEvent.VK_F3):
            case ( KeyEvent.VK_F4):
            case ( KeyEvent.VK_F5):
            case ( KeyEvent.VK_F6):
            case ( KeyEvent.VK_F7):
            case ( KeyEvent.VK_F8):
            case ( KeyEvent.VK_F9):
            case ( KeyEvent.VK_F10):
            case ( KeyEvent.VK_F11):
            case ( KeyEvent.VK_F12):
            case ( KeyEvent.VK_ESCAPE ):

            // only modifier pressed
            break;

            // Control-C
/* ksuzuki 2011/02/15 >>>
// Let ancestor handle CTRL+C.
            case ( KeyEvent.VK_C ):
                if (text.getSelectedText() == null) {
                    if (( (e.getModifiers() & InputEvent.CTRL_MASK) > 0 )
                    && (e.getID() == KeyEvent.KEY_PRESSED)) {
                        append("^C");
                    }
                    e.consume();
                }
                break;
<<< ksuzuki 2011/02/15 */

            case ( KeyEvent.VK_TAB ):
                if (e.getID() == KeyEvent.KEY_RELEASED) {
                    String part = text.getText().substring( cmdStart );
                    doCommandCompletion( part );
                }
                e.consume();
                break;

            default:
                if (
                    (e.getModifiers() &
                    (InputEvent.CTRL_MASK
                    | InputEvent.ALT_MASK | InputEvent.META_MASK)) == 0 )
                {
                    // plain character
                    forceCaretMoveToEnd();
                }

                /*
                    The getKeyCode function always returns VK_UNDEFINED for
                    keyTyped events, so backspace is not fully consumed.
                */
                if (e.paramString().indexOf("Backspace") != -1)
                {
                  if (text.getCaretPosition() <= cmdStart) {
                        e.consume();
                        break;
                    }
                }

                break;
        }
    }

    private void doCommandCompletion( String part ) {
        if ( nameCompletion == null )
            return;

        int i=part.length()-1;

        // Character.isJavaIdentifierPart()  How convenient for us!!
        while (
            i >= 0 &&
                ( Character.isJavaIdentifierPart(part.charAt(i))
                || part.charAt(i) == '.' )
        )
            i--;

        part = part.substring(i+1);

        if ( part.length() < 2 // reasonable completion length
            return;

        //System.out.println("completing part: "+part);

        // no completion
        String [] complete = nameCompletion.completeName(part);
        if ( complete.length == 0 ) {
            java.awt.Toolkit.getDefaultToolkit().beep();
            return;
        }

        // Found one completion (possibly what we already have)
        if ( complete.length == 1 && !complete.equals(part) ) {
            String append = complete[0].substring(part.length());
            append( append );
            return;
        }

        // Found ambiguous, show (some of) them

        String line = text.getText();
        String command = line.substring( cmdStart );
        // Find prompt
        for(i=cmdStart; line.charAt(i) != '\n' && i > 0; i--);
        String prompt = line.substring( i+1, cmdStart );

        // Show ambiguous
        StringBuffer sb = new StringBuffer("\n");
        for( i=0; i<complete.length && i<SHOW_AMBIG_MAX; i++)
            sb.append( complete[i] +"\n" );
        if ( i == SHOW_AMBIG_MAX )
            sb.append("...\n");

        print( sb, Color.gray );
        print( prompt ); // print resets command start
        append( command ); // append does not reset command start
    }

    private void resetCommandStart() {
        cmdStart = textLength();
    }

    private void append(String string) {
        int slen = textLength();
        text.select(slen, slen);
        text.replaceSelection(string);
    }

    private String replaceRange(Object s, int start, int end) {
        String st = s.toString();

        // ksuzuki 2010/12/14 >>>
        //text.select(start, end);
        //text.replaceSelection(st);
        MutableAttributeSet attr = new SimpleAttributeSet();
        StyleConstants.setForeground(attr, text.getForeground());
        StyleConstants.setBackground(attr, text.getBackground());

        CaretListener[] cls = disableCaretListeners(); {
            text.select(start, end);
            text.replaceSelection(st);
            text.setCharacterAttributes(attr, false);
        } enableCaretListeners(cls);

        // ksuzuki 2010/12/14 <<<

        //text.repaint();
        return st;
    }

    private void forceCaretMoveToEnd() {
        if (text.getCaretPosition() < cmdStart) {
            // move caret first!
            text.setCaretPosition(textLength());
        }
        text.repaint();
    }

    private void forceCaretMoveToStart() {
        if (text.getCaretPosition() < cmdStart) {
            // move caret first!
        }
        text.repaint();
    }


    private void enter() {
        String s = getCmd();

        // ksuzuki 2010/12/14 >>>
        StringWriter sw = new StringWriter();
        for (int i = 0; i < s.length(); i++) {
            int c = s.codePointAt(i);
            if ((Character.isWhitespace(c) == true) || (Character.isValidCodePoint(c) == false)) {
                sw.append(' ');
            } else {
                sw.append(s.charAt(i));
            }
        }
        s = sw.toString();
        // ksuzuki 2010/12/14 <<<

        if ( s.length() == 0 // special hack for empty return!
            s = ";\n";
        else {
            history.addElement( s );
            s = s +"\n";
        }

        append("\n");
        histLine = 0;
        acceptLine( s );
        text.repaint();
    }

    private String getCmd() {
        String s = "";
        try {
            s = text.getText(cmdStart, textLength() - cmdStart);
        } catch (BadLocationException e) {
            // should not happen
            System.out.println("Internal JConsole Error: "+e);
        }
        return s;
    }

    private void historyUp() {
        if ( history.size() == 0 )
            return;
        if ( histLine == 0 // save current line
            startedLine = getCmd();
        if ( histLine < history.size() ) {
            histLine++;
            showHistoryLine();
        }
    }
   
    private void historyDown() {
        if ( histLine == 0 )
            return;

        histLine--;
        showHistoryLine();
    }

    private void showHistoryLine() {
        String showline;
        if ( histLine == 0 )
            showline = startedLine;
        else
            showline = (String)history.elementAt( history.size() - histLine );

        replaceRange( showline, cmdStart, textLength() );
        text.setCaretPosition(textLength());
        text.repaint();
    }

    String ZEROS = "000";

    private void acceptLine( String line )
    {
/* ksuzuki 2010/12/31 >>>
* This patch is disabled in order to preserve the same character literal
* expression (a char is preceeded with a backslash) for all the Unicode
* character on the command line. With this patch 'a' should be expressed
* as '\a' but a char of which codepoint is greater than 127 does NOT
* require the preceeding backslash, which makes them look inconsistent.

        // Patch to handle Unicode characters
        // Submitted by Daniel Leuck
        StringBuffer buf = new StringBuffer();
        int lineLength = line.length();
        for(int i=0; i<lineLength; i++) {
                char c = line.charAt(i);
                if(c>127) {
                    String val = Integer.toString(c, 16);
                    val=ZEROS.substring(0,4-val.length()) + val;
                    buf.append("\\u" + val);
                } else {
                    buf.append(c);
                }
        }
        line = buf.toString();
        // End unicode patch

ksuzuki 2010/12/31 <<< */

        if (outPipe == null )
            print("Console internal error: cannot output ...", Color.red);
        else
            try {
                outPipe.write( line.getBytes() );
                outPipe.flush();
            } catch ( IOException e ) {
                outPipe = null;
                throw new RuntimeException("Console pipe broken...");
            }
        //text.repaint();
    }

    public void println(Object o) {
        print( String.valueOf(o) + "\n" );
        text.repaint();
    }

    public void print(final Object o) {
        invokeAndWait(new Runnable() {
                public void run() {
                    append(String.valueOf(o));
                    resetCommandStart();
                    text.setCaretPosition(cmdStart);
                }
            });
    }

    /**
      * Prints "\\n" (i.e. newline)
      */
    public void println() {
        print("\n");
        text.repaint();
    }

    public void error( Object o ) {
        print( o, Color.red );
    }

    public void println(Icon icon) {
        print(icon);
        println();
        text.repaint();
    }

    public void print(final Icon icon) {
        if (icon==null)
            return;

        invokeAndWait(new Runnable() {
            public void run() {
                text.insertIcon(icon);
                resetCommandStart();
                text.setCaretPosition(cmdStart);
            }
        });        
    }

    public void print(Object s, Font font) {
        print(s, font, null);
    }

    public void print(Object s, Color color) {
        print(s, null, color);
    }

    public void print(final Object o, final Font font, final Color color) {
        invokeAndWait(new Runnable() {
            public void run() {
                AttributeSet old = getStyle();
                setStyle(font, color);
                append(String.valueOf(o));
                resetCommandStart();
                text.setCaretPosition(cmdStart);
                setStyle(old, true);
            }
        });
    }

    public void print(
        Object s,
        String fontFamilyName,
        int size,
        Color color
        ) {
           
        print(s,fontFamilyName,size,color,false,false,false);
    }

    public void print(
        final Object o,
        final String fontFamilyName,
        final int   size,
        final Color color,
        final boolean bold,
        final  boolean italic,
        final boolean underline
        )
    {
        invokeAndWait(new Runnable() {
            public void run() {
                AttributeSet old = getStyle();
                setStyle(fontFamilyName, size, color, bold, italic, underline);
                append(String.valueOf(o));
                resetCommandStart();
                text.setCaretPosition(cmdStart);
                setStyle(old, true);
            }
        });        
    }

    private AttributeSet setStyle(Font font) {
        return setStyle(font, null);
    }

    private AttributeSet setStyle(Color color) {
        return setStyle(null, color);
    }

    private AttributeSet setStyle( Font font, Color color)
    {
        if (font!=null)
            return setStyle( font.getFamily(), font.getSize(), color,
                font.isBold(), font.isItalic(),
                StyleConstants.isUnderline(getStyle()) );
        else
            return setStyle(null,-1,color);
    }

    private AttributeSet setStyle (
        String fontFamilyName, int  size, Color color)
    {
        MutableAttributeSet attr = new SimpleAttributeSet();
        if (color!=null)
            StyleConstants.setForeground(attr, color);
        if (fontFamilyName!=null)
            StyleConstants.setFontFamily(attr, fontFamilyName);
        if (size!=-1)
            StyleConstants.setFontSize(attr, size);

        setStyle(attr);

        return getStyle();
    }

    private AttributeSet setStyle(
        String fontFamilyName,
        int size,
        Color color,
        boolean bold,
        boolean italic,
        boolean underline
        )
    {
        MutableAttributeSet attr = new SimpleAttributeSet();
        if (color!=null)
            StyleConstants.setForeground(attr, color);
        if (fontFamilyName!=null)
            StyleConstants.setFontFamily(attr, fontFamilyName);
        if (size!=-1)
            StyleConstants.setFontSize(attr, size);
        StyleConstants.setBold(attr, bold);
        StyleConstants.setItalic(attr, italic);
        StyleConstants.setUnderline(attr, underline);

        setStyle(attr);

        return getStyle();
    }

    private void setStyle(AttributeSet attributes) {
        setStyle(attributes, false);
    }

    private void setStyle(AttributeSet attributes, boolean overWrite) {
        text.setCharacterAttributes(attributes, overWrite);
    }

    private AttributeSet getStyle() {
        return text.getCharacterAttributes();
    }

    public void setFont( Font font ) {
        super.setFont( font );

        if ( text != null )
            text.setFont( font );
    }

    // ksuzuki 2010/12/14 >>>
    private CaretListener[] disableCaretListeners() {
        CaretListener[] cls = text.getCaretListeners();
        for (int i = 0; i < cls.length; i++) {
            text.removeCaretListener(cls[i]);
        }
        return cls;
    }

    private void enableCaretListeners(CaretListener[] cls) {
        for (int i = 0; i < cls.length; i++) {
            text.addCaretListener(cls[i]);
        }
    }
    // ksuzuki 2010/12/14 <<<

    // ksuzuki 2010/12/26 >>>
    private void resetPromptStart() {
        promptStart = textLength();
    }
    // ksuzuki 2010/12/26 <<<

    private void inPipeWatcher() throws IOException {
        byte [] ba = new byte [1024]; // arbitrary blocking factor
        int read;
        // ksuzuki 2010/10/24, 2011/01/28 >>>
        while ( ((read = inPipe.read(ba)) != -1) && (closingIO == false) ) {
            CaretListener[] cls = disableCaretListeners(); { // ksuzuki 2010/12/14
                // print( new String(ba, 0, read) );
                String s = new String(ba, 0, read);
                int i = s.lastIndexOf(promptCharacter);
                if (0 <= i) {
                    print(s.substring(0, i));
                    print(promptString, promptColor);
                    print(" ", text.getForeground());
                    resetPromptStart(); // 2010/12/26
                    if (i + 1 < s.length()) {
                        print(s.substring(i + 1));
                    }
                } else {
                    print(s);
                }
            } enableCaretListeners(cls); // ksuzuki 2010/12/14
            //text.repaint();
        }
        // ksuzuki 2010/10/24, 2011/01/28 <<<
        // ksuzuki 2010/10/12: print("Console: Input closed...");
    }

    public void run() {
        try {
            inPipeWatcher();
        } catch ( IOException e ) {
            print("Console: I/O Error: "+e+"\n", Color.red);
        }
    }

    public String toString() {
        return "BeanShell console";
    }

    // MouseListener Interface
    public void mouseClicked(MouseEvent event) {
    }

    public void mousePressed(MouseEvent event) {
        if (event.isPopupTrigger()) {
            menu.show(
                (Component)event.getSource(), event.getX(), event.getY());
        }
    }

    public void mouseReleased(MouseEvent event) {
        if (event.isPopupTrigger()) {
            menu.show((Component)event.getSource(), event.getX(),
            event.getY());
        }
        text.repaint();
    }

    public void mouseEntered(MouseEvent event) { }

    public void mouseExited(MouseEvent event) { }

    // property change
    public void propertyChange(PropertyChangeEvent event) {
        if (event.getPropertyName().equals("lookAndFeel")) {
            SwingUtilities.updateComponentTreeUI(menu);
        }
    }

    // handle cut, copy and paste
    public void actionPerformed(ActionEvent event) {
        String cmd = event.getActionCommand();
        if (cmd.equals(CUT)) {
            text.cut();
        } else if (cmd.equals(COPY)) {
            text.copy();
        } else if (cmd.equals(PASTE)) {
            text.paste();
        }
    }

    /**
     * If not in the event thread run via SwingUtilities.invokeAndWait()
     */
    private void invokeAndWait(Runnable run) {
        if(!SwingUtilities.isEventDispatchThread()) {
            try {
                SwingUtilities.invokeAndWait(run);
            } catch(Exception e) {
                // shouldn't happen
                e.printStackTrace();
            }
        } else {
            run.run();
        }
    }

    /**
        The overridden read method in this class will not throw "Broken pipe"
        IOExceptions;  It will simply wait for new writers and data.
        This is used by the JConsole internal read thread to allow writers
        in different (and in particular ephemeral) threads to write to the pipe.

        It also checks a little more frequently than the original read().

        Warning: read() will not even error on a read to an explicitly closed
        pipe (override closed to for that).
    */
    public static class BlockingPipedInputStream extends PipedInputStream
    {
        boolean closed;
        public BlockingPipedInputStream( PipedOutputStream pout )
            throws IOException
        {
            super(pout);
        }
        public synchronized int read() throws IOException {
            if ( closed )
                throw new IOException("stream closed");

            while (super.in < 0) {  // While no data */
                notifyAll();    // Notify any writers to wake up
                try {
                    wait(750);
                } catch ( InterruptedException e ) {
                    throw new InterruptedIOException();
                }
            }
            // This is what the superclass does.
            int ret = buffer[super.out++] & 0xFF;
            if (super.out >= buffer.length)
                super.out = 0;
            if (super.in == super.out)
                super.in = -1/* now empty */
            return ret;
        }
        public void close() throws IOException {
            closed = true;
            super.close();
        }
    }

  public void setNameCompletion( NameCompletion nc ) {
    this.nameCompletion = nc;
  }

    public void setWaitFeedback( boolean on ) {
        if ( on )
            setCursor( Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR) );
        else
            setCursor( Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR) );
    }

    private int textLength() { return text.getDocument().getLength(); }

    // ksuzuki 2010/10/06, 2011/01/06 >>>
    // Use the TEXT cursor only when the mouse pointer is on text.
    public void mouseMoved(MouseEvent event) {
        JTextPane text = (JTextPane)event.getComponent();
        text.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));

        Point point = event.getPoint();
        int pos = text.viewToModel(point);
        if (0 <= pos) {
            try {
                StyledDocument doc = text.getStyledDocument();
                Element elm = doc.getCharacterElement(pos);
                if (elm != null) {
                    int soff = Math.max(elm.getStartOffset(), pos - 1);
                    int eoff = Math.min(pos + 1, elm.getEndOffset());
                    int size = eoff - soff;
                    String str = doc.getText(soff, size);
                    FontMetrics fm = text.getFontMetrics(text.getFont());
                    int h = fm.getHeight();
                    for (int i = 0; i < size; i++) {
                        Rectangle r = text.modelToView(soff + i);
                        r.width = fm.charWidth(str.charAt(i));
                        r.height = h;
                        if (r.contains(point)) {
                            text.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
                            break;
                        }
                    }
                }
            } catch (BadLocationException ble) {}
        }
    }
    public void mouseDragged(MouseEvent event) {}
    // ksuzuki 2010/10/06 <<<

    // ksuzuki 2010/10/12 >>>
    public void closeIO() {
        try {
            closingIO = true;
            if (out != null) {
                out.println( "closing IO..." );
                out.close();
                out = null;
            }
            if (outPipe != null) {
                outPipe.flush();
                outPipe.close();
                outPipe = null;
            }
        } catch (IOException e) {}
    }
    // ksuzuki 2010/10/12 <<<

    // ksuzuki 2011/02/15 >>>
    public void resetIO() {
        outPipe = new PipedOutputStream();
        try {
            in = new PipedInputStream((PipedOutputStream)outPipe);
        } catch ( IOException e ) {}

        PipedOutputStream pout = new PipedOutputStream();
        out = new PrintStream( pout );
        try {
            inPipe = new BlockingPipedInputStream(pout);
        } catch ( IOException e ) {}
    }
    // ksuzuki 2011/02/15 <<<

    // ksuzuki 2010/12/02 >>>
    private int getCommandLineStartOffset() {
        Element re = text.getDocument().getDefaultRootElement();
        int ei = re.getElementIndex( cmdStart );
        return re.getElement( ei ).getStartOffset();
    }

    public static class AKM
    {
        public String action;
        public int keyCode;
        public int modifier;

        public AKM(String a, int k, int m)
        {
            action = a; keyCode = k; modifier = m;
        }
    }

    private void assignTextInputToAction() {
        AKM[] akm = { new AKM("page-up", KeyEvent.VK_R, InputEvent.CTRL_MASK),
                      new AKM("page-down", KeyEvent.VK_V, InputEvent.CTRL_MASK) };

        ActionMap am = text.getActionMap();
        InputMap im = text.getInputMap();

        for ( int i = 0; i < akm.length; i++ ) {
            Action ac = am.get( akm[i].action );
            if ( ac != null ) {
                KeyStroke ks = KeyStroke.getKeyStroke( akm[i].keyCode, akm[i].modifier );
                im.put(ks, ac);
            }
        }
    }
    // ksuzuki 2010/12/02 <<<

    // ksuzuki 2010/12/14 >>>
    private void setCaretLater(final int pos) {
        EventQueue.invokeLater(new Runnable() {
                public void run() {
                    text.setCaretPosition(pos);
                }
            });
    }

    private void scrollToHome(KeyEvent event) {
        text.setCaretPosition(cmdStart);
        try {
            text.scrollRectToVisible(text.modelToView(cmdStart));
        } catch (BadLocationException e) {}
        event.consume();
    }
    // ksuzuki 2010/12/14 <<<
}
TOP

Related Classes of bsh.util.JConsole

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.