update author list in license for (JAL-826)
[jalview.git] / src / jalview / gui / ScriptWindow.java
index fc2d849..adebec8 100644 (file)
-/* $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.7)
+ * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, 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();
+}