blob: c7e4dee51bc34c73dc2ef896599e39832ae256c6 [file] [log] [blame]
/*
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This source code is provided to illustrate the usage of a given feature
* or technique and has been deliberately simplified. Additional steps
* required for a production-quality application, such as security checks,
* input validation and proper error handling, might not be present in
* this sample code.
*/
package com.sun.demo.scripting.jconsole;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
/**
* A JPanel subclass containing a scrollable text area displaying the
* jconsole's script console.
*/
public class ScriptShellPanel extends JPanel {
private static final long serialVersionUID = 4116273141148726319L;
// interface to evaluate script command and script prompt
interface CommandProcessor {
// execute given String as script and return the result
public String executeCommand(String cmd);
// get prompt used for interactive read-eval-loop
public String getPrompt();
}
// my script command processor
private CommandProcessor commandProcessor;
// editor component for command editing
private JTextComponent editor;
private final ExecutorService commandExecutor =
Executors.newSingleThreadExecutor();
// document management
private boolean updating;
public ScriptShellPanel(CommandProcessor cmdProc) {
setLayout(new BorderLayout());
this.commandProcessor = cmdProc;
this.editor = new JTextArea();
editor.setDocument(new EditableAtEndDocument());
JScrollPane scroller = new JScrollPane();
scroller.getViewport().add(editor);
add(scroller, BorderLayout.CENTER);
editor.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void changedUpdate(DocumentEvent e) {
}
@Override
public void insertUpdate(DocumentEvent e) {
if (updating) return;
beginUpdate();
editor.setCaretPosition(editor.getDocument().getLength());
if (insertContains(e, '\n')) {
String cmd = getMarkedText();
// Handle multi-line input
if ((cmd.length() == 0) ||
(cmd.charAt(cmd.length() - 1) != '\\')) {
// Trim "\\n" combinations
final String cmd1 = trimContinuations(cmd);
commandExecutor.execute(new Runnable() {
@Override
public void run() {
final String result = executeCommand(cmd1);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (result != null) {
print(result + "\n");
}
printPrompt();
setMark();
endUpdate();
}
});
}
});
} else {
endUpdate();
}
} else {
endUpdate();
}
}
@Override
public void removeUpdate(DocumentEvent e) {
}
});
// This is a bit of a hack but is probably better than relying on
// the JEditorPane to update the caret's position precisely the
// size of the insertion
editor.addCaretListener(new CaretListener() {
@Override
public void caretUpdate(CaretEvent e) {
int len = editor.getDocument().getLength();
if (e.getDot() > len) {
editor.setCaretPosition(len);
}
}
});
Box hbox = Box.createHorizontalBox();
hbox.add(Box.createGlue());
JButton button = new JButton("Clear"); // FIXME: i18n?
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
clear();
}
});
hbox.add(button);
hbox.add(Box.createGlue());
add(hbox, BorderLayout.SOUTH);
clear();
}
public void dispose() {
commandExecutor.shutdown();
}
@Override
public void requestFocus() {
editor.requestFocus();
}
public void clear() {
clear(true);
}
public void clear(boolean prompt) {
EditableAtEndDocument d = (EditableAtEndDocument) editor.getDocument();
d.clear();
if (prompt) printPrompt();
setMark();
editor.requestFocus();
}
public void setMark() {
((EditableAtEndDocument) editor.getDocument()).setMark();
}
public String getMarkedText() {
try {
String s = ((EditableAtEndDocument) editor.getDocument()).getMarkedText();
int i = s.length();
while ((i > 0) && (s.charAt(i - 1) == '\n')) {
i--;
}
return s.substring(0, i);
} catch (BadLocationException e) {
e.printStackTrace();
return null;
}
}
public void print(String s) {
Document d = editor.getDocument();
try {
d.insertString(d.getLength(), s, null);
} catch (BadLocationException e) {
e.printStackTrace();
}
}
//
// Internals only below this point
//
private String executeCommand(String cmd) {
return commandProcessor.executeCommand(cmd);
}
private String getPrompt() {
return commandProcessor.getPrompt();
}
private void beginUpdate() {
editor.setEditable(false);
updating = true;
}
private void endUpdate() {
editor.setEditable(true);
updating = false;
}
private void printPrompt() {
print(getPrompt());
}
private boolean insertContains(DocumentEvent e, char c) {
String s = null;
try {
s = editor.getText(e.getOffset(), e.getLength());
for (int i = 0; i < e.getLength(); i++) {
if (s.charAt(i) == c) {
return true;
}
}
} catch (BadLocationException ex) {
ex.printStackTrace();
}
return false;
}
private String trimContinuations(String text) {
int i;
while ((i = text.indexOf("\\\n")) >= 0) {
text = text.substring(0, i) + text.substring(i+1, text.length());
}
return text;
}
}