using jsyntaxpane as javascript editor, added ui controls to link test scripts to a file on disk
This commit is contained in:
parent
7cfa8e28d3
commit
dcd0460e0b
1 changed files with 159 additions and 116 deletions
|
@ -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 setScriptActive(boolean active) {
|
public void setLinkFile(File source) {
|
||||||
/* Reload script from file */
|
linkedFile = source;
|
||||||
if (scriptFile != null) {
|
if (source == null) {
|
||||||
String script = StringUtils.loadFromFile(scriptFile);
|
updateScript("");
|
||||||
if (script == null) {
|
|
||||||
logger.fatal("Failed to load script from: " + scriptFile.getAbsolutePath());
|
|
||||||
} else {
|
|
||||||
updateScript(script);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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) {
|
||||||
if (active) {
|
if (active) {
|
||||||
|
/* setScriptActive(true) */
|
||||||
|
|
||||||
/* Free any resources */
|
/* Free any resources */
|
||||||
setScriptActive(false);
|
setScriptActive(false);
|
||||||
|
|
||||||
|
/* Reload script from file */
|
||||||
|
if (linkedFile != null) {
|
||||||
|
String script = StringUtils.loadFromFile(linkedFile);
|
||||||
|
if (script == null) {
|
||||||
|
logger.fatal("Failed to load script from: " + linkedFile.getAbsolutePath());
|
||||||
|
} else {
|
||||||
|
updateScript(script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Deactivate script */
|
if (engine != null) {
|
||||||
engine.deactivateScript();
|
/* Deactivate script */
|
||||||
engine.setScriptLogObserver(null);
|
engine.deactivateScript();
|
||||||
engine = null;
|
engine.setScriptLogObserver(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());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue