/*
* JythonScriptPanel.java
*
* Created on May 13, 2008, 11:24 AM
*/
package org.autoplot.scriptconsole;
import java.awt.Dimension;
import org.autoplot.jythonsupport.ui.EditorContextMenu;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.AbstractAction;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import jsyntaxpane.SyntaxDocument;
import org.das2.jythoncompletion.JythonCompletionProvider;
import org.das2.jythoncompletion.JythonCompletionTask;
import org.das2.jythoncompletion.JythonInterpreterProvider;
import org.das2.jythoncompletion.ui.CompletionImpl;
import org.das2.util.FileUtil;
import org.das2.util.LoggerManager;
import org.das2.util.filesystem.FileSystem;
import org.das2.util.monitor.NullProgressMonitor;
import org.python.core.Py;
import org.python.core.PyDictionary;
import org.python.util.PythonInterpreter;
import org.autoplot.AppManager;
import org.autoplot.ApplicationModel;
import org.autoplot.AutoplotUI;
import org.autoplot.JythonUtil;
import org.autoplot.ScriptContext;
import org.autoplot.dom.ApplicationController;
import org.autoplot.datasource.DataSetSelector;
import org.autoplot.datasource.DataSetURI;
import org.autoplot.datasource.DataSourceUtil;
import org.autoplot.jythonsupport.ui.EditorAnnotationsSupport;
import org.autoplot.jythonsupport.ui.EditorTextPane;
/**
* GUI for editing and running Jython scripts.
* @author jbf
*/
public class JythonScriptPanel extends javax.swing.JPanel {
private static final Logger logger= org.das2.util.LoggerManager.getLogger("autoplot");
ApplicationModel model;
ApplicationController applicationController;
DataSetSelector selector;
ScriptPanelSupport support;
static final int CONTEXT_DATA_SOURCE = 1;
static final int CONTEXT_APPLICATION = 0;
private int context = 0;
File runningScript= null; // the script being run.
EditorContextMenu menu;
/**
* true if the current file contains tabs.
*/
boolean containsTabs= false;
private transient DocumentListener dirtyListener; // this contains repeated code in ScriptPanelSupport
/**
* this downloads the URI and loads the local version into the editor.
* @param uri the URI
*/
public void loadExampleUri( String uri ) {
try {
File ff= DataSetURI.getFile( uri, new NullProgressMonitor() );
loadFile( ff );
} catch (IOException ex) {
Logger.getLogger(JythonScriptPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Creates new form JythonScriptPanel
*
* @param app the app with which we'll register the close callback.
* @param selector the selector which might receive jyds URIs when "execute" is pressed.
*/
public JythonScriptPanel( AutoplotUI app, final DataSetSelector selector) {
initComponents();
setMinimumSize( new Dimension(400,400) );
jScrollPane2.getVerticalScrollBar().setUnitIncrement( 12 ); // TODO: should be line height.
setContext(CONTEXT_APPLICATION);
this.model = app.getApplicationModel();
support = new ScriptPanelSupport(this, model, selector);
this.applicationController= model.getDocumentModel().getController();
this.selector = selector;
this.textArea.setFont( Font.decode(JythonCompletionProvider.getInstance().settings().getEditorFont() ) );
this.textArea.addCaretListener(new CaretListener() {
@Override
public void caretUpdate(CaretEvent e) {
int pos = textArea.getCaretPosition();
Element root = textArea.getDocument().getDefaultRootElement();
int irow = root.getElementIndex(pos);
int icol = pos - root.getElement(irow).getStartOffset();
String text = "" + (1 + irow) + "," + (1 + icol);
int isel = textArea.getSelectionEnd() - textArea.getSelectionStart();
int iselRow0 = root.getElementIndex(textArea.getSelectionStart());
int iselRow1 = root.getElementIndex(textArea.getSelectionEnd());
if (isel > 0) {
if (iselRow1 > iselRow0) {
text = "[" + isel + "ch," + (1 + iselRow1 - iselRow0) + "lines]";
} else {
text = "[" + isel + "ch]";
}
}
caretPositionLabel.setText(text);
}
});
dirtyListener= new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
setDirty(true);
}
@Override
public void removeUpdate(DocumentEvent e) {
setDirty(true);
}
@Override
public void changedUpdate(DocumentEvent e) {
}
};
this.textArea.getDocument().addDocumentListener(dirtyListener);
this.textArea.addPropertyChangeListener( "document", new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ( evt.getOldValue()!=null ) {
((Document)evt.getOldValue()).removeDocumentListener(dirtyListener);
}
((Document)evt.getNewValue()).addDocumentListener(dirtyListener);
}
});
this.textArea.getActionMap().put( ACTIONKEY_SAVE, new AbstractAction( ACTIONKEY_SAVE ) {
@Override
public void actionPerformed( ActionEvent e ) {
LoggerManager.logGuiEvent(e);
try {
support.save();
} catch (FileNotFoundException ex) {
model.getExceptionHandler().handle(ex);
} catch (IOException ex) {
model.getExceptionHandler().handle(ex);
}
}
});
this.textArea.getActionMap().put( ACTIONKEY_EXECUTE, new AbstractAction( ACTIONKEY_EXECUTE ) {
@Override
public void actionPerformed( ActionEvent e ) {
executeButtonActionPerformed(e);
}
});
AppManager.getInstance().addCloseCallback( app, "jythonScriptPanel", new AppManager.CloseCallback() {
@Override
public boolean checkClose() {
if ( isDirty() && isVisible() && textArea.getDocument().getLength()>0 ) {
int resp= JOptionPane.showConfirmDialog( JythonScriptPanel.this, "Script Editor contains unsaved changes. Save these changes?" );
switch (resp) {
case JOptionPane.CANCEL_OPTION:
return false;
case JOptionPane.OK_OPTION:
try {
return support.save() == JOptionPane.OK_OPTION;
} catch ( IOException ex ) {
return false;
}
case JOptionPane.NO_OPTION:
return true;
default:
break;
}
return false;
} else {
return true;
}
}
});
this.textArea.getInputMap().put(KeyStroke.getKeyStroke( KeyEvent.VK_S,Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() ), ACTIONKEY_SAVE);
this.textArea.getInputMap().put(KeyStroke.getKeyStroke( KeyEvent.VK_F6, 0 ), ACTIONKEY_EXECUTE);
this.textArea.getInputMap().put(KeyStroke.getKeyStroke( KeyEvent.VK_F6, InputEvent.SHIFT_DOWN_MASK ), ACTIONKEY_EXECUTE );
EditorContextMenu menu= new EditorContextMenu( this.textArea );
menu.addExampleAction( new AbstractAction("makePngWalk.jy") {
@Override
public void actionPerformed(ActionEvent e) {
LoggerManager.logGuiEvent(e);
loadExample( "/scripts/pngwalk/makePngWalk.jy" );
}
});
menu.addExampleAction( new AbstractAction("addDigitizer.jy") {
@Override
public void actionPerformed(ActionEvent e) {
LoggerManager.logGuiEvent(e);
loadExample( "/scripts/addDigitizer.jy" );
}
});
menu.addExampleAction( new AbstractAction("splineDemo.jy") {
@Override
public void actionPerformed(ActionEvent e) {
LoggerManager.logGuiEvent(e);
loadExample( "/scripts/splineDemo.jy" );
}
});
menu.addExampleAction( new AbstractAction("More Jython Scripts...") {
@Override
public void actionPerformed(ActionEvent e) {
LoggerManager.logGuiEvent(e);
DataSourceUtil.openBrowser( "https://ci-pw.physics.uiowa.edu/job/autoplot-release/ws/autoplot/Autoplot/src/scripts/" );
}
});
menu.addExampleAction( new AbstractAction("mashup.jyds") {
@Override
public void actionPerformed(ActionEvent e) {
LoggerManager.logGuiEvent(e);
loadExample( "/mashup.jyds" );
}
});
menu.addExampleAction( new AbstractAction("rheology.jyds") {
@Override
public void actionPerformed(ActionEvent e) {
LoggerManager.logGuiEvent(e);
loadExample( "/rheology.jyds" );
}
});
menu.addExampleAction( new AbstractAction("More Jython Data Source Scripts...") {
@Override
public void actionPerformed(ActionEvent e) {
LoggerManager.logGuiEvent(e);
DataSourceUtil.openBrowser( "https://ci-pw.physics.uiowa.edu/job/autoplot-release/ws/autoplot/JythonDataSource/src/" );
}
});
menu.setDataSetSelector(selector);
this.menu= menu;
JythonCompletionProvider.getInstance().addPropertyChangeListener( JythonCompletionProvider.PROP_MESSAGE, new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
applicationController.setStatus(JythonCompletionProvider.getInstance().getMessage());
}
});
support.addPropertyChangeListener(ScriptPanelSupport.PROP_INTERRUPTABLE,new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ( evt.getNewValue()==null ) {
//interruptButton.setIcon(
// new javax.swing.ImageIcon(
// getClass().getResource(
// "/org/autoplot/resources/stop-icon-disabled.png")) );
interruptButton.setEnabled(false);
executeButton.setEnabled(true);
} else {
//interruptButton.setIcon(
// new javax.swing.ImageIcon(
// getClass().getResource(
// "/org/autoplot/resources/stop-icon.png")) );
interruptButton.setEnabled(true);
executeButton.setEnabled(false);
}
}
} );
CompletionImpl impl = CompletionImpl.get();
impl.startPopup(this.textArea);
}
private static final String ACTIONKEY_SAVE = "save";
private static final String ACTIONKEY_EXECUTE = "execute";
/**
* load in an example, replacing the current editor text.
* @param resourceFile the name of a file loaded with
* EditorContextMenu.class.getResource(resourceFile);
*/
private void loadExample( String resourceFile ) {
try {
URL url = EditorContextMenu.class.getResource(resourceFile);
if (this.isDirty()) {
if ( this.support.saveAs()==JFileChooser.CANCEL_OPTION ) {
return;
}
}
this.support.loadInputStream(url.openStream());
if ( resourceFile.endsWith(".jy") ) {
this.setContext(CONTEXT_APPLICATION);
} else {
this.setContext(CONTEXT_DATA_SOURCE);
}
} catch (IOException ex) {
logger.log(Level.SEVERE, ex.getMessage(), ex);
}
}
protected void updateStatus() {
if ( filename==null ) {
fileNameTextField.setText( "" + ( dirty ? " *" : "" ) + ( containsTabs ? " TAB" : "" ) );
getEditorPanel().setEditable(true);
} else {
File lfile= new File(filename);
boolean writable;
try {
writable = lfile.canWrite() && !FileUtil.isParent( FileSystem.settings().getLocalCacheDir(), lfile );
} catch ( SecurityException ex ) {
writable = false;
}
getEditorPanel().setEditable(writable);
fileNameTextField.setText( filename + ( writable ? "" : " (read only)" ) + ( dirty ? " *" : "" ) + ( containsTabs ? " TAB" : "" ) ) ;
}
}
int getContext() {
return context;
}
protected final void setContext(int context) {
this.context = context;
this.contextSelector.setSelectedIndex(context);
if (context == CONTEXT_APPLICATION) {
this.textArea.putClientProperty(JythonCompletionTask.CLIENT_PROPERTY_INTERPRETER_PROVIDER, new JythonInterpreterProvider() {
@Override
public PythonInterpreter createInterpreter() throws java.io.IOException {
PythonInterpreter interp = JythonUtil.createInterpreter(true, false);
interp.set("dom", model.getDocumentModel() );
interp.set("params", new PyDictionary());
interp.set("resourceURI", Py.None );
return interp;
}
});
} else if (context == CONTEXT_DATA_SOURCE) {
this.textArea.putClientProperty(JythonCompletionTask.CLIENT_PROPERTY_INTERPRETER_PROVIDER, new JythonInterpreterProvider() {
@Override
public PythonInterpreter createInterpreter() throws java.io.IOException {
PythonInterpreter interp = JythonUtil.createInterpreter(false,false);
interp.set("params", new PyDictionary());
interp.set("resourceURI", Py.None );
return interp;
}
});
}
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// //GEN-BEGIN:initComponents
private void initComponents() {
executeButton = new javax.swing.JButton();
saveAsButton = new javax.swing.JButton();
openButton = new javax.swing.JButton();
contextSelector = new javax.swing.JComboBox();
caretPositionLabel = new javax.swing.JLabel();
jScrollPane2 = new javax.swing.JScrollPane();
textArea = new org.autoplot.jythonsupport.ui.EditorTextPane();
newScriptButton = new javax.swing.JButton();
interruptButton = new javax.swing.JButton();
fileNameTextField = new javax.swing.JTextField();
executeButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/autoplot/go.png"))); // NOI18N
executeButton.setText("Execute");
executeButton.setToolTipText("Execute script.
Alt modifier enters editor GUI.
Ctrl modifier attempts to trace program location.
Shift modifier will being up parameters gui.");
executeButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
executeButtonActionPerformed(evt);
}
});
saveAsButton.setText("Save As...");
saveAsButton.setToolTipText("Save the buffer to a local file.");
saveAsButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
saveAsButtonActionPerformed(evt);
}
});
openButton.setText("Open...");
openButton.setToolTipText("Open the local file to the buffer.");
openButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
openButtonActionPerformed(evt);
}
});
contextSelector.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Application Context", "Data Source Context" }));
contextSelector.setToolTipText("select the context for the script: to create new datasets (data source context), or to control an application (application context)\n");
contextSelector.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
contextSelectorActionPerformed(evt);
}
});
caretPositionLabel.setText("1,1");
caretPositionLabel.setToolTipText("row,column; or the number of characters and lines selected.");
textArea.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
textAreaFocusGained(evt);
}
});
jScrollPane2.setViewportView(textArea);
newScriptButton.setText("New");
newScriptButton.setToolTipText("Reset the buffer to a new file.");
newScriptButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
newScriptButtonActionPerformed(evt);
}
});
interruptButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resources/stop.png"))); // NOI18N
interruptButton.setText("Stop");
interruptButton.setToolTipText("Interrupt running script");
interruptButton.setEnabled(false);
interruptButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
interruptButtonActionPerformed(evt);
}
});
fileNameTextField.setEditable(false);
fileNameTextField.setFont(fileNameTextField.getFont().deriveFont(fileNameTextField.getFont().getSize()-2f));
fileNameTextField.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1));
org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.add(executeButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 124, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(interruptButton)
.add(7, 7, 7)
.add(saveAsButton)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(openButton)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(newScriptButton)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.add(contextSelector, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
.add(fileNameTextField)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(caretPositionLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 99, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
.add(jScrollPane2)
);
layout.setVerticalGroup(
layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
.add(layout.createSequentialGroup()
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(executeButton)
.add(contextSelector, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
.add(saveAsButton)
.add(openButton)
.add(newScriptButton)
.add(interruptButton))
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(jScrollPane2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 280, Short.MAX_VALUE)
.addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
.add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
.add(caretPositionLabel)
.add(fileNameTextField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
);
layout.linkSize(new java.awt.Component[] {executeButton, interruptButton, newScriptButton, openButton, saveAsButton}, org.jdesktop.layout.GroupLayout.VERTICAL);
}// //GEN-END:initComponents
private void executeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_executeButtonActionPerformed
org.das2.util.LoggerManager.logGuiEvent(evt);
if ( dirty && support.file!=null ) {
try {
support.save();
} catch ( IOException ex ) {
}
}
System.err.println("== Executing Script ==");
ScriptContext.setWindow(model);
if ( support.file!=null ) this.setRunningScript(support.file);
support.executeScript( evt.getModifiers() );
}//GEN-LAST:event_executeButtonActionPerformed
private void saveAsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveAsButtonActionPerformed
org.das2.util.LoggerManager.logGuiEvent(evt);
support.saveAs();
}//GEN-LAST:event_saveAsButtonActionPerformed
private void openButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openButtonActionPerformed
org.das2.util.LoggerManager.logGuiEvent(evt);
support.open();
}//GEN-LAST:event_openButtonActionPerformed
private void contextSelectorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_contextSelectorActionPerformed
org.das2.util.LoggerManager.logGuiEvent(evt);
setContext(contextSelector.getSelectedIndex());
}//GEN-LAST:event_contextSelectorActionPerformed
private void textAreaFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_textAreaFocusGained
CompletionImpl impl = CompletionImpl.get();
impl.startPopup(textArea);
}//GEN-LAST:event_textAreaFocusGained
private void newScriptButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newScriptButtonActionPerformed
org.das2.util.LoggerManager.logGuiEvent(evt);
support.newScript();
}//GEN-LAST:event_newScriptButtonActionPerformed
private void interruptButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_interruptButtonActionPerformed
org.das2.util.LoggerManager.logGuiEvent(evt);
support.interrupt();
}//GEN-LAST:event_interruptButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel caretPositionLabel;
private javax.swing.JComboBox contextSelector;
private javax.swing.JButton executeButton;
private javax.swing.JTextField fileNameTextField;
private javax.swing.JButton interruptButton;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JButton newScriptButton;
private javax.swing.JButton openButton;
private javax.swing.JButton saveAsButton;
private org.autoplot.jythonsupport.ui.EditorTextPane textArea;
// End of variables declaration//GEN-END:variables
/**
* returns the editor
* @return the editor
*/
public EditorTextPane getEditorPanel() {
return textArea;
}
Pattern jythonRefPattern = Pattern.compile("\\s*((\\S+\\.jy(ds)?|\\)\\:(\\d+))");
/**
* return action listener listening for action commands containing source:linenum
* @return
*/
public ActionListener getConsoleListener() {
return (ActionEvent e) -> {
String printline= e.getActionCommand();
Matcher jythonMatcher= jythonRefPattern.matcher(printline);
if ( jythonMatcher.find() ) {
String jythonRef= jythonMatcher.group(1);
String currentFilename= this.filename==null ? "" : this.filename;
String messageSource= jythonMatcher.group(2);
if ( messageSource.contains("/") ) {
int iff= messageSource.lastIndexOf("/");
if ( currentFilename.endsWith( messageSource.substring(iff) ) ) {
File ff= DataSetURI.getCacheFilename(DataSetURI.getResourceURI(messageSource));
messageSource= ff.toString();
}
}
if ( currentFilename.endsWith(messageSource) ) {
int line= Integer.parseInt(jythonMatcher.group(4));
try {
this.support.annotationsSupport.annotateLine( line, EditorAnnotationsSupport.ANNO_CODE_HINT, printline );
} catch (BadLocationException ex) {
}
}
jythonRef=null;
}
};
}
/**
* returns the JScrollPane containing the editor so that special applications can control what's visible.
* @return the JScrollPane containing the editor
*/
public JScrollPane getScrollPane() {
return jScrollPane2;
}
protected String filename = null;
public static final String PROP_FILENAME = "filename";
public String getFilename() {
return filename;
}
public void setFilename(final String filename) {
String oldFilename = this.filename;
this.filename = filename;
if ( filename!=oldFilename && ( oldFilename==null || !oldFilename.equals(filename) ) ) {
if ( filename!=null ) {
final File loadFile= new File(filename);
Runnable r= new Runnable() {
@Override
public void run() {
try {
loadFile(loadFile);
} catch (IOException ex) {
Logger.getLogger(JythonScriptPanel.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
new Thread(r,"loadScript603").start();
}
}
updateStatus();
firePropertyChange(PROP_FILENAME, oldFilename, filename);
}
protected boolean dirty = false;
public static final String PROP_DIRTY = "dirty";
public boolean isDirty() {
return dirty;
}
/**
* set the flag indicating the script has been modified.
* @param dirty
*/
public void setDirty(boolean dirty) {
boolean oldDirty = this.dirty;
this.dirty = dirty;
if ( oldDirty!=dirty ) updateStatus();
firePropertyChange(PROP_DIRTY, oldDirty, dirty);
}
/**
* reset the undo history.
*/
public void resetUndo() {
Document doc= textArea.getDocument();
if ( doc instanceof SyntaxDocument ) {
((SyntaxDocument)textArea.getDocument()).resetUndo();
}
}
/**
* allow clients to tell this to load a file.
* @param file the .jy or .jyds file.
* @return false if the editor is dirty, true if the file is loaded.
* @throws java.io.IOException
*/
public boolean loadFile( File file ) throws IOException {
if ( isDirty() ) {
return false;
} else {
support.loadFile(file);
return true;
}
}
/**
* provide access to the annotations support, so that errors
* can be marked on the editor. This may cause bugs as there
* are issues like ensuring the exception marked belongs to the code,
* and it should not be used without reservation.
*
* @return the annotations support.
*/
public EditorAnnotationsSupport getAnnotationsSupport() {
return support.annotationsSupport;
}
/**
* add the menu or menu item to the editor context menu.
* @param menu
*/
public void addMenuItem( JMenuItem menu ) {
this.menu.addMenuItem(menu);
}
/**
* set the current script that is running. This will prevent
* automatic loads from occurring.
* @param f
*/
public void setRunningScript( File f ) {
this.runningScript= f;
}
/**
* return the name of the script that the panel is busy running, or null.
* When this is non-null, don't load other scripts.
* @return null or the running script.
*/
public File getRunningScript() {
return this.runningScript;
}
}