-/* $RCSfile$\r
- * $Author$\r
- * $Date$\r
- * $Revision$\r
- *\r
- * Copyright (C) 2002-2005 The Jmol Development Team\r
- *\r
- * Contact: jmol-developers@lists.sf.net\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\r
-\r
- *\r
- * Modified and added to Jalview by A Waterhouse to extend JInternalFrame\r
- *\r
-\r
- */\r
-package jalview.gui;\r
-\r
-import org.jmol.api.*;\r
-\r
-import java.awt.*;\r
-import java.awt.event.*;\r
-import javax.swing.*;\r
-import javax.swing.text.*;\r
-import java.util.Vector;\r
-\r
-import org.jmol.i18n.GT;\r
-import org.jmol.util.Logger;\r
-import org.jmol.util.CommandHistory;\r
-\r
-public final class ScriptWindow extends JPanel\r
- implements ActionListener, EnterListener{\r
-\r
- private ConsoleTextPane console;\r
- private JButton closeButton;\r
- private JButton runButton;\r
- private JButton haltButton;\r
- private JButton clearButton;\r
- private JButton historyButton;\r
- private JButton stateButton;\r
- JmolViewer viewer;\r
- AppJMol appJmol;\r
-\r
- public ScriptWindow(AppJMol appJmol)\r
- {\r
- this.viewer = appJmol.viewer;\r
- this.appJmol = appJmol;\r
-\r
-\r
- setLayout(new BorderLayout());\r
-\r
- console = new ConsoleTextPane(this);\r
-\r
-\r
- console.setPrompt();\r
- add(new JScrollPane(console)\r
- , BorderLayout.CENTER);\r
-\r
- JPanel buttonPanel = new JPanel();\r
- add(buttonPanel, BorderLayout.SOUTH);\r
-\r
- runButton = new JButton(GT._("Run"));\r
- haltButton = new JButton(GT._("Halt"));\r
- /*\r
- runButton.addActionListener(this);\r
- buttonPanel.add(runButton);\r
- haltButton.addActionListener(this);\r
- buttonPanel.add(haltButton);\r
- haltButton.setEnabled(false);*/\r
-\r
- clearButton = new JButton(GT._("Clear"));\r
- clearButton.addActionListener(this);\r
- buttonPanel.add(clearButton);\r
-\r
- historyButton = new JButton(GT._("History"));\r
- historyButton.addActionListener(this);\r
- buttonPanel.add(historyButton);\r
-\r
- stateButton = new JButton(GT._("State"));\r
- stateButton.addActionListener(this);\r
- buttonPanel.add(stateButton);\r
-\r
- closeButton = new JButton(GT._("Close"));\r
- closeButton.addActionListener(this);\r
- buttonPanel.add(closeButton);\r
-\r
- for(int i=0; i<buttonPanel.getComponentCount(); i++)\r
- {\r
- // ((JButton)buttonPanel.getComponent(i))\r
- // .setMargin(new Insets(0, 0, 0, 0));\r
- }\r
-\r
- }\r
-\r
- public void sendConsoleEcho(String strEcho) {\r
- if (strEcho != null && !isError) {\r
-\r
- console.outputEcho(strEcho);\r
-\r
- }\r
- setError(false);\r
- }\r
-\r
- boolean isError = false;\r
- void setError(boolean TF) {\r
- isError = TF;\r
- //if (isError)\r
- //console.recallCommand(true);\r
- }\r
-\r
- public void sendConsoleMessage(String strStatus) {\r
- if (strStatus == null) {\r
- console.clearContent();\r
- console.outputStatus("");\r
- } else if (strStatus.indexOf("ERROR:") >= 0) {\r
- console.outputError(strStatus);\r
- isError = true;\r
- } else if (!isError) {\r
- console.outputStatus(strStatus);\r
- }\r
- }\r
-\r
- public void notifyScriptTermination(String strMsg, int msWalltime) {\r
- if (strMsg != null && strMsg.indexOf("ERROR") >= 0) {\r
- console.outputError(strMsg);\r
- }\r
- runButton.setEnabled(true);\r
- haltButton.setEnabled(false);\r
- }\r
-\r
- public void enterPressed() {\r
- runButton.doClick(100);\r
- // executeCommand();\r
- }\r
-\r
-\r
- class ExecuteCommandThread extends Thread {\r
-\r
- String strCommand;\r
- ExecuteCommandThread (String command) {\r
- strCommand = command;\r
- }\r
-\r
- public void run() {\r
- try {\r
- executeCommand(strCommand);\r
- } catch (Exception ie) {\r
- Logger.debug("execution command interrupted!"+ie);\r
- }\r
- }\r
- }\r
-\r
- ExecuteCommandThread execThread;\r
- void executeCommandAsThread(){\r
- String strCommand = console.getCommandString().trim();\r
- if (strCommand.length() > 0) {\r
- execThread = new ExecuteCommandThread(strCommand);\r
- execThread.start();\r
- }\r
- }\r
-\r
- void executeCommand(String strCommand) {\r
- boolean doWait;\r
- setError(false);\r
- console.appendNewline();\r
- console.setPrompt();\r
- if (strCommand.length() > 0) {\r
- String strErrorMessage = null;\r
- doWait = (strCommand.indexOf("WAIT ") == 0);\r
- if (doWait) { //for testing, mainly\r
- // demonstrates using the statusManager system.\r
- runButton.setEnabled(false);\r
- haltButton.setEnabled(true);\r
-\r
- Vector info = (Vector) viewer\r
- .scriptWaitStatus(strCommand.substring(5),\r
- "+fileLoaded,+scriptStarted,+scriptStatus,+scriptEcho,+scriptTerminated");\r
- runButton.setEnabled(true);\r
- haltButton.setEnabled(false);\r
- /*\r
- * info = [ statusRecortSet0, statusRecortSet1, statusRecortSet2, ...]\r
- * statusRecordSet = [ statusRecord0, statusRecord1, statusRecord2, ...]\r
- * statusRecord = [int msgPtr, String statusName, int intInfo, String msg]\r
- */\r
- for (int i = 0; i < info.size(); i++) {\r
- Vector statusRecordSet = (Vector) info.get(i);\r
- for (int j = 0; j < statusRecordSet.size(); j++) {\r
- Vector statusRecord = (Vector) statusRecordSet.get(j);\r
- Logger.info("msg#=" + statusRecord.get(0) + " "\r
- + statusRecord.get(1) + " intInfo=" + statusRecord.get(2)\r
- + " stringInfo=" + statusRecord.get(3));\r
- }\r
- }\r
- console.appendNewline();\r
- } else {\r
- boolean isScriptExecuting = viewer.isScriptExecuting();\r
- if (viewer.checkHalt(strCommand))\r
- strErrorMessage = (isScriptExecuting ? "string execution halted with " + strCommand : "no script was executing");\r
- else\r
- strErrorMessage = "";//viewer.scriptCheck(strCommand);\r
- //the problem is that scriptCheck is synchronized, so these might get backed up.\r
- if (strErrorMessage != null && strErrorMessage.length() > 0) {\r
- console.outputError(strErrorMessage);\r
- } else {\r
- //runButton.setEnabled(false);\r
- haltButton.setEnabled(true);\r
- viewer.script(strCommand);\r
- }\r
- }\r
- }\r
- console.grabFocus();\r
- }\r
-\r
- public void actionPerformed(ActionEvent e) {\r
- Object source = e.getSource();\r
- if (source == closeButton) {\r
- appJmol.showConsole(false);\r
- } else if (source == runButton) {\r
- executeCommandAsThread();\r
- } else if (source == clearButton) {\r
- console.clearContent();\r
- } else if (source == historyButton) {\r
- console.clearContent(viewer.getSetHistory(Integer.MAX_VALUE));\r
- } else if (source == stateButton) {\r
- console.clearContent(viewer.getStateInfo());\r
- } else if (source == haltButton) {\r
- viewer.haltScriptExecution();\r
- }\r
- console.grabFocus(); // always grab the focus (e.g., after clear)\r
- }\r
-}\r
-\r
-class ConsoleTextPane extends JTextPane {\r
-\r
- ConsoleDocument consoleDoc;\r
- EnterListener enterListener;\r
- JmolViewer viewer;\r
-\r
- ConsoleTextPane(ScriptWindow scriptWindow) {\r
- super(new ConsoleDocument());\r
- consoleDoc = (ConsoleDocument)getDocument();\r
- consoleDoc.setConsoleTextPane(this);\r
- this.enterListener = (EnterListener) scriptWindow;\r
- this.viewer = scriptWindow.viewer;\r
- }\r
-\r
- public String getCommandString() {\r
- String cmd = consoleDoc.getCommandString();\r
- return cmd;\r
- }\r
-\r
- public void setPrompt() {\r
- consoleDoc.setPrompt();\r
- }\r
-\r
- public void appendNewline() {\r
- consoleDoc.appendNewline();\r
- }\r
-\r
- public void outputError(String strError) {\r
- consoleDoc.outputError(strError);\r
- }\r
-\r
- public void outputErrorForeground(String strError) {\r
- consoleDoc.outputErrorForeground(strError);\r
- }\r
-\r
- public void outputEcho(String strEcho) {\r
- consoleDoc.outputEcho(strEcho);\r
- }\r
-\r
- public void outputStatus(String strStatus) {\r
- consoleDoc.outputStatus(strStatus);\r
- }\r
-\r
- public void enterPressed() {\r
- if (enterListener != null)\r
- enterListener.enterPressed();\r
- }\r
-\r
- public void clearContent() {\r
- clearContent(null);\r
- }\r
- public void clearContent(String text) {\r
- consoleDoc.clearContent();\r
- if (text != null)\r
- consoleDoc.outputEcho(text);\r
- setPrompt();\r
- }\r
-\r
- /* (non-Javadoc)\r
- * @see java.awt.Component#processKeyEvent(java.awt.event.KeyEvent)\r
- */\r
-\r
- /**\r
- * Custom key event processing for command 0 implementation.\r
- *\r
- * Captures key up and key down strokes to call command history\r
- * and redefines the same events with control down to allow\r
- * caret vertical shift.\r
- *\r
- * @see java.awt.Component#processKeyEvent(java.awt.event.KeyEvent)\r
- */\r
- protected void processKeyEvent(KeyEvent ke)\r
- {\r
- // Id Control key is down, captures events does command\r
- // history recall and inhibits caret vertical shift.\r
- if (ke.getKeyCode() == KeyEvent.VK_UP\r
- && ke.getID() == KeyEvent.KEY_PRESSED\r
- && !ke.isControlDown())\r
- {\r
- recallCommand(true);\r
- }\r
- else if (\r
- ke.getKeyCode() == KeyEvent.VK_DOWN\r
- && ke.getID() == KeyEvent.KEY_PRESSED\r
- && !ke.isControlDown())\r
- {\r
- recallCommand(false);\r
- }\r
- // If Control key is down, redefines the event as if it\r
- // where a key up or key down stroke without modifiers.\r
- // This allows to move the caret up and down\r
- // with no command history recall.\r
- else if (\r
- (ke.getKeyCode() == KeyEvent.VK_DOWN\r
- || ke.getKeyCode() == KeyEvent.VK_UP)\r
- && ke.getID() == KeyEvent.KEY_PRESSED\r
- && ke.isControlDown())\r
- {\r
- super\r
- .processKeyEvent(new KeyEvent(\r
- (Component) ke.getSource(),\r
- ke.getID(),\r
- ke.getWhen(),\r
- 0, // No modifiers\r
- ke.getKeyCode(),\r
- ke.getKeyChar(),\r
- ke.getKeyLocation()));\r
- }\r
- // Standard processing for other events.\r
- else\r
- {\r
- super.processKeyEvent(ke);\r
- //check command for compiler-identifyable syntax issues\r
- //this may have to be taken out if people start complaining\r
- //that only some of the commands are being checked\r
- //that is -- that the script itself is not being fully checked\r
-\r
- //not perfect -- help here?\r
- if (ke.getID() == KeyEvent.KEY_RELEASED\r
- && (ke.getKeyCode() > KeyEvent.VK_DOWN) || ke.getKeyCode() == KeyEvent.VK_BACK_SPACE)\r
- checkCommand();\r
- }\r
- }\r
-\r
- /**\r
- * Recall command history.\r
- *\r
- * @param up - history up or down\r
- */\r
- void recallCommand(boolean up) {\r
- String cmd = viewer.getSetHistory(up ? -1 : 1);\r
- if (cmd == null) {\r
- return;\r
- }\r
- try {\r
- if (cmd.endsWith(CommandHistory.ERROR_FLAG)) {\r
- cmd = cmd.substring(0, cmd.indexOf(CommandHistory.ERROR_FLAG));\r
- consoleDoc.replaceCommand(cmd, true);\r
- } else {\r
- consoleDoc.replaceCommand(cmd, false);\r
- }\r
- } catch (BadLocationException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
-\r
- void checkCommand() {\r
- String strCommand = consoleDoc.getCommandString();\r
- if (strCommand.length() == 0)\r
- return;\r
- consoleDoc\r
- .colorCommand(viewer.scriptCheck(strCommand) == null ? consoleDoc.attUserInput\r
- : consoleDoc.attError);\r
- }\r
-\r
-\r
-}\r
-\r
-class ConsoleDocument extends DefaultStyledDocument {\r
-\r
- ConsoleTextPane consoleTextPane;\r
-\r
- SimpleAttributeSet attError;\r
- SimpleAttributeSet attEcho;\r
- SimpleAttributeSet attPrompt;\r
- SimpleAttributeSet attUserInput;\r
- SimpleAttributeSet attStatus;\r
-\r
- ConsoleDocument() {\r
- super();\r
-\r
- attError = new SimpleAttributeSet();\r
- StyleConstants.setForeground(attError, Color.red);\r
-\r
- attPrompt = new SimpleAttributeSet();\r
- StyleConstants.setForeground(attPrompt, Color.magenta);\r
-\r
- attUserInput = new SimpleAttributeSet();\r
- StyleConstants.setForeground(attUserInput, Color.black);\r
-\r
- attEcho = new SimpleAttributeSet();\r
- StyleConstants.setForeground(attEcho, Color.blue);\r
- StyleConstants.setBold(attEcho, true);\r
-\r
- attStatus = new SimpleAttributeSet();\r
- StyleConstants.setForeground(attStatus, Color.black);\r
- StyleConstants.setItalic(attStatus, true);\r
- }\r
-\r
- void setConsoleTextPane(ConsoleTextPane consoleTextPane) {\r
- this.consoleTextPane = consoleTextPane;\r
- }\r
-\r
- Position positionBeforePrompt; // starts at 0, so first time isn't tracked (at least on Mac OS X)\r
- Position positionAfterPrompt; // immediately after $, so this will track\r
- int offsetAfterPrompt; // only still needed for the insertString override and replaceCommand\r
-\r
- /**\r
- * Removes all content of the script window, and add a new prompt.\r
- */\r
- void clearContent() {\r
- try {\r
- super.remove(0, getLength());\r
- } catch (BadLocationException exception) {\r
- System.out.println("Could not clear script window content: " + exception.getMessage());\r
- }\r
- }\r
-\r
- void setPrompt() {\r
- try {\r
- super.insertString(getLength(), "$ ", attPrompt);\r
- setOffsetPositions();\r
- consoleTextPane.setCaretPosition(offsetAfterPrompt);\r
- } catch (BadLocationException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
-\r
- void setOffsetPositions() {\r
- try {\r
- offsetAfterPrompt = getLength();\r
- positionBeforePrompt = createPosition(offsetAfterPrompt - 2);\r
- // after prompt should be immediately after $ otherwise tracks the end\r
- // of the line (and no command will be found) at least on Mac OS X it did.\r
- positionAfterPrompt = createPosition(offsetAfterPrompt - 1);\r
- } catch (BadLocationException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
-\r
- void setNoPrompt() {\r
- try {\r
- offsetAfterPrompt = getLength();\r
- positionAfterPrompt = positionBeforePrompt = createPosition(offsetAfterPrompt);\r
- consoleTextPane.setCaretPosition(offsetAfterPrompt);\r
- } catch (BadLocationException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
-\r
- // it looks like the positionBeforePrompt does not track when it started out as 0\r
- // and a insertString at location 0 occurs. It may be better to track the\r
- // position after the prompt in stead\r
- void outputBeforePrompt(String str, SimpleAttributeSet attribute) {\r
- try {\r
- int pt = consoleTextPane.getCaretPosition();\r
- Position caretPosition = createPosition(pt);\r
- pt = positionBeforePrompt.getOffset();\r
- super.insertString(pt, str+"\n", attribute);\r
- setOffsetPositions();\r
- pt = caretPosition.getOffset();\r
- consoleTextPane.setCaretPosition(pt);\r
- } catch (BadLocationException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
-\r
- void outputError(String strError) {\r
- outputBeforePrompt(strError, attError);\r
- }\r
-\r
- void outputErrorForeground(String strError) {\r
- try {\r
- super.insertString(getLength(), strError+"\n", attError);\r
- consoleTextPane.setCaretPosition(getLength());\r
- } catch (BadLocationException e) {\r
- e.printStackTrace();\r
-\r
- }\r
- }\r
-\r
- void outputEcho(String strEcho) {\r
- outputBeforePrompt(strEcho, attEcho);\r
- }\r
-\r
- void outputStatus(String strStatus) {\r
- outputBeforePrompt(strStatus, attStatus);\r
- }\r
-\r
- void appendNewline() {\r
- try {\r
- super.insertString(getLength(), "\n", attUserInput);\r
- consoleTextPane.setCaretPosition(getLength());\r
- } catch (BadLocationException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
-\r
- // override the insertString to make sure everything typed ends up at the end\r
- // or in the 'command line' using the proper font, and the newline is processed.\r
- public void insertString(int offs, String str, AttributeSet a)\r
- throws BadLocationException {\r
- int ichNewline = str.indexOf('\n');\r
- if (ichNewline > 0)\r
- str = str.substring(0, ichNewline);\r
- if (ichNewline != 0) {\r
- if (offs < offsetAfterPrompt) {\r
- offs = getLength();\r
- }\r
- super.insertString(offs, str, a == attError ? a : attUserInput);\r
- consoleTextPane.setCaretPosition(offs+str.length());\r
- }\r
- if (ichNewline >= 0) {\r
- consoleTextPane.enterPressed();\r
- }\r
- }\r
-\r
- String getCommandString() {\r
- String strCommand = "";\r
- try {\r
- int cmdStart = positionAfterPrompt.getOffset();\r
- strCommand = getText(cmdStart, getLength() - cmdStart);\r
- while (strCommand.length() > 0 && strCommand.charAt(0) == ' ')\r
- strCommand = strCommand.substring(1);\r
- } catch (BadLocationException e) {\r
- e.printStackTrace();\r
- }\r
- return strCommand;\r
- }\r
-\r
- public void remove(int offs, int len)\r
- throws BadLocationException {\r
- if (offs < offsetAfterPrompt) {\r
- len -= offsetAfterPrompt - offs;\r
- if (len <= 0)\r
- return;\r
- offs = offsetAfterPrompt;\r
- }\r
- super.remove(offs, len);\r
-// consoleTextPane.setCaretPosition(offs);\r
- }\r
-\r
- public void replace(int offs, int length, String str, AttributeSet attrs)\r
- throws BadLocationException {\r
- if (offs < offsetAfterPrompt) {\r
- if (offs + length < offsetAfterPrompt) {\r
- offs = getLength();\r
- length = 0;\r
- } else {\r
- length -= offsetAfterPrompt - offs;\r
- offs = offsetAfterPrompt;\r
- }\r
- }\r
- super.replace(offs, length, str, attrs);\r
-// consoleTextPane.setCaretPosition(offs + str.length());\r
- }\r
-\r
- /**\r
- * Replaces current command on script.\r
- *\r
- * @param newCommand new command value\r
- * @param isError true to set error color ends with #??\r
- *\r
- * @throws BadLocationException\r
- */\r
- void replaceCommand(String newCommand, boolean isError) throws BadLocationException {\r
- if (positionAfterPrompt == positionBeforePrompt)\r
- return;\r
- replace(offsetAfterPrompt, getLength() - offsetAfterPrompt, newCommand,\r
- isError ? attError : attUserInput);\r
- }\r
-\r
- void colorCommand(SimpleAttributeSet att) {\r
- if (positionAfterPrompt == positionBeforePrompt)\r
- return;\r
- setCharacterAttributes(offsetAfterPrompt, getLength() - offsetAfterPrompt, att, true);\r
- }\r
-}\r
-\r
-interface EnterListener {\r
- public void enterPressed();\r
-}\r
-\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer (Version 2.6)
+ * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * Jalview is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ */
+package jalview.gui;
+
+import org.jmol.api.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.text.*;
+import java.util.Vector;
+
+import org.jmol.i18n.GT;
+import org.jmol.util.Logger;
+import org.jmol.util.CommandHistory;
+
+// TODO: this class is copied in from jmol 11.0.2 - upgrade to 12.0.2 ?
+public final class ScriptWindow extends JPanel implements ActionListener,
+ EnterListener
+{
+
+ private ConsoleTextPane console;
+
+ private JButton closeButton;
+
+ private JButton runButton;
+
+ private JButton haltButton;
+
+ private JButton clearButton;
+
+ private JButton historyButton;
+
+ private JButton stateButton;
+
+ JmolViewer viewer;
+
+ AppJmol appJmol;
+
+ public ScriptWindow(AppJmol appJmol)
+ {
+ this.viewer = appJmol.jmb.viewer;
+ this.appJmol = appJmol;
+
+ setLayout(new BorderLayout());
+
+ console = new ConsoleTextPane(this);
+
+ console.setPrompt();
+ add(new JScrollPane(console), BorderLayout.CENTER);
+
+ JPanel buttonPanel = new JPanel();
+ add(buttonPanel, BorderLayout.SOUTH);
+
+ runButton = new JButton(GT._("Run"));
+ haltButton = new JButton(GT._("Halt"));
+ runButton.addActionListener(this);
+ // buttonPanel.add(runButton);
+ haltButton.addActionListener(this);
+ // buttonPanel.add(haltButton);
+ haltButton.setEnabled(false);
+
+ clearButton = new JButton(GT._("Clear"));
+ clearButton.addActionListener(this);
+ buttonPanel.add(clearButton);
+
+ historyButton = new JButton(GT._("History"));
+ historyButton.addActionListener(this);
+ buttonPanel.add(historyButton);
+
+ stateButton = new JButton(GT._("State"));
+ stateButton.addActionListener(this);
+ buttonPanel.add(stateButton);
+
+ closeButton = new JButton(GT._("Close"));
+ closeButton.addActionListener(this);
+ buttonPanel.add(closeButton);
+
+ for (int i = 0; i < buttonPanel.getComponentCount(); i++)
+ {
+ // ((JButton)buttonPanel.getComponent(i))
+ // .setMargin(new Insets(0, 0, 0, 0));
+ }
+
+ }
+
+ public void sendConsoleEcho(String strEcho)
+ {
+ if (strEcho != null && !isError)
+ {
+
+ console.outputEcho(strEcho);
+
+ }
+ setError(false);
+ }
+
+ boolean isError = false;
+
+ void setError(boolean TF)
+ {
+ isError = TF;
+ // if (isError)
+ // console.recallCommand(true);
+ }
+
+ public void sendConsoleMessage(String strStatus)
+ {
+ if (strStatus == null)
+ {
+ console.clearContent();
+ console.outputStatus("");
+ }
+ else if (strStatus.indexOf("ERROR:") >= 0)
+ {
+ console.outputError(strStatus);
+ isError = true;
+ }
+ else if (!isError)
+ {
+ console.outputStatus(strStatus);
+ }
+ }
+
+ public void notifyScriptTermination(String strMsg, int msWalltime)
+ {
+ if (strMsg != null && strMsg.indexOf("ERROR") >= 0)
+ {
+ console.outputError(strMsg);
+ }
+ runButton.setEnabled(true);
+ haltButton.setEnabled(false);
+ }
+
+ public void enterPressed()
+ {
+ runButton.doClick(100);
+ // executeCommand();
+ }
+
+ class ExecuteCommandThread extends Thread
+ {
+
+ String strCommand;
+
+ ExecuteCommandThread(String command)
+ {
+ strCommand = command;
+ }
+
+ public void run()
+ {
+ try
+ {
+ executeCommand(strCommand);
+ } catch (Exception ie)
+ {
+ Logger.debug("execution command interrupted!" + ie);
+ }
+ }
+ }
+
+ ExecuteCommandThread execThread;
+
+ void executeCommandAsThread()
+ {
+ String strCommand = console.getCommandString().trim();
+ if (strCommand.length() > 0)
+ {
+ execThread = new ExecuteCommandThread(strCommand);
+ execThread.start();
+ }
+ }
+
+ void executeCommand(String strCommand)
+ {
+ boolean doWait;
+ setError(false);
+ console.appendNewline();
+ console.setPrompt();
+ if (strCommand.length() > 0)
+ {
+ String strErrorMessage = null;
+ doWait = (strCommand.indexOf("WAIT ") == 0);
+ if (doWait)
+ { // for testing, mainly
+ // demonstrates using the statusManager system.
+ runButton.setEnabled(false);
+ haltButton.setEnabled(true);
+
+ Vector info = (Vector) viewer
+ .scriptWaitStatus(strCommand.substring(5),
+ "+fileLoaded,+scriptStarted,+scriptStatus,+scriptEcho,+scriptTerminated");
+ runButton.setEnabled(true);
+ haltButton.setEnabled(false);
+ /*
+ * info = [ statusRecortSet0, statusRecortSet1, statusRecortSet2, ...]
+ * statusRecordSet = [ statusRecord0, statusRecord1, statusRecord2, ...]
+ * statusRecord = [int msgPtr, String statusName, int intInfo, String
+ * msg]
+ */
+ for (int i = 0; i < info.size(); i++)
+ {
+ Vector statusRecordSet = (Vector) info.get(i);
+ for (int j = 0; j < statusRecordSet.size(); j++)
+ {
+ Vector statusRecord = (Vector) statusRecordSet.get(j);
+ Logger.info("msg#=" + statusRecord.get(0) + " "
+ + statusRecord.get(1) + " intInfo="
+ + statusRecord.get(2) + " stringInfo="
+ + statusRecord.get(3));
+ }
+ }
+ console.appendNewline();
+ }
+ else
+ {
+ boolean isScriptExecuting = viewer.isScriptExecuting();
+ if (viewer.checkHalt(strCommand, true))
+ strErrorMessage = (isScriptExecuting ? "string execution halted with "
+ + strCommand
+ : "no script was executing");
+ else
+ strErrorMessage = "";// viewer.scriptCheck(strCommand);
+ // the problem is that scriptCheck is synchronized, so these might get
+ // backed up.
+ if (strErrorMessage != null && strErrorMessage.length() > 0)
+ {
+ console.outputError(strErrorMessage);
+ }
+ else
+ {
+ // runButton.setEnabled(false);
+ haltButton.setEnabled(true);
+ viewer.script(strCommand);
+ }
+ }
+ }
+ console.grabFocus();
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ Object source = e.getSource();
+ if (source == closeButton)
+ {
+ // appJmol.showConsole(false);
+ }
+ else if (source == runButton)
+ {
+ executeCommandAsThread();
+ }
+ else if (source == clearButton)
+ {
+ console.clearContent();
+ }
+ else if (source == historyButton)
+ {
+ console.clearContent(viewer.getSetHistory(Integer.MAX_VALUE));
+ }
+ else if (source == stateButton)
+ {
+ console.clearContent(viewer.getStateInfo());
+ }
+ else if (source == haltButton)
+ {
+ viewer.haltScriptExecution();
+ }
+ console.grabFocus(); // always grab the focus (e.g., after clear)
+ }
+}
+
+class ConsoleTextPane extends JTextPane
+{
+
+ ConsoleDocument consoleDoc;
+
+ EnterListener enterListener;
+
+ JmolViewer viewer;
+
+ ConsoleTextPane(ScriptWindow scriptWindow)
+ {
+ super(new ConsoleDocument());
+ consoleDoc = (ConsoleDocument) getDocument();
+ consoleDoc.setConsoleTextPane(this);
+ this.enterListener = (EnterListener) scriptWindow;
+ this.viewer = scriptWindow.viewer;
+ }
+
+ public String getCommandString()
+ {
+ String cmd = consoleDoc.getCommandString();
+ return cmd;
+ }
+
+ public void setPrompt()
+ {
+ consoleDoc.setPrompt();
+ }
+
+ public void appendNewline()
+ {
+ consoleDoc.appendNewline();
+ }
+
+ public void outputError(String strError)
+ {
+ consoleDoc.outputError(strError);
+ }
+
+ public void outputErrorForeground(String strError)
+ {
+ consoleDoc.outputErrorForeground(strError);
+ }
+
+ public void outputEcho(String strEcho)
+ {
+ consoleDoc.outputEcho(strEcho);
+ }
+
+ public void outputStatus(String strStatus)
+ {
+ consoleDoc.outputStatus(strStatus);
+ }
+
+ public void enterPressed()
+ {
+ if (enterListener != null)
+ enterListener.enterPressed();
+ }
+
+ public void clearContent()
+ {
+ clearContent(null);
+ }
+
+ public void clearContent(String text)
+ {
+ consoleDoc.clearContent();
+ if (text != null)
+ consoleDoc.outputEcho(text);
+ setPrompt();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.awt.Component#processKeyEvent(java.awt.event.KeyEvent)
+ */
+
+ /**
+ * Custom key event processing for command 0 implementation.
+ *
+ * Captures key up and key down strokes to call command history and redefines
+ * the same events with control down to allow caret vertical shift.
+ *
+ * @see java.awt.Component#processKeyEvent(java.awt.event.KeyEvent)
+ */
+ protected void processKeyEvent(KeyEvent ke)
+ {
+ // Id Control key is down, captures events does command
+ // history recall and inhibits caret vertical shift.
+ if (ke.getKeyCode() == KeyEvent.VK_UP
+ && ke.getID() == KeyEvent.KEY_PRESSED && !ke.isControlDown())
+ {
+ recallCommand(true);
+ }
+ else if (ke.getKeyCode() == KeyEvent.VK_DOWN
+ && ke.getID() == KeyEvent.KEY_PRESSED && !ke.isControlDown())
+ {
+ recallCommand(false);
+ }
+ // If Control key is down, redefines the event as if it
+ // where a key up or key down stroke without modifiers.
+ // This allows to move the caret up and down
+ // with no command history recall.
+ else if ((ke.getKeyCode() == KeyEvent.VK_DOWN || ke.getKeyCode() == KeyEvent.VK_UP)
+ && ke.getID() == KeyEvent.KEY_PRESSED && ke.isControlDown())
+ {
+ super.processKeyEvent(new KeyEvent((Component) ke.getSource(), ke
+ .getID(), ke.getWhen(), 0, // No modifiers
+ ke.getKeyCode(), ke.getKeyChar(), ke.getKeyLocation()));
+ }
+ // Standard processing for other events.
+ else
+ {
+ super.processKeyEvent(ke);
+ // check command for compiler-identifyable syntax issues
+ // this may have to be taken out if people start complaining
+ // that only some of the commands are being checked
+ // that is -- that the script itself is not being fully checked
+
+ // not perfect -- help here?
+ if (ke.getID() == KeyEvent.KEY_RELEASED
+ && (ke.getKeyCode() > KeyEvent.VK_DOWN)
+ || ke.getKeyCode() == KeyEvent.VK_BACK_SPACE)
+ checkCommand();
+ }
+ }
+
+ /**
+ * Recall command history.
+ *
+ * @param up
+ * - history up or down
+ */
+ void recallCommand(boolean up)
+ {
+ String cmd = viewer.getSetHistory(up ? -1 : 1);
+ if (cmd == null)
+ {
+ return;
+ }
+ try
+ {
+ if (cmd.endsWith(CommandHistory.ERROR_FLAG))
+ {
+ cmd = cmd.substring(0, cmd.indexOf(CommandHistory.ERROR_FLAG));
+ consoleDoc.replaceCommand(cmd, true);
+ }
+ else
+ {
+ consoleDoc.replaceCommand(cmd, false);
+ }
+ } catch (BadLocationException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ void checkCommand()
+ {
+ String strCommand = consoleDoc.getCommandString();
+ if (strCommand.length() == 0)
+ return;
+ consoleDoc
+ .colorCommand(viewer.scriptCheck(strCommand) == null ? consoleDoc.attUserInput
+ : consoleDoc.attError);
+ }
+
+}
+
+class ConsoleDocument extends DefaultStyledDocument
+{
+
+ ConsoleTextPane consoleTextPane;
+
+ SimpleAttributeSet attError;
+
+ SimpleAttributeSet attEcho;
+
+ SimpleAttributeSet attPrompt;
+
+ SimpleAttributeSet attUserInput;
+
+ SimpleAttributeSet attStatus;
+
+ ConsoleDocument()
+ {
+ super();
+
+ attError = new SimpleAttributeSet();
+ StyleConstants.setForeground(attError, Color.red);
+
+ attPrompt = new SimpleAttributeSet();
+ StyleConstants.setForeground(attPrompt, Color.magenta);
+
+ attUserInput = new SimpleAttributeSet();
+ StyleConstants.setForeground(attUserInput, Color.black);
+
+ attEcho = new SimpleAttributeSet();
+ StyleConstants.setForeground(attEcho, Color.blue);
+ StyleConstants.setBold(attEcho, true);
+
+ attStatus = new SimpleAttributeSet();
+ StyleConstants.setForeground(attStatus, Color.black);
+ StyleConstants.setItalic(attStatus, true);
+ }
+
+ void setConsoleTextPane(ConsoleTextPane consoleTextPane)
+ {
+ this.consoleTextPane = consoleTextPane;
+ }
+
+ Position positionBeforePrompt; // starts at 0, so first time isn't tracked
+
+ // (at least on Mac OS X)
+
+ Position positionAfterPrompt; // immediately after $, so this will track
+
+ int offsetAfterPrompt; // only still needed for the insertString override and
+
+ // replaceCommand
+
+ /**
+ * Removes all content of the script window, and add a new prompt.
+ */
+ void clearContent()
+ {
+ try
+ {
+ super.remove(0, getLength());
+ } catch (BadLocationException exception)
+ {
+ System.out.println("Could not clear script window content: "
+ + exception.getMessage());
+ }
+ }
+
+ void setPrompt()
+ {
+ try
+ {
+ super.insertString(getLength(), "$ ", attPrompt);
+ setOffsetPositions();
+ consoleTextPane.setCaretPosition(offsetAfterPrompt);
+ } catch (BadLocationException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ void setOffsetPositions()
+ {
+ try
+ {
+ offsetAfterPrompt = getLength();
+ positionBeforePrompt = createPosition(offsetAfterPrompt - 2);
+ // after prompt should be immediately after $ otherwise tracks the end
+ // of the line (and no command will be found) at least on Mac OS X it did.
+ positionAfterPrompt = createPosition(offsetAfterPrompt - 1);
+ } catch (BadLocationException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ void setNoPrompt()
+ {
+ try
+ {
+ offsetAfterPrompt = getLength();
+ positionAfterPrompt = positionBeforePrompt = createPosition(offsetAfterPrompt);
+ consoleTextPane.setCaretPosition(offsetAfterPrompt);
+ } catch (BadLocationException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ // it looks like the positionBeforePrompt does not track when it started out
+ // as 0
+ // and a insertString at location 0 occurs. It may be better to track the
+ // position after the prompt in stead
+ void outputBeforePrompt(String str, SimpleAttributeSet attribute)
+ {
+ try
+ {
+ int pt = consoleTextPane.getCaretPosition();
+ Position caretPosition = createPosition(pt);
+ pt = positionBeforePrompt.getOffset();
+ super.insertString(pt, str + "\n", attribute);
+ setOffsetPositions();
+ pt = caretPosition.getOffset();
+ consoleTextPane.setCaretPosition(pt);
+ } catch (BadLocationException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ void outputError(String strError)
+ {
+ outputBeforePrompt(strError, attError);
+ }
+
+ void outputErrorForeground(String strError)
+ {
+ try
+ {
+ super.insertString(getLength(), strError + "\n", attError);
+ consoleTextPane.setCaretPosition(getLength());
+ } catch (BadLocationException e)
+ {
+ e.printStackTrace();
+
+ }
+ }
+
+ void outputEcho(String strEcho)
+ {
+ outputBeforePrompt(strEcho, attEcho);
+ }
+
+ void outputStatus(String strStatus)
+ {
+ outputBeforePrompt(strStatus, attStatus);
+ }
+
+ void appendNewline()
+ {
+ try
+ {
+ super.insertString(getLength(), "\n", attUserInput);
+ consoleTextPane.setCaretPosition(getLength());
+ } catch (BadLocationException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ // override the insertString to make sure everything typed ends up at the end
+ // or in the 'command line' using the proper font, and the newline is
+ // processed.
+ public void insertString(int offs, String str, AttributeSet a)
+ throws BadLocationException
+ {
+ int ichNewline = str.indexOf('\n');
+ if (ichNewline > 0)
+ str = str.substring(0, ichNewline);
+ if (ichNewline != 0)
+ {
+ if (offs < offsetAfterPrompt)
+ {
+ offs = getLength();
+ }
+ super.insertString(offs, str, a == attError ? a : attUserInput);
+ consoleTextPane.setCaretPosition(offs + str.length());
+ }
+ if (ichNewline >= 0)
+ {
+ consoleTextPane.enterPressed();
+ }
+ }
+
+ String getCommandString()
+ {
+ String strCommand = "";
+ try
+ {
+ int cmdStart = positionAfterPrompt.getOffset();
+ strCommand = getText(cmdStart, getLength() - cmdStart);
+ while (strCommand.length() > 0 && strCommand.charAt(0) == ' ')
+ strCommand = strCommand.substring(1);
+ } catch (BadLocationException e)
+ {
+ e.printStackTrace();
+ }
+ return strCommand;
+ }
+
+ public void remove(int offs, int len) throws BadLocationException
+ {
+ if (offs < offsetAfterPrompt)
+ {
+ len -= offsetAfterPrompt - offs;
+ if (len <= 0)
+ return;
+ offs = offsetAfterPrompt;
+ }
+ super.remove(offs, len);
+ // consoleTextPane.setCaretPosition(offs);
+ }
+
+ public void replace(int offs, int length, String str, AttributeSet attrs)
+ throws BadLocationException
+ {
+ if (offs < offsetAfterPrompt)
+ {
+ if (offs + length < offsetAfterPrompt)
+ {
+ offs = getLength();
+ length = 0;
+ }
+ else
+ {
+ length -= offsetAfterPrompt - offs;
+ offs = offsetAfterPrompt;
+ }
+ }
+ super.replace(offs, length, str, attrs);
+ // consoleTextPane.setCaretPosition(offs + str.length());
+ }
+
+ /**
+ * Replaces current command on script.
+ *
+ * @param newCommand
+ * new command value
+ * @param isError
+ * true to set error color ends with #??
+ *
+ * @throws BadLocationException
+ */
+ void replaceCommand(String newCommand, boolean isError)
+ throws BadLocationException
+ {
+ if (positionAfterPrompt == positionBeforePrompt)
+ return;
+ replace(offsetAfterPrompt, getLength() - offsetAfterPrompt, newCommand,
+ isError ? attError : attUserInput);
+ }
+
+ void colorCommand(SimpleAttributeSet att)
+ {
+ if (positionAfterPrompt == positionBeforePrompt)
+ return;
+ setCharacterAttributes(offsetAfterPrompt, getLength()
+ - offsetAfterPrompt, att, true);
+ }
+}
+
+interface EnterListener
+{
+ public void enterPressed();
+}