using jsyntaxpane as javascript editor, added ui controls to link test scripts to a file on disk

This commit is contained in:
Fredrik Osterlind 2012-03-21 16:59:08 +01:00
parent 7cfa8e28d3
commit dcd0460e0b

View file

@ -32,6 +32,7 @@
package se.sics.cooja.plugins; package se.sics.cooja.plugins;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Window; import java.awt.Window;
@ -53,9 +54,12 @@ import java.util.Observer;
import javax.script.ScriptException; import javax.script.ScriptException;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
@ -63,8 +67,10 @@ import javax.swing.JPopupMenu;
import javax.swing.JScrollPane; import javax.swing.JScrollPane;
import javax.swing.JSplitPane; import javax.swing.JSplitPane;
import javax.swing.JTextArea; import javax.swing.JTextArea;
import javax.swing.event.DocumentEvent; import javax.swing.filechooser.FileFilter;
import javax.swing.event.DocumentListener;
import jsyntaxpane.DefaultSyntaxKit;
import jsyntaxpane.actions.DefaultSyntaxAction;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.jdom.Element; import org.jdom.Element;
@ -83,6 +89,10 @@ public class ScriptRunner extends VisPlugin {
private static final long serialVersionUID = 7614358340336799109L; private static final long serialVersionUID = 7614358340336799109L;
private static Logger logger = Logger.getLogger(ScriptRunner.class); private static Logger logger = Logger.getLogger(ScriptRunner.class);
{
DefaultSyntaxKit.initKit();
}
final String[] EXAMPLE_SCRIPTS = new String[] { final String[] EXAMPLE_SCRIPTS = new String[] {
"basic.js", "Various commands", "basic.js", "Various commands",
"helloworld.js", "Wait for 'Hello, world'", "helloworld.js", "Wait for 'Hello, world'",
@ -97,24 +107,19 @@ public class ScriptRunner extends VisPlugin {
private static BufferedWriter logWriter = null; /* For non-GUI tests */ private static BufferedWriter logWriter = null; /* For non-GUI tests */
private JTextArea scriptTextArea = null; private JEditorPane codeEditor = null;
private JTextArea logTextArea = null; private JTextArea logTextArea = null;
private JButton toggleButton = null; private JButton toggleButton = null;
private JButton examplesButton = null; private JButton examplesButton = null;
private int scriptFirstLinesNumber; private JSyntaxLinkFile actionLinkFile = null;
private File linkedFile = null;
public ScriptRunner(Simulation simulation, GUI gui) { public ScriptRunner(Simulation simulation, GUI gui) {
super("Contiki Test Editor", gui, false); super("Contiki Test Editor", gui, false);
this.simulation = simulation; this.simulation = simulation;
final JTextArea lineTextArea = new JTextArea();
lineTextArea.setEnabled(false);
lineTextArea.setMargin(new Insets(5,0,5,0));
scriptFirstLinesNumber = 1;
/* Examples popup menu */ /* Examples popup menu */
final JPopupMenu popupMenu = new JPopupMenu(); final JPopupMenu popupMenu = new JPopupMenu();
JMenuItem moteItem; JMenuItem moteItem;
@ -148,65 +153,19 @@ public class ScriptRunner extends VisPlugin {
} }
}); });
{
/* Workaround to configure jsyntaxpane */
JEditorPane e = new JEditorPane();
new JScrollPane(e);
e.setContentType("text/javascript");
DefaultSyntaxKit kit = (DefaultSyntaxKit) e.getEditorKit();
kit.setProperty("PopupMenu", "copy-to-clipboard,-,find,find-next,goto-line,-,linkfile");
kit.setProperty("Action.linkfile", JSyntaxLinkFile.class.getName());
}
/* Script area */ /* Script area */
scriptTextArea = new JTextArea(12,50); setLayout(new BorderLayout());
scriptTextArea.getDocument().addDocumentListener(new DocumentListener() { codeEditor = new JEditorPane();
private int lastLines = -1;
private void update() {
int lines = scriptTextArea.getLineCount() + scriptFirstLinesNumber;
if (lines == lastLines) {
return;
}
lastLines = lines;
String txt = "";
for (int i=scriptFirstLinesNumber; i < 10; i++) {
if (i > lines) {
break;
}
txt += "00" + i + "\n";
}
for (int i=10; i < 100; i++) {
if (i > lines) {
break;
}
txt += "0" + i + "\n";
}
for (int i=100; i < 1000; i++) {
if (i > lines) {
break;
}
txt += i + "\n";
}
lineTextArea.setText(txt);
/*ScriptParser parser;
try {
parser = new ScriptParser(scriptTextArea.getText());
String tooltip = parser.getJSCode();
tooltip = tooltip.replaceAll("\n", "<br>");
tooltip = "<html><b>Generated code:</b><p>" + tooltip + "</html>";
lineTextArea.setToolTipText(tooltip);
} catch (ScriptSyntaxErrorException e) {
lineTextArea.setToolTipText("Unable to generate code: " + e.getMessage());
}*/
}
public void changedUpdate(DocumentEvent e) {
update();
}
public void insertUpdate(DocumentEvent e) {
update();
}
public void removeUpdate(DocumentEvent e) {
update();
}
});
scriptTextArea.setMargin(new Insets(5,0,5,5));
scriptTextArea.setEditable(true);
scriptTextArea.setCursor(null);
scriptTextArea.setTabSize(1);
logTextArea = new JTextArea(12,50); logTextArea = new JTextArea(12,50);
logTextArea.setMargin(new Insets(5,5,5,5)); logTextArea.setMargin(new Insets(5,5,5,5));
@ -231,16 +190,30 @@ public class ScriptRunner extends VisPlugin {
} }
}); });
JPanel scriptArea = new JPanel(new BorderLayout()); doLayout();
scriptArea.setEnabled(false);
scriptArea.add(BorderLayout.WEST, lineTextArea);
scriptArea.add(BorderLayout.CENTER, scriptTextArea);
JSplitPane centerPanel = new JSplitPane( JSplitPane centerPanel = new JSplitPane(
JSplitPane.VERTICAL_SPLIT, JSplitPane.VERTICAL_SPLIT,
new JScrollPane(scriptArea), new JScrollPane(codeEditor),
new JScrollPane(logTextArea) new JScrollPane(logTextArea)
); );
codeEditor.setContentType("text/javascript");
DefaultSyntaxKit kit = (DefaultSyntaxKit) codeEditor.getEditorKit();
kit.setProperty("PopupMenu", "copy-to-clipboard,-,find,find-next,goto-line,-,linkfile");
kit.setProperty("Action.linkfile", JSyntaxLinkFile.class.getName());
JPopupMenu p = codeEditor.getComponentPopupMenu();
for (Component c: p.getComponents()) {
if (c instanceof JMenuItem) {
if (((JMenuItem) c).getAction() != null &&
((JMenuItem) c).getAction() instanceof JSyntaxLinkFile) {
actionLinkFile = (JSyntaxLinkFile)(((JMenuItem) c).getAction());
actionLinkFile.setMenuText("Link script to disk file");
actionLinkFile.putValue("ScriptRunner", this);
}
}
}
centerPanel.setOneTouchExpandable(true); centerPanel.setOneTouchExpandable(true);
centerPanel.setResizeWeight(0.5); centerPanel.setResizeWeight(0.5);
@ -271,21 +244,43 @@ public class ScriptRunner extends VisPlugin {
} }
} }
public void setLinkFile(File source) {
linkedFile = source;
if (source == null) {
updateScript("");
actionLinkFile.setMenuText("Link script to disk file");
actionLinkFile.putValue("JavascriptSource", null);
codeEditor.setEditable(true);
} else {
updateScript(linkedFile);
actionLinkFile.setMenuText("Unlink script: " + source.getName());
actionLinkFile.putValue("JavascriptSource", source);
codeEditor.setEditable(false);
}
updateTitle();
}
public void setScriptActive(boolean active) { public void setScriptActive(boolean active) {
if (active) {
/* setScriptActive(true) */
/* Free any resources */
setScriptActive(false);
/* Reload script from file */ /* Reload script from file */
if (scriptFile != null) { if (linkedFile != null) {
String script = StringUtils.loadFromFile(scriptFile); String script = StringUtils.loadFromFile(linkedFile);
if (script == null) { if (script == null) {
logger.fatal("Failed to load script from: " + scriptFile.getAbsolutePath()); logger.fatal("Failed to load script from: " + linkedFile.getAbsolutePath());
} else { } else {
updateScript(script); updateScript(script);
} }
} }
if (active) {
/* Free any resources */
setScriptActive(false);
/* Create new engine */ /* Create new engine */
engine = new LogScriptEngine(simulation); engine = new LogScriptEngine(simulation);
if (GUI.isVisualized()) { if (GUI.isVisualized()) {
@ -331,14 +326,14 @@ public class ScriptRunner extends VisPlugin {
/* Activate engine */ /* Activate engine */
try { try {
engine.activateScript(scriptTextArea.getText()); engine.activateScript(codeEditor.getText());
actionLinkFile.setEnabled(false);
toggleButton.setText("Deactivate"); toggleButton.setText("Deactivate");
examplesButton.setEnabled(false); examplesButton.setEnabled(false);
logTextArea.setText(""); logTextArea.setText("");
scriptTextArea.setEnabled(false); codeEditor.setEnabled(false);
setTitle("Contiki Test Editor (ACTIVE) " updateTitle();
+ (scriptFile==null?"":" (" + scriptFile.getName() + ")"));
logger.info("Test script activated"); logger.info("Test script activated");
@ -355,14 +350,14 @@ public class ScriptRunner extends VisPlugin {
} }
} else { } else {
if (engine == null) { /* setScriptActive(false) */
return;
}
if (engine != null) {
/* Deactivate script */ /* Deactivate script */
engine.deactivateScript(); engine.deactivateScript();
engine.setScriptLogObserver(null); engine.setScriptLogObserver(null);
engine = null; engine = null;
}
if (logWriter != null) { if (logWriter != null) {
try { try {
@ -376,15 +371,26 @@ public class ScriptRunner extends VisPlugin {
logWriter = null; logWriter = null;
} }
actionLinkFile.setEnabled(true);
toggleButton.setText("Activate"); toggleButton.setText("Activate");
examplesButton.setEnabled(true); examplesButton.setEnabled(linkedFile==null?true:false);
scriptTextArea.setEnabled(scriptFile==null?true:false); codeEditor.setEnabled(true);
logger.info("Test script deactivated"); logger.info("Test script deactivated");
setTitle("Contiki Test Editor" updateTitle();
+ (scriptFile==null?"":" (" + scriptFile.getName() + ")"));
} }
} }
private void updateTitle() {
String title = "Contiki Test Editor ";
if (linkedFile != null) {
title += ": " + linkedFile.getName() + " ";
}
if (isActive()) {
title += "(ACTIVE) ";
}
setTitle(title);
}
private void exportAndRun() { private void exportAndRun() {
/* Save simulation config */ /* Save simulation config */
File configFile = simulation.getGUI().doSaveConfig(true); File configFile = simulation.getGUI().doSaveConfig(true);
@ -558,7 +564,7 @@ public class ScriptRunner extends VisPlugin {
return; return;
} }
scriptTextArea.setText(script); codeEditor.setText(script);
logTextArea.setText(""); logTextArea.setText("");
} }
@ -566,29 +572,32 @@ public class ScriptRunner extends VisPlugin {
ArrayList<Element> config = new ArrayList<Element>(); ArrayList<Element> config = new ArrayList<Element>();
Element element; Element element;
if (scriptFile != null) { if (linkedFile != null) {
element = new Element("scriptfile"); element = new Element("scriptfile");
element.setText(simulation.getGUI().createPortablePath(scriptFile).getPath().replace('\\', '/')); element.setText(simulation.getGUI().createPortablePath(linkedFile).getPath().replace('\\', '/'));
config.add(element); config.add(element);
/*StringUtils.saveToFile(scriptFile, scriptTextArea.getText());*/ /*StringUtils.saveToFile(scriptFile, scriptTextArea.getText());*/
} else { } else {
element = new Element("script"); element = new Element("script");
element.setText(scriptTextArea.getText()); element.setText(codeEditor.getText());
config.add(element); config.add(element);
} }
element = new Element("active"); element = new Element("active");
element.setText("" + (engine != null)); element.setText("" + isActive());
config.add(element); config.add(element);
return config; return config;
} }
public boolean isActive() {
return engine != null;
}
public void closePlugin() { public void closePlugin() {
setScriptActive(false); setScriptActive(false);
} }
private File scriptFile = null;
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) { public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
for (Element element : configXML) { for (Element element : configXML) {
String name = element.getName(); String name = element.getName();
@ -598,14 +607,7 @@ public class ScriptRunner extends VisPlugin {
} }
} else if ("scriptfile".equals(name)) { } else if ("scriptfile".equals(name)) {
File file = simulation.getGUI().restorePortablePath(new File(element.getText().trim())); File file = simulation.getGUI().restorePortablePath(new File(element.getText().trim()));
String script = StringUtils.loadFromFile(file); setLinkFile(file);
if (script == null) {
logger.fatal("Failed to load script from: " + file.getAbsolutePath());
} else {
updateScript(script);
}
scriptFile = file;
scriptTextArea.setEnabled(false);
} else if ("active".equals(name)) { } else if ("active".equals(name)) {
boolean active = Boolean.parseBoolean(element.getText()); boolean active = Boolean.parseBoolean(element.getText());
if (GUI.isVisualized()) { if (GUI.isVisualized()) {
@ -627,4 +629,45 @@ public class ScriptRunner extends VisPlugin {
return StringUtils.loadFromURL(ScriptRunner.class.getResource("/scripts/" + file)); return StringUtils.loadFromURL(ScriptRunner.class.getResource("/scripts/" + file));
} }
public static class JSyntaxLinkFile extends DefaultSyntaxAction {
private static Logger logger = Logger.getLogger(JSyntaxLinkFile.class);
public JSyntaxLinkFile() {
super("linkfile");
}
public void actionPerformed(ActionEvent e) {
JMenuItem menuItem = (JMenuItem) e.getSource();
Action action = menuItem.getAction();
ScriptRunner scriptRunner = (ScriptRunner) action.getValue("ScriptRunner");
File currentSource = (File) action.getValue("JavascriptSource");
if (currentSource != null) {
scriptRunner.setLinkFile(null);
return;
}
JFileChooser fileChooser = new JFileChooser();
fileChooser.setCurrentDirectory(new java.io.File("."));
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
fileChooser.setDialogTitle("Select script file");
fileChooser.setFileFilter(new FileFilter() {
public boolean accept(File file) {
if (file.isDirectory()) { return true; }
if (file.getName().endsWith(".js")) {
return true;
}
return false;
}
public String getDescription() {
return "Javascript";
}
});
if (fileChooser.showOpenDialog(scriptRunner) != JFileChooser.APPROVE_OPTION) {
logger.debug("cancel");
return;
}
scriptRunner.setLinkFile(fileChooser.getSelectedFile());
}
}
} }