//
// JPythonEditor.java
//

/*
VisAD system for interactive analysis and visualization of numerical
data.  Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom
Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and
Tommy Jasmin.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This library 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
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/

package visad.python;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import visad.VisADException;
import visad.util.*;

/** An editor for writing and executing JPython code in Java runtime. */
public class JPythonEditor extends CodeEditor {

  /** text to be prepended to all JPython documents */
  private static final String PREPENDED_TEXT =
    "from visad.python.JPythonMethods import *";

  /** monospaced font to use for error message reporting */
  private static final Font MONO_FONT = new Font("Monospaced", Font.PLAIN, 11);

  /** wrapper for PythonInterpreter object */
  protected RunJPython python = null;

  /** flag indicating whether to warn before auto-saving */
  protected boolean warnBeforeSave = true;
  
  /** flag indicating whether to launch scripts in a separate process */
  protected boolean runSeparate = true;

  /** run menu item */
  private JMenuItem runItem;


  /** runs the given command in a separate process */
  public static String[] runCommand(String cmd)
    throws IOException, VisADException
  {
    ArrayList list = new ArrayList();
    Process proc = Runtime.getRuntime().exec(cmd);

    // capture program output
    InputStream istr = proc.getInputStream();
    BufferedReader br = new BufferedReader(new InputStreamReader(istr));
    String str;
    while ((str = br.readLine()) != null) list.add(str);

    // wait for command to terminate
    try { proc.waitFor(); }
    catch (InterruptedException e) { e.printStackTrace(); }

    br.close();

    // check exit value
    if (proc.exitValue() != 0) {
      throw new VisADException("exit value was non-zero");
    }

    // return output as a list of strings
    return (String[]) list.toArray(new String[0]);
  }


  /** constructs a JPythonEditor */
  public JPythonEditor() throws VisADException {
    this(null);
  }

  /** constructs a JPythonEditor containing text from the given filename */
  public JPythonEditor(String filename) throws VisADException {
    super(filename);
    python = new RunJPython();


  }

  /** Create and initialize the the file chooser */
  protected JFileChooser doMakeFileChooser() {
      JFileChooser tmpFileChooser = super.doMakeFileChooser();
      // add JPython files to file chooser dialog box
      tmpFileChooser.addChoosableFileFilter(
          new ExtensionFileFilter("py", "JPython source code"));
      return tmpFileChooser;
  }


  /** adjusts the line number of the given error to match the displayed text,
      and highlights that line of code to indicate the source of error */
  private String handleError(String err, String filename) {
    // convert eol character sequences to newlines
    StringTokenizer st = new StringTokenizer(err, "\r\n");
    StringBuffer sbuf = new StringBuffer(err.length());
    while (st.hasMoreTokens()) {
      String line = st.nextToken();
      // convert tabs to spaces
      int tab = line.indexOf("\t");
      while (tab >= 0) {
        line = line.substring(0, tab) + "        " + line.substring(tab + 1);
        tab = line.indexOf("\t");
      }
      sbuf.append(line + "\n");
    }
    String nerr = sbuf.toString();

    // adjust error's line number to match displayed line numbers
    String toLine = filename + "\", ";
    int index = nerr.indexOf(toLine + "line ");
    if (index >= 0) {
      index += toLine.length() + 5;
      int nline = nerr.indexOf("\n", index);
      int lineNum = -1;
      try {
        lineNum = Integer.parseInt(nerr.substring(index, nline));
      }
      catch (NumberFormatException exc) { }
      lineNum--;
      if (lineNum >= 1) {
        highlightLine(lineNum);
        nerr = nerr.substring(0, index) + lineNum + nerr.substring(nline);
      }
    }

    // set up error message dialog
    Component c = getRootPane().getParent();
    final JDialog dialog =
      c instanceof Dialog ?
        new JDialog((Dialog) c, "JPython script error", true) :
      c instanceof Frame ?
        new JDialog((Frame) c, "JPython script error", true) :
        new JDialog((Frame) null, "JPython script error", true);

    // create dialog components
    JLabel label = new JLabel("An error in the script occurred:");
    label.setAlignmentX(JLabel.CENTER_ALIGNMENT);
    JTextArea area = new JTextArea(nerr, 16, 80);
    area.setEditable(false);
    area.setFont(MONO_FONT);
    area.setWrapStyleWord(true);
    JButton button = new JButton("OK");

    // define dialog actions
    button.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        // dismiss dialog box
        dialog.hide();
      }
    });

    // do dialog layout
    JPanel p = new JPanel();
    p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
    p.add(label);
    p.add(area);
    p.add(button);
    dialog.setContentPane(p);

    // pop up dialog with error message
    dialog.pack();
    dialog.show();

    return nerr;
  }

  /** executes a line of JPython code */
  public void exec(String line) throws VisADException {
    python.exec(line);
  }

  /** executes the document as JPython source code */
  public void execfile(String filename) throws VisADException {
    try {
      python.execfile(filename);
    }
    catch (VisADException exc) {
      String error = handleError(exc.getMessage(), filename);
      throw new VisADException(error);
    }
  }

  /** returns a string containing the text of the document */
  public String getText() {
    return PREPENDED_TEXT +
      System.getProperty("line.separator") + super.getText();
  }

  /** sets the text of the document to the current string */
  public void setText(String text) {
    if (text.startsWith(PREPENDED_TEXT)) {
      // strip off prepended text
      text = text.substring(PREPENDED_TEXT.length()).trim();
    }
    super.setText(text);
  }

  /** sets whether editor should warn user before auto-saving */
  public void setWarnBeforeSave(boolean warn) { warnBeforeSave = warn; }

  /** sets whether editor should run scripts in a separate process */
  public void setRunSeparateProcess(boolean separate) {
    runSeparate = separate;
  }
  
  /** sets the run menu item */
  public void setRunItem(JMenuItem run) { runItem = run; }

  /** executes the JPython script */
  public void run() {
    if (hasChanged()) {
      if (warnBeforeSave) {
        int ans = JOptionPane.showConfirmDialog(this,
          "A save is required before execution. Okay to save?",
          "VisAD JPython Editor", JOptionPane.YES_NO_OPTION);
        if (ans != JOptionPane.YES_OPTION) return;
      }
      boolean success = saveFile();
      if (!success) return;
    }
    Thread t = new Thread(new Runnable() {
      public void run() {
        String name = getFilename();
        if (runSeparate) {
          String[] out;
          try {
            out = runCommand("java visad.python.RunJPython " + name);
          }
          catch (IOException exc) {
            if (DEBUG) exc.printStackTrace();
          }
          catch (VisADException exc) {
            if (DEBUG) exc.printStackTrace();
            String error = handleError(exc.getMessage(), name);
          }
        }
        else {
          runItem.setEnabled(false);
          runItem.setText("Running...");
          try {
            execfile(name);
          }
          catch (VisADException exc) {
            if (DEBUG) exc.printStackTrace();
          }
          runItem.setText("Run");
          runItem.setEnabled(true);
        }
      }
    });
    t.start();
  }

  /** compiles the JPython script to a Java class */
  public void compile() throws VisADException {
    throw new VisADException("Not yet implemented!");
  }
  
}

 

Ads help maintain this website.