reworked MspCodeWatcher plugin: using jsyntaxpane to display Contiki code, using tabs instead of splitpanes, easier to
configure watch-/breakpoints, lots of bug fixes and minor improvements
This commit is contained in:
parent
2e583c733e
commit
7cfa8e28d3
5 changed files with 616 additions and 791 deletions
|
@ -31,26 +31,32 @@
|
|||
|
||||
package se.sics.cooja.mspmote.plugins;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JColorChooser;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
import javax.swing.table.TableCellEditor;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import se.sics.cooja.GUI;
|
||||
import se.sics.cooja.Mote;
|
||||
import se.sics.cooja.MoteType;
|
||||
import se.sics.cooja.Simulation;
|
||||
import se.sics.cooja.mspmote.MspMote;
|
||||
import se.sics.cooja.Watchpoint;
|
||||
import se.sics.cooja.WatchpointMote;
|
||||
|
||||
/**
|
||||
* Displays a set of breakpoints.
|
||||
|
@ -60,27 +66,27 @@ import se.sics.cooja.mspmote.MspMote;
|
|||
public class BreakpointsUI extends JPanel {
|
||||
private static Logger logger = Logger.getLogger(BreakpointsUI.class);
|
||||
|
||||
private static final int COLUMN_INFO = 0;
|
||||
private static final int COLUMN_ADDRESS = 1;
|
||||
private static final int COLUMN_FILELINE = 2;
|
||||
private static final int COLUMN_ADDRESS = 0;
|
||||
private static final int COLUMN_FILELINE = 1;
|
||||
private static final int COLUMN_INFO = 2;
|
||||
private static final int COLUMN_STOP = 3;
|
||||
private static final int COLUMN_REMOVE = 4;
|
||||
|
||||
private static final String[] COLUMN_NAMES = {
|
||||
"Info",
|
||||
"Address",
|
||||
"File",
|
||||
"Stop",
|
||||
"Remove"
|
||||
"Source",
|
||||
"Info",
|
||||
"Stops simulation"
|
||||
};
|
||||
|
||||
private MspBreakpointContainer breakpoints = null;
|
||||
private WatchpointMote mote;
|
||||
private MspCodeWatcher codeWatcher;
|
||||
private JTable table = null;
|
||||
|
||||
private MspBreakpoint popupBreakpoint = null;
|
||||
private Watchpoint selectedWatchpoint = null;
|
||||
|
||||
public BreakpointsUI(MspBreakpointContainer breakpoints, final MspCodeWatcher codeWatcher) {
|
||||
this.breakpoints = breakpoints;
|
||||
public BreakpointsUI(WatchpointMote mote, final MspCodeWatcher codeWatcher) {
|
||||
this.mote = mote;
|
||||
this.codeWatcher = codeWatcher;
|
||||
|
||||
/* Breakpoints table */
|
||||
table = new JTable(tableModel) {
|
||||
|
@ -93,15 +99,20 @@ public class BreakpointsUI extends JPanel {
|
|||
int realColumnIndex = table.convertColumnIndexToModel(colIndex);
|
||||
|
||||
if (realColumnIndex == COLUMN_FILELINE) {
|
||||
MspBreakpoint[] allBreakpoints = BreakpointsUI.this.breakpoints.getBreakpoints();
|
||||
Watchpoint[] allBreakpoints = BreakpointsUI.this.mote.getBreakpoints();
|
||||
if (rowIndex < 0 || rowIndex >= allBreakpoints.length) {
|
||||
return null;
|
||||
}
|
||||
File file = allBreakpoints[rowIndex].getCodeFile();
|
||||
Watchpoint watchpoint = allBreakpoints[rowIndex];
|
||||
File file = watchpoint.getCodeFile();
|
||||
if (file == null) {
|
||||
return null;
|
||||
return String.format("[unknown @ 0x%04x]", watchpoint.getExecutableAddress());
|
||||
}
|
||||
return file.getPath() + ":" + allBreakpoints[rowIndex].getLineNumber();
|
||||
Integer line = watchpoint.getLineNumber();
|
||||
if (line == null) {
|
||||
return file.getPath() + ":?";
|
||||
}
|
||||
return file.getPath() + ":" + line;
|
||||
}
|
||||
|
||||
if (realColumnIndex == COLUMN_INFO) {
|
||||
|
@ -111,53 +122,41 @@ public class BreakpointsUI extends JPanel {
|
|||
if (realColumnIndex == COLUMN_STOP) {
|
||||
return "Indicates whether the watchpoint will stop the simulation when triggered";
|
||||
}
|
||||
|
||||
if (realColumnIndex == COLUMN_REMOVE) {
|
||||
return "Remove breakpoint from this mote only. (Right-click for more options)";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
||||
table.getColumnModel().getColumn(COLUMN_ADDRESS).setPreferredWidth(60); /* XXX */
|
||||
table.getColumnModel().getColumn(COLUMN_ADDRESS).setMaxWidth(60);
|
||||
table.getColumnModel().getColumn(COLUMN_INFO).setPreferredWidth(60);
|
||||
table.getColumnModel().getColumn(COLUMN_INFO).setMaxWidth(60);
|
||||
table.getColumnModel().getColumn(COLUMN_INFO).setCellRenderer(
|
||||
new DefaultTableCellRenderer() {
|
||||
public Component getTableCellRendererComponent(JTable table, Object value,
|
||||
boolean isSelected, boolean hasFocus, int row, int column) {
|
||||
Component c = super.getTableCellRendererComponent(
|
||||
table, value, isSelected, hasFocus, row, column);
|
||||
if (column != COLUMN_INFO) {
|
||||
return c;
|
||||
}
|
||||
|
||||
MspBreakpoint[] allBreakpoints = BreakpointsUI.this.breakpoints.getBreakpoints();
|
||||
if (row < 0 || row >= allBreakpoints.length) {
|
||||
return c;
|
||||
}
|
||||
MspBreakpoint breakpoint = allBreakpoints[row];
|
||||
if (breakpoint.getColor() == null) {
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Use watchpoint color */
|
||||
c.setForeground(breakpoint.getColor());
|
||||
return c;
|
||||
}
|
||||
});
|
||||
table.getColumnModel().getColumn(COLUMN_STOP).setPreferredWidth(60);
|
||||
table.getColumnModel().getColumn(COLUMN_STOP).setMaxWidth(60);
|
||||
table.getColumnModel().getColumn(COLUMN_REMOVE).setPreferredWidth(60);
|
||||
table.getColumnModel().getColumn(COLUMN_REMOVE).setMaxWidth(60);
|
||||
table.getColumnModel().getColumn(COLUMN_INFO).setCellRenderer(new DefaultTableCellRenderer() {
|
||||
public Component getTableCellRendererComponent(JTable table, Object value,
|
||||
boolean isSelected, boolean hasFocus, int row, int column) {
|
||||
Component c = super.getTableCellRendererComponent(
|
||||
table, value, isSelected, hasFocus, row, column);
|
||||
if (column != COLUMN_INFO) {
|
||||
return c;
|
||||
}
|
||||
|
||||
Watchpoint[] allBreakpoints = BreakpointsUI.this.mote.getBreakpoints();
|
||||
if (row < 0 || row >= allBreakpoints.length) {
|
||||
return c;
|
||||
}
|
||||
Watchpoint breakpoint = allBreakpoints[row];
|
||||
if (breakpoint.getColor() == null) {
|
||||
return c;
|
||||
}
|
||||
|
||||
/* Use watchpoint color */
|
||||
c.setBackground(Color.WHITE);
|
||||
c.setForeground(breakpoint.getColor());
|
||||
return c;
|
||||
}
|
||||
});
|
||||
|
||||
/* Popup menu: register on all motes */
|
||||
final JPopupMenu popupMenu = new JPopupMenu();
|
||||
popupMenu.add(new JMenuItem(addToMoteTypeAction));
|
||||
popupMenu.add(new JMenuItem(delFromMoteTypeAction));
|
||||
popupMenu.add(new JMenuItem(gotoCodeAction));
|
||||
popupMenu.add(new JSeparator());
|
||||
popupMenu.add(new JMenuItem(removeWatchpointAction));
|
||||
popupMenu.add(new JMenuItem(configureWatchpointAction));
|
||||
|
||||
/* Show source file on breakpoint mouse click */
|
||||
table.addMouseListener(new MouseAdapter() {
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
java.awt.Point p = e.getPoint();
|
||||
|
@ -167,63 +166,32 @@ public class BreakpointsUI extends JPanel {
|
|||
|
||||
if (realColumnIndex != COLUMN_ADDRESS
|
||||
&& realColumnIndex != COLUMN_FILELINE
|
||||
&& realColumnIndex != COLUMN_REMOVE
|
||||
&& realColumnIndex != COLUMN_INFO) {
|
||||
return;
|
||||
}
|
||||
|
||||
MspBreakpoint[] allBreakpoints = BreakpointsUI.this.breakpoints.getBreakpoints();
|
||||
Watchpoint[] allBreakpoints = BreakpointsUI.this.mote.getBreakpoints();
|
||||
if (rowIndex < 0 || rowIndex >= allBreakpoints.length) {
|
||||
return;
|
||||
}
|
||||
MspBreakpoint breakpoint = allBreakpoints[rowIndex];
|
||||
Watchpoint breakpoint = allBreakpoints[rowIndex];
|
||||
|
||||
if (e.isPopupTrigger() || SwingUtilities.isRightMouseButton(e)) {
|
||||
popupBreakpoint = breakpoint;
|
||||
selectedWatchpoint = breakpoint;
|
||||
popupMenu.show(table, e.getX(), e.getY());
|
||||
return;
|
||||
}
|
||||
|
||||
if (realColumnIndex == COLUMN_INFO) {
|
||||
String msg = JOptionPane.showInputDialog(
|
||||
GUI.getTopParentContainer(),
|
||||
"Enter description",
|
||||
"Watchpoint Description",
|
||||
JOptionPane.QUESTION_MESSAGE);
|
||||
if (msg != null) {
|
||||
breakpoint.setUserMessage(msg);
|
||||
}
|
||||
Color newColor = JColorChooser.showDialog(
|
||||
GUI.getTopParentContainer(),
|
||||
"Watchpoint Color",
|
||||
breakpoint.getColor());
|
||||
if (newColor != null) {
|
||||
breakpoint.setColor(newColor);
|
||||
}
|
||||
configureWatchpointInfo(breakpoint);
|
||||
return;
|
||||
}
|
||||
|
||||
File file = allBreakpoints[rowIndex].getCodeFile();
|
||||
/*File file = allBreakpoints[rowIndex].getCodeFile();
|
||||
int line = allBreakpoints[rowIndex].getLineNumber();
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Display source code */
|
||||
codeWatcher.displaySourceFile(file, line);
|
||||
}
|
||||
});
|
||||
|
||||
/* Update when breakpoints are triggered/added/removed */
|
||||
breakpoints.addWatchpointListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
MspBreakpoint triggered = BreakpointsUI.this.breakpoints.getLastWatchpoint();
|
||||
if (triggered == null) {
|
||||
table.repaint();
|
||||
return;
|
||||
}
|
||||
|
||||
flashBreakpoint(triggered);
|
||||
}*/
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -232,24 +200,41 @@ public class BreakpointsUI extends JPanel {
|
|||
add(BorderLayout.CENTER, table);
|
||||
}
|
||||
|
||||
private void flashBreakpoint(MspBreakpoint breakpoint) {
|
||||
/* Locate breakpoints table index */
|
||||
int index = -1;
|
||||
MspBreakpoint[] all = breakpoints.getBreakpoints();
|
||||
for (int i=0; i < breakpoints.getBreakpointsCount(); i++) {
|
||||
if (breakpoint == all[i]) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index < 0) {
|
||||
private void configureWatchpointInfo(Watchpoint breakpoint) {
|
||||
String msg = (String) JOptionPane.showInputDialog(
|
||||
GUI.getTopParentContainer(),
|
||||
"Enter description;",
|
||||
"Watchpoint description",
|
||||
JOptionPane.QUESTION_MESSAGE, null, null, breakpoint.getUserMessage());
|
||||
if (msg == null) {
|
||||
return;
|
||||
}
|
||||
breakpoint.setUserMessage(msg);
|
||||
Color newColor = JColorChooser.showDialog(
|
||||
GUI.getTopParentContainer(),
|
||||
"Watchpoint color",
|
||||
breakpoint.getColor());
|
||||
if (newColor == null) {
|
||||
return;
|
||||
}
|
||||
breakpoint.setColor(newColor);
|
||||
}
|
||||
|
||||
final int breakpointIndex = index;
|
||||
public void selectBreakpoint(final Watchpoint breakpoint) {
|
||||
if (breakpoint == null) {
|
||||
return;
|
||||
}
|
||||
/* Locate breakpoints table index */
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
table.setRowSelectionInterval(breakpointIndex, breakpointIndex);
|
||||
Watchpoint[] watchpoints = mote.getBreakpoints();
|
||||
for (int i=0; i < watchpoints.length; i++) {
|
||||
if (breakpoint == watchpoints[i]) {
|
||||
/* Select */
|
||||
table.setRowSelectionInterval(i, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -259,18 +244,18 @@ public class BreakpointsUI extends JPanel {
|
|||
return COLUMN_NAMES[col].toString();
|
||||
}
|
||||
public int getRowCount() {
|
||||
return breakpoints.getBreakpointsCount();
|
||||
return mote.getBreakpoints().length;
|
||||
}
|
||||
public int getColumnCount() {
|
||||
return COLUMN_NAMES.length;
|
||||
}
|
||||
public Object getValueAt(int row, int col) {
|
||||
MspBreakpoint breakpoint = breakpoints.getBreakpoints()[row];
|
||||
Watchpoint breakpoint = mote.getBreakpoints()[row];
|
||||
|
||||
/* Executable address in hexadecimal */
|
||||
if (col == COLUMN_ADDRESS) {
|
||||
Integer address = breakpoint.getExecutableAddress();
|
||||
return "0x" + Integer.toHexString(address.intValue());
|
||||
return String.format("0x%04x", address.intValue());
|
||||
}
|
||||
|
||||
/* Source file + line number */
|
||||
|
@ -300,7 +285,7 @@ public class BreakpointsUI extends JPanel {
|
|||
return getColumnClass(col) == Boolean.class;
|
||||
}
|
||||
public void setValueAt(Object value, int row, int col) {
|
||||
MspBreakpoint breakpoint = breakpoints.getBreakpoints()[row];
|
||||
Watchpoint breakpoint = mote.getBreakpoints()[row];
|
||||
|
||||
if (col == COLUMN_STOP) {
|
||||
/* Toggle stop state */
|
||||
|
@ -308,109 +293,36 @@ public class BreakpointsUI extends JPanel {
|
|||
fireTableCellUpdated(row, col);
|
||||
return;
|
||||
}
|
||||
|
||||
if (col == COLUMN_REMOVE) {
|
||||
/* Remove breakpoint */
|
||||
Integer address = breakpoint.getExecutableAddress();
|
||||
breakpoints.removeBreakpoint(address);
|
||||
fireTableCellUpdated(row, col);
|
||||
return;
|
||||
}
|
||||
}
|
||||
public Class<?> getColumnClass(int c) {
|
||||
return getValueAt(0, c).getClass();
|
||||
}
|
||||
};
|
||||
|
||||
private Action addToMoteTypeAction = new AbstractAction("Register on all motes (mote type)") {
|
||||
private Action gotoCodeAction = new AbstractAction("Show in source code") {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (popupBreakpoint == null) {
|
||||
logger.fatal("No breakpoint to add");
|
||||
if (selectedWatchpoint == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Extract all motes of the same mote type */
|
||||
Simulation sim = popupBreakpoint.getMote().getSimulation();
|
||||
MoteType type = popupBreakpoint.getMote().getType();
|
||||
ArrayList<MspMote> motes = new ArrayList<MspMote>();
|
||||
for (Mote m: sim.getMotes()) {
|
||||
if (m.getType() == type) {
|
||||
if (!(m instanceof MspMote)) {
|
||||
logger.fatal("At least one mote was not a MSP mote: " + m);
|
||||
return;
|
||||
}
|
||||
|
||||
motes.add((MspMote)m);
|
||||
}
|
||||
}
|
||||
|
||||
/* Register breakpoints */
|
||||
int reregistered = 0;
|
||||
for (MspMote m: motes) {
|
||||
/* Avoid duplicates (match executable addresses) */
|
||||
MspBreakpointContainer container = m.getBreakpointsContainer();
|
||||
MspBreakpoint[] breakpoints = container.getBreakpoints();
|
||||
for (MspBreakpoint w: breakpoints) {
|
||||
if (popupBreakpoint.getExecutableAddress().intValue() ==
|
||||
w.getExecutableAddress().intValue()) {
|
||||
logger.info("Reregistering breakpoint at mote: " + m);
|
||||
container.removeBreakpoint(w.getExecutableAddress());
|
||||
reregistered++;
|
||||
}
|
||||
}
|
||||
|
||||
MspBreakpoint newBreakpoint = container.addBreakpoint(
|
||||
popupBreakpoint.getCodeFile(),
|
||||
popupBreakpoint.getLineNumber(),
|
||||
popupBreakpoint.getExecutableAddress());
|
||||
newBreakpoint.setUserMessage(popupBreakpoint.getUserMessage());
|
||||
newBreakpoint.setColor(popupBreakpoint.getColor());
|
||||
newBreakpoint.setStopsSimulation(popupBreakpoint.stopsSimulation());
|
||||
}
|
||||
|
||||
JOptionPane.showMessageDialog(GUI.getTopParentContainer(),
|
||||
"Registered " + motes.size() + " breakpoints (" + reregistered + " re-registered)",
|
||||
"Breakpoints added", JOptionPane.INFORMATION_MESSAGE);
|
||||
codeWatcher.displaySourceFile(selectedWatchpoint.getCodeFile(), selectedWatchpoint.getLineNumber(), false);
|
||||
}
|
||||
};
|
||||
private Action delFromMoteTypeAction = new AbstractAction("Delete from all motes (mote type)") {
|
||||
private Action removeWatchpointAction = new AbstractAction("Remove watchpoint") {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (popupBreakpoint == null) {
|
||||
logger.fatal("No breakpoint to delete");
|
||||
if (selectedWatchpoint == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Extract all motes of the same mote type */
|
||||
Simulation sim = popupBreakpoint.getMote().getSimulation();
|
||||
MoteType type = popupBreakpoint.getMote().getType();
|
||||
ArrayList<MspMote> motes = new ArrayList<MspMote>();
|
||||
for (Mote m: sim.getMotes()) {
|
||||
if (m.getType() == type) {
|
||||
if (!(m instanceof MspMote)) {
|
||||
logger.fatal("At least one mote was not a MSP mote: " + m);
|
||||
return;
|
||||
}
|
||||
|
||||
motes.add((MspMote)m);
|
||||
}
|
||||
mote.removeBreakpoint(selectedWatchpoint);
|
||||
table.invalidate();
|
||||
table.repaint();
|
||||
}
|
||||
};
|
||||
private Action configureWatchpointAction = new AbstractAction("Configure watchpoint information") {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (selectedWatchpoint == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Delete breakpoints */
|
||||
int deleted = 0;
|
||||
for (MspMote m: motes) {
|
||||
/* Avoid duplicates (match executable addresses) */
|
||||
MspBreakpointContainer container = m.getBreakpointsContainer();
|
||||
MspBreakpoint[] breakpoints = container.getBreakpoints();
|
||||
for (MspBreakpoint w: breakpoints) {
|
||||
if (popupBreakpoint.getExecutableAddress().intValue() ==
|
||||
w.getExecutableAddress().intValue()) {
|
||||
container.removeBreakpoint(w.getExecutableAddress());
|
||||
deleted++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JOptionPane.showMessageDialog(GUI.getTopParentContainer(),
|
||||
"Deleted " + deleted + " breakpoints",
|
||||
"Breakpoints deleted", JOptionPane.INFORMATION_MESSAGE);
|
||||
configureWatchpointInfo(selectedWatchpoint);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -34,32 +34,33 @@ package se.sics.cooja.mspmote.plugins;
|
|||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.swing.AbstractListModel;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JEditorPane;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JSeparator;
|
||||
import javax.swing.ListCellRenderer;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.PopupMenuEvent;
|
||||
import javax.swing.event.PopupMenuListener;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Highlighter;
|
||||
import javax.swing.text.Highlighter.HighlightPainter;
|
||||
|
||||
import jsyntaxpane.DefaultSyntaxKit;
|
||||
import jsyntaxpane.components.Markers.SimpleMarker;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import se.sics.mspsim.extutil.highlight.CScanner;
|
||||
import se.sics.mspsim.extutil.highlight.Token;
|
||||
import se.sics.mspsim.extutil.highlight.TokenTypes;
|
||||
import se.sics.cooja.Watchpoint;
|
||||
import se.sics.cooja.WatchpointMote;
|
||||
import se.sics.cooja.util.JSyntaxAddBreakpoint;
|
||||
import se.sics.cooja.util.JSyntaxRemoveBreakpoint;
|
||||
import se.sics.cooja.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Displays source code and allows a user to add and remove breakpoints.
|
||||
|
@ -69,184 +70,231 @@ import se.sics.mspsim.extutil.highlight.TokenTypes;
|
|||
public class CodeUI extends JPanel {
|
||||
private static Logger logger = Logger.getLogger(CodeUI.class);
|
||||
|
||||
private JPanel panel = null;
|
||||
private JList codeList = null;
|
||||
{
|
||||
DefaultSyntaxKit.initKit();
|
||||
}
|
||||
|
||||
private MspBreakpointContainer breakpoints = null;
|
||||
private JEditorPane codeEditor = null;
|
||||
private HashMap<Integer, Integer> codeEditorLines = null;
|
||||
protected File displayedFile = null;
|
||||
|
||||
private Token tokensArray[][] = null;
|
||||
private int tokensStartPos[] = null;
|
||||
private static final HighlightPainter CURRENT_LINE_MARKER = new SimpleMarker(Color.ORANGE);
|
||||
private static final HighlightPainter SELECTED_LINE_MARKER = new SimpleMarker(Color.GREEN);
|
||||
private static final HighlightPainter BREAKPOINTS_MARKER = new SimpleMarker(Color.LIGHT_GRAY);
|
||||
private final Object currentLineTag;
|
||||
private final Object selectedLineTag;
|
||||
private final ArrayList<Object> breakpointsLineTags = new ArrayList<Object>();
|
||||
|
||||
/**
|
||||
* @param breakpoints Breakpoints
|
||||
*/
|
||||
public CodeUI(MspBreakpointContainer breakpoints) {
|
||||
this.breakpoints = breakpoints;
|
||||
private JSyntaxAddBreakpoint actionAddBreakpoint = null;
|
||||
private JSyntaxRemoveBreakpoint actionRemoveBreakpoint = null;
|
||||
|
||||
private WatchpointMote mote;
|
||||
|
||||
public CodeUI(WatchpointMote mote) {
|
||||
this.mote = mote;
|
||||
|
||||
{
|
||||
/* Workaround to configure jsyntaxpane */
|
||||
JEditorPane e = new JEditorPane();
|
||||
new JScrollPane(e);
|
||||
e.setContentType("text/c");
|
||||
DefaultSyntaxKit kit = (DefaultSyntaxKit) e.getEditorKit();
|
||||
kit.setProperty("Action.addbreakpoint", JSyntaxAddBreakpoint.class.getName());
|
||||
kit.setProperty("Action.removebreakpoint", JSyntaxRemoveBreakpoint.class.getName());
|
||||
kit.setProperty("PopupMenu", "copy-to-clipboard,-,find,find-next,goto-line,-,addbreakpoint,removebreakpoint");
|
||||
}
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
codeEditor = new JEditorPane();
|
||||
add(new JScrollPane(codeEditor), BorderLayout.CENTER);
|
||||
doLayout();
|
||||
|
||||
panel = new JPanel(new BorderLayout());
|
||||
add(panel, BorderLayout.CENTER);
|
||||
displayNoCode();
|
||||
codeEditorLines = new HashMap<Integer, Integer>();
|
||||
codeEditor.setContentType("text/c");
|
||||
DefaultSyntaxKit kit = (DefaultSyntaxKit) codeEditor.getEditorKit();
|
||||
kit.setProperty("Action.addbreakpoint", JSyntaxAddBreakpoint.class.getName());
|
||||
kit.setProperty("Action.removebreakpoint", JSyntaxRemoveBreakpoint.class.getName());
|
||||
kit.setProperty("PopupMenu", "copy-to-clipboard,-,find,find-next,goto-line,-,addbreakpoint,removebreakpoint");
|
||||
|
||||
breakpoints.addWatchpointListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
/* Only update code list if simulation is not running */
|
||||
if (CodeUI.this.breakpoints.getMote().getSimulation().isRunning() ||
|
||||
CodeUI.this.breakpoints.getLastWatchpoint() != null) {
|
||||
JPopupMenu p = codeEditor.getComponentPopupMenu();
|
||||
for (Component c: p.getComponents()) {
|
||||
if (c instanceof JMenuItem) {
|
||||
if (((JMenuItem) c).getAction() != null &&
|
||||
((JMenuItem) c).getAction() instanceof JSyntaxAddBreakpoint) {
|
||||
actionAddBreakpoint = (JSyntaxAddBreakpoint)(((JMenuItem) c).getAction());
|
||||
actionAddBreakpoint.setMenuText("Add breakpoint");
|
||||
}
|
||||
if (((JMenuItem) c).getAction() != null &&
|
||||
((JMenuItem) c).getAction() instanceof JSyntaxRemoveBreakpoint) {
|
||||
actionRemoveBreakpoint = (JSyntaxRemoveBreakpoint)(((JMenuItem) c).getAction());
|
||||
actionRemoveBreakpoint.setMenuText("Remove breakpoint");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
codeEditor.setText("");
|
||||
codeEditorLines.clear();
|
||||
codeEditor.setEditable(false);
|
||||
|
||||
Highlighter hl = codeEditor.getHighlighter();
|
||||
Object o = null;
|
||||
try {
|
||||
o = hl.addHighlight(0, 0, CURRENT_LINE_MARKER);
|
||||
} catch (BadLocationException e1) {
|
||||
}
|
||||
currentLineTag = o;
|
||||
|
||||
o = null;
|
||||
try {
|
||||
o = hl.addHighlight(0, 0, SELECTED_LINE_MARKER);
|
||||
} catch (BadLocationException e1) {
|
||||
}
|
||||
selectedLineTag = o;
|
||||
|
||||
codeEditor.getComponentPopupMenu().addPopupMenuListener(new PopupMenuListener() {
|
||||
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
|
||||
/* Disable breakpoint actions */
|
||||
actionAddBreakpoint.setEnabled(false);
|
||||
actionRemoveBreakpoint.setEnabled(false);
|
||||
|
||||
int line = getCodeEditorMouseLine();
|
||||
if (line < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
if (codeList != null) {
|
||||
codeList.updateUI();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* Configure breakpoint menu options */
|
||||
Integer address =
|
||||
CodeUI.this.mote.getExecutableAddressOf(displayedFile, line);
|
||||
if (address == null) {
|
||||
return;
|
||||
}
|
||||
final int start = codeEditorLines.get(line);
|
||||
int end = codeEditorLines.get(line+1);
|
||||
Highlighter hl = codeEditor.getHighlighter();
|
||||
try {
|
||||
hl.changeHighlight(selectedLineTag, start, end);
|
||||
} catch (BadLocationException e1) {
|
||||
}
|
||||
boolean hasBreakpoint =
|
||||
CodeUI.this.mote.breakpointExists(address);
|
||||
if (!hasBreakpoint) {
|
||||
actionAddBreakpoint.setEnabled(true);
|
||||
actionAddBreakpoint.putValue("WatchpointMote", CodeUI.this.mote);
|
||||
actionAddBreakpoint.putValue("WatchpointFile", displayedFile);
|
||||
actionAddBreakpoint.putValue("WatchpointLine", new Integer(line));
|
||||
actionAddBreakpoint.putValue("WatchpointAddress", new Integer(address));
|
||||
} else {
|
||||
actionRemoveBreakpoint.setEnabled(true);
|
||||
actionRemoveBreakpoint.putValue("WatchpointMote", CodeUI.this.mote);
|
||||
actionRemoveBreakpoint.putValue("WatchpointFile", displayedFile);
|
||||
actionRemoveBreakpoint.putValue("WatchpointLine", new Integer(line));
|
||||
actionRemoveBreakpoint.putValue("WatchpointAddress", new Integer(address));
|
||||
}
|
||||
}
|
||||
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
|
||||
Highlighter hl = codeEditor.getHighlighter();
|
||||
try {
|
||||
hl.changeHighlight(selectedLineTag, 0, 0);
|
||||
} catch (BadLocationException e1) {
|
||||
}
|
||||
}
|
||||
public void popupMenuCanceled(PopupMenuEvent e) {
|
||||
}
|
||||
});
|
||||
|
||||
displayNoCode(true);
|
||||
}
|
||||
|
||||
public void updateBreakpoints() {
|
||||
Highlighter hl = codeEditor.getHighlighter();
|
||||
|
||||
for (Object breakpointsLineTag: breakpointsLineTags) {
|
||||
hl.removeHighlight(breakpointsLineTag);
|
||||
}
|
||||
breakpointsLineTags.clear();
|
||||
|
||||
for (Watchpoint w: mote.getBreakpoints()) {
|
||||
if (!w.getCodeFile().equals(displayedFile)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final int start = codeEditorLines.get(w.getLineNumber());
|
||||
int end = codeEditorLines.get(w.getLineNumber()+1);
|
||||
try {
|
||||
breakpointsLineTags.add(hl.addHighlight(start, end, BREAKPOINTS_MARKER));
|
||||
} catch (BadLocationException e1) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getCodeEditorMouseLine() {
|
||||
if (codeEditorLines == null) {
|
||||
return -1;
|
||||
}
|
||||
Point mousePos = codeEditor.getMousePosition();
|
||||
if (mousePos == null) {
|
||||
return -1;
|
||||
}
|
||||
int modelPos = codeEditor.viewToModel(mousePos);
|
||||
int line = 1;
|
||||
while (codeEditorLines.containsKey(line+1)) {
|
||||
int next = codeEditorLines.get(line+1);
|
||||
if (modelPos < next) {
|
||||
return line;
|
||||
}
|
||||
line++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any shown source code.
|
||||
*/
|
||||
public void displayNoCode() {
|
||||
// Display "no code" message
|
||||
public void displayNoCode(final boolean markCurrent) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
panel.removeAll();
|
||||
panel.repaint();
|
||||
displayedFile = null;
|
||||
codeEditor.setText(null);
|
||||
codeEditorLines.clear();
|
||||
displayLine(-1, markCurrent);
|
||||
}
|
||||
});
|
||||
displayedFile = null;
|
||||
return;
|
||||
}
|
||||
|
||||
private void createTokens(String[] codeData) {
|
||||
|
||||
/* Merge code lines */
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String line: codeData) {
|
||||
sb.append(line);
|
||||
sb.append('\n');
|
||||
}
|
||||
String code = sb.toString();
|
||||
|
||||
/* Scan code */
|
||||
CScanner cScanner = new CScanner();
|
||||
cScanner.change(0, 0, code.length());
|
||||
int nrTokens;
|
||||
nrTokens = cScanner.scan(code.toCharArray(), 0, code.length());
|
||||
|
||||
/* Extract tokens */
|
||||
ArrayList<Token> codeTokensVector = new ArrayList<Token>();
|
||||
for (int i=0; i < nrTokens; i++) {
|
||||
Token token = cScanner.getToken(i);
|
||||
codeTokensVector.add(token);
|
||||
}
|
||||
|
||||
/* Create new line token array */
|
||||
Token newTokensArray[][] = new Token[codeData.length][];
|
||||
int[] newTokensStartPos = new int[codeData.length];
|
||||
int lineStart=0, lineEnd=-1;
|
||||
Iterator<Token> tokens = codeTokensVector.iterator();
|
||||
Token currentToken = tokens.next();
|
||||
for (int i=0; i < newTokensArray.length; i++) {
|
||||
lineStart = lineEnd + 1;
|
||||
lineEnd = lineStart + codeData[i].length();
|
||||
|
||||
newTokensStartPos[i] = lineStart;;
|
||||
|
||||
/* Advance tokens until correct line */
|
||||
while (currentToken.position + currentToken.symbol.name.length() < lineStart) {
|
||||
if (!tokens.hasNext()) {
|
||||
break;
|
||||
}
|
||||
currentToken = tokens.next();
|
||||
}
|
||||
|
||||
/* Advance tokens until last token on line */
|
||||
Vector<Token> lineTokens = new Vector<Token>();
|
||||
while (currentToken.position < lineEnd) {
|
||||
lineTokens.add(currentToken);
|
||||
|
||||
if (!tokens.hasNext()) {
|
||||
break;
|
||||
}
|
||||
currentToken = tokens.next();
|
||||
}
|
||||
|
||||
if (currentToken == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Store line tokens */
|
||||
Token[] lineTokensArray = new Token[lineTokens.size()];
|
||||
for (int j=0; j < lineTokens.size(); j++) {
|
||||
lineTokensArray[j] = lineTokens.get(j);
|
||||
}
|
||||
newTokensArray[i] = lineTokensArray;
|
||||
}
|
||||
|
||||
/* Start using tokens array */
|
||||
tokensArray = newTokensArray;
|
||||
tokensStartPos = newTokensStartPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display given source code and mark given line.
|
||||
*
|
||||
* @param codeFile Source code file
|
||||
* @param codeData Source code
|
||||
* @param lineNr Line numer
|
||||
*/
|
||||
public void displayNewCode(File codeFile, String[] codeData, final int lineNr) {
|
||||
displayedFile = codeFile;
|
||||
public void displayNewCode(final File codeFile, final int lineNr, final boolean markCurrent) {
|
||||
if (!codeFile.equals(displayedFile)) {
|
||||
/* Read from disk */
|
||||
final String data = StringUtils.loadFromFile(codeFile);
|
||||
if (data == null || data.length() == 0) {
|
||||
displayNoCode(markCurrent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (codeData == null || codeData.length == 0) {
|
||||
displayNoCode();
|
||||
return;
|
||||
String[] lines = data.split("\n");
|
||||
logger.info("Opening " + codeFile + " (" + lines.length + " lines)");
|
||||
int length = 0;
|
||||
codeEditorLines.clear();
|
||||
for (int line=1; line-1 < lines.length; line++) {
|
||||
codeEditorLines.put(line, length);
|
||||
length += lines[line-1].length()+1;
|
||||
}
|
||||
codeEditor.setText(data.toString());
|
||||
displayedFile = codeFile;
|
||||
updateBreakpoints();
|
||||
}
|
||||
|
||||
logger.info("Opening " + codeFile + " (" + codeData.length + " lines)");
|
||||
|
||||
/* Create new list */
|
||||
final JList newList = new JList(new CodeListModel(codeData));
|
||||
newList.setBackground(Color.WHITE);
|
||||
newList.setFont(new Font("courier", 0, 12));
|
||||
newList.setCellRenderer(new CodeCellRenderer(lineNr));
|
||||
((CodeCellRenderer)newList.getCellRenderer()).setNice(false);
|
||||
newList.setFixedCellHeight(12);
|
||||
newList.addMouseListener(new MouseAdapter() {
|
||||
public void mousePressed(MouseEvent e) {
|
||||
handleMouseEvent(e);
|
||||
}
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
handleMouseEvent(e);
|
||||
}
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
handleMouseEvent(e);
|
||||
}
|
||||
public void mouseExited(MouseEvent e) {
|
||||
handleMouseEvent(e);
|
||||
}
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
handleMouseEvent(e);
|
||||
}
|
||||
});
|
||||
createTokens(codeData);
|
||||
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
panel.removeAll();
|
||||
codeList = newList;
|
||||
panel.add(codeList);
|
||||
panel.validate();
|
||||
displayLine(lineNr);
|
||||
displayLine(lineNr, markCurrent);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -255,290 +303,35 @@ public class CodeUI extends JPanel {
|
|||
*
|
||||
* @param lineNumber Line number
|
||||
*/
|
||||
public void displayLine(int lineNumber) {
|
||||
if (codeList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
((CodeCellRenderer) codeList.getCellRenderer()).setNice(false);
|
||||
((CodeCellRenderer) codeList.getCellRenderer()).changeCurrentLine(lineNumber);
|
||||
((CodeCellRenderer) codeList.getCellRenderer()).validate();
|
||||
|
||||
if (lineNumber > 0) {
|
||||
int index = lineNumber - 1;
|
||||
codeList.setSelectedIndex(index);
|
||||
codeList.ensureIndexIsVisible(Math.max(0, index-3));
|
||||
codeList.ensureIndexIsVisible(Math.min(index+3, codeList.getModel().getSize()));
|
||||
codeList.ensureIndexIsVisible(index);
|
||||
}
|
||||
|
||||
codeList.updateUI();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
((CodeCellRenderer) codeList.getCellRenderer()).setNice(true);
|
||||
codeList.repaint();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleMouseEvent(MouseEvent event) {
|
||||
if (event.isPopupTrigger()) {
|
||||
Point menuLocation = codeList.getPopupLocation(event);
|
||||
if (menuLocation == null) {
|
||||
menuLocation = new Point(
|
||||
codeList.getLocationOnScreen().x + event.getX(),
|
||||
codeList.getLocationOnScreen().y + event.getY());
|
||||
private void displayLine(int lineNumber, boolean markCurrent) {
|
||||
try {
|
||||
if (markCurrent) {
|
||||
/* remove previous highlight */
|
||||
Highlighter hl = codeEditor.getHighlighter();
|
||||
hl.changeHighlight(currentLineTag, 0, 0);
|
||||
}
|
||||
|
||||
final int currentLine = codeList.locationToIndex(new Point(event.getX(), event.getY())) + 1;
|
||||
codeList.setSelectedIndex(currentLine - 1);
|
||||
JPopupMenu popupMenu = createPopupMenu(displayedFile, currentLine);
|
||||
|
||||
popupMenu.setLocation(menuLocation);
|
||||
popupMenu.setInvoker(codeList);
|
||||
popupMenu.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
private JPopupMenu createPopupMenu(final File codeFile, final int lineNr) {
|
||||
final Integer executableAddress = breakpoints.getExecutableAddressOf(codeFile, lineNr);
|
||||
boolean breakpointExists = breakpoints.breakpointExists(codeFile, lineNr);
|
||||
|
||||
JPopupMenu menuMotePlugins = new JPopupMenu();
|
||||
JMenuItem headerMenuItem = new JMenuItem("Breakpoints:");
|
||||
headerMenuItem.setEnabled(false);
|
||||
menuMotePlugins.add(headerMenuItem);
|
||||
menuMotePlugins.add(new JSeparator());
|
||||
|
||||
JMenuItem addBreakpointMenuItem = new JMenuItem("Add breakpoint on line " + lineNr);
|
||||
if (executableAddress == null || breakpointExists) {
|
||||
addBreakpointMenuItem.setEnabled(false);
|
||||
} else {
|
||||
addBreakpointMenuItem.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
breakpoints.addBreakpoint(codeFile, lineNr, executableAddress);
|
||||
if (lineNumber >= 0) {
|
||||
final int start = codeEditorLines.get(lineNumber);
|
||||
int end = codeEditorLines.get(lineNumber+1);
|
||||
if (markCurrent) {
|
||||
/* highlight code */
|
||||
Highlighter hl = codeEditor.getHighlighter();
|
||||
hl.changeHighlight(currentLineTag, start, end);
|
||||
}
|
||||
});
|
||||
}
|
||||
menuMotePlugins.add(addBreakpointMenuItem);
|
||||
|
||||
JMenuItem delBreakpointMenuItem = new JMenuItem("Delete breakpoint on line " + lineNr);
|
||||
if (executableAddress == null || !breakpointExists) {
|
||||
delBreakpointMenuItem.setEnabled(false);
|
||||
} else {
|
||||
delBreakpointMenuItem.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
breakpoints.removeBreakpoint(executableAddress);
|
||||
}
|
||||
});
|
||||
}
|
||||
menuMotePlugins.add(delBreakpointMenuItem);
|
||||
|
||||
return menuMotePlugins;
|
||||
}
|
||||
|
||||
private class CodeListModel extends AbstractListModel {
|
||||
private String[] codeData;
|
||||
|
||||
public CodeListModel(String[] codeData) {
|
||||
super();
|
||||
this.codeData = codeData;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
if (codeData == null || codeData.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return codeData.length;
|
||||
}
|
||||
|
||||
public Object getElementAt(int index) {
|
||||
if (codeData == null || codeData.length == 0) {
|
||||
return "No code to display";
|
||||
}
|
||||
|
||||
return codeData[index];
|
||||
}
|
||||
}
|
||||
|
||||
/* FROM: http://www.rgagnon.com/javadetails/java-0306.html, 03/19/2008 */
|
||||
private static String stringToHTMLString(String string) {
|
||||
StringBuffer sb = new StringBuffer(string.length());
|
||||
boolean lastWasBlankChar = false;
|
||||
int len = string.length();
|
||||
char c;
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
c = string.charAt(i);
|
||||
if (c == ' ') {
|
||||
if (lastWasBlankChar) {
|
||||
lastWasBlankChar = false;
|
||||
sb.append(" ");
|
||||
}
|
||||
else {
|
||||
lastWasBlankChar = true;
|
||||
sb.append(' ');
|
||||
}
|
||||
}
|
||||
else {
|
||||
lastWasBlankChar = false;
|
||||
//
|
||||
// HTML Special Chars
|
||||
if (c == '"') {
|
||||
sb.append(""");
|
||||
} else if (c == '&') {
|
||||
sb.append("&");
|
||||
} else if (c == '<') {
|
||||
sb.append("<");
|
||||
} else if (c == '>') {
|
||||
sb.append(">");
|
||||
} else if (c == '\n') {
|
||||
// Handle Newline
|
||||
sb.append("<br/>");
|
||||
} else {
|
||||
int ci = 0xffff & c;
|
||||
if (ci < 160 ) {
|
||||
// nothing special only 7 Bit
|
||||
sb.append(c);
|
||||
} else {
|
||||
// Not 7 Bit use the unicode system
|
||||
sb.append("&#");
|
||||
sb.append(new Integer(ci).toString());
|
||||
sb.append(';');
|
||||
/* ensure visible */
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
codeEditor.scrollRectToVisible(codeEditor.modelToView(start));
|
||||
} catch (BadLocationException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("Error when highlighting current line: " + e.getMessage(), e);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private class CodeCellRenderer extends JLabel implements ListCellRenderer {
|
||||
private int currentIndex;
|
||||
private boolean nice = true;
|
||||
|
||||
public CodeCellRenderer(int currentLineNr) {
|
||||
this.currentIndex = currentLineNr - 1;
|
||||
}
|
||||
|
||||
public void setNice(boolean b) {
|
||||
nice = b;
|
||||
}
|
||||
|
||||
public void changeCurrentLine(int currentLineNr) {
|
||||
this.currentIndex = currentLineNr - 1;
|
||||
}
|
||||
|
||||
private String getColoredLabelText(int lineNr, int lineStartPos, Token[] tokens, String code) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("<html>");
|
||||
|
||||
/* Add line number */
|
||||
String lineString = "0000" + Integer.toString(lineNr);
|
||||
lineString = lineString.substring(lineString.length() - 4);
|
||||
sb.append("<font color=\"333333\">");
|
||||
sb.append(lineString);
|
||||
sb.append(": </font>");
|
||||
|
||||
/* Add code */
|
||||
if (tokens == null || tokens.length == 0 || lineStartPos < 0) {
|
||||
sb.append("<font color=\"000000\">");
|
||||
sb.append(code);
|
||||
sb.append("</font>");
|
||||
} else {
|
||||
for (int i=tokens.length-1; i >= 0; i--) {
|
||||
Token subToken = tokens[i];
|
||||
|
||||
String colorString = "000000";
|
||||
|
||||
/* Determine code color */
|
||||
final int type = subToken.symbol.type;
|
||||
switch (type) {
|
||||
case TokenTypes.COMMENT:
|
||||
case TokenTypes.START_COMMENT:
|
||||
case TokenTypes.MID_COMMENT:
|
||||
case TokenTypes.END_COMMENT:
|
||||
colorString = "00AA00";
|
||||
break;
|
||||
case TokenTypes.STRING:
|
||||
colorString = "0000AA";
|
||||
break;
|
||||
case TokenTypes.KEYWORD:
|
||||
case TokenTypes.KEYWORD2:
|
||||
colorString = "AA0000";
|
||||
break;
|
||||
}
|
||||
|
||||
/* Extract part of token residing in current line */
|
||||
int tokenLinePos;
|
||||
String subCode;
|
||||
if (subToken.position < lineStartPos) {
|
||||
subCode = subToken.symbol.name.substring(lineStartPos - subToken.position);
|
||||
tokenLinePos = 0;
|
||||
} else if (subToken.position + subToken.symbol.name.length() > lineStartPos + code.length()) {
|
||||
subCode = subToken.symbol.name.substring(0, code.length() + lineStartPos - subToken.position);
|
||||
tokenLinePos = subToken.position - lineStartPos;
|
||||
} else {
|
||||
subCode = subToken.symbol.name;
|
||||
tokenLinePos = subToken.position - lineStartPos;
|
||||
}
|
||||
|
||||
subCode = stringToHTMLString(subCode);
|
||||
String firstPart = code.substring(0, tokenLinePos);
|
||||
String coloredSubCode = "<font color=\"" + colorString + "\">" + subCode + "</font>";
|
||||
String lastPart =
|
||||
tokenLinePos + subToken.symbol.name.length() >= code.length()?
|
||||
"":code.substring(tokenLinePos + subToken.symbol.name.length());
|
||||
|
||||
code = firstPart + coloredSubCode + lastPart;
|
||||
}
|
||||
|
||||
code = code.replace(" ", " ");
|
||||
sb.append(code);
|
||||
}
|
||||
|
||||
sb.append("</html>");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Component getListCellRendererComponent(
|
||||
JList list,
|
||||
Object value,
|
||||
int index,
|
||||
boolean isSelected,
|
||||
boolean cellHasFocus)
|
||||
{
|
||||
int lineNr = index + 1;
|
||||
if (!nice) {
|
||||
setText((String) value);
|
||||
} else if (tokensArray != null && index < tokensArray.length && tokensArray[index] != null) {
|
||||
setText(getColoredLabelText(lineNr, tokensStartPos[index], tokensArray[index], (String) value));
|
||||
} else {
|
||||
setText(getColoredLabelText(lineNr, 0, null, (String) value));
|
||||
}
|
||||
|
||||
if (index == currentIndex) {
|
||||
setBackground(Color.green);
|
||||
} else if (isSelected) {
|
||||
setBackground(list.getSelectionBackground());
|
||||
setForeground(list.getSelectionForeground());
|
||||
} else {
|
||||
setBackground(list.getBackground());
|
||||
setForeground(list.getForeground());
|
||||
}
|
||||
setEnabled(list.isEnabled());
|
||||
|
||||
if (breakpoints.breakpointExists(displayedFile, lineNr)) {
|
||||
setFont(list.getFont().deriveFont(Font.BOLD));
|
||||
} else {
|
||||
setFont(list.getFont());
|
||||
}
|
||||
|
||||
setOpaque(true);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,18 +30,16 @@
|
|||
package se.sics.cooja.mspmote.plugins;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
|
@ -54,8 +52,7 @@ import javax.swing.JLabel;
|
|||
import javax.swing.JList;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.filechooser.FileFilter;
|
||||
|
@ -72,11 +69,12 @@ import se.sics.cooja.MotePlugin;
|
|||
import se.sics.cooja.PluginType;
|
||||
import se.sics.cooja.Simulation;
|
||||
import se.sics.cooja.VisPlugin;
|
||||
import se.sics.cooja.Watchpoint;
|
||||
import se.sics.cooja.WatchpointMote;
|
||||
import se.sics.cooja.WatchpointMote.WatchpointListener;
|
||||
import se.sics.cooja.mspmote.MspMote;
|
||||
import se.sics.cooja.mspmote.MspMoteType;
|
||||
import se.sics.cooja.util.StringUtils;
|
||||
import se.sics.mspsim.core.EmulationException;
|
||||
import se.sics.mspsim.core.MSP430;
|
||||
import se.sics.mspsim.ui.DebugUI;
|
||||
import se.sics.mspsim.util.DebugInfo;
|
||||
import se.sics.mspsim.util.ELFDebug;
|
||||
|
@ -85,25 +83,31 @@ import se.sics.mspsim.util.ELFDebug;
|
|||
@PluginType(PluginType.MOTE_PLUGIN)
|
||||
public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
||||
private static final long serialVersionUID = -8463196456352243367L;
|
||||
|
||||
private static final int SOURCECODE = 0;
|
||||
private static final int BREAKPOINTS = 2;
|
||||
|
||||
private static Logger logger = Logger.getLogger(MspCodeWatcher.class);
|
||||
private Simulation simulation;
|
||||
private Observer simObserver;
|
||||
private MspMote mspMote;
|
||||
|
||||
private File currentCodeFile = null;
|
||||
private int currentLineNumber = -1;
|
||||
|
||||
private JSplitPane leftSplitPane, rightSplitPane;
|
||||
private DebugUI assCodeUI;
|
||||
private CodeUI sourceCodeUI;
|
||||
private BreakpointsUI breakpointsUI;
|
||||
|
||||
private MspBreakpointContainer breakpoints = null;
|
||||
private MspMote mspMote; /* currently the only supported mote */
|
||||
private WatchpointMote watchpointMote;
|
||||
private WatchpointListener watchpointListener;
|
||||
|
||||
private JComboBox fileComboBox;
|
||||
private String[] debugInfoMap = null;
|
||||
private File[] sourceFiles;
|
||||
|
||||
|
||||
private JTabbedPane mainPane;
|
||||
|
||||
/**
|
||||
* Mini-debugger for MSP Motes.
|
||||
* Visualizes instructions, source code and allows a user to manipulate breakpoints.
|
||||
|
@ -113,15 +117,13 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
* @param gui Simulator
|
||||
*/
|
||||
public MspCodeWatcher(Mote mote, Simulation simulationToVisualize, GUI gui) {
|
||||
super("Msp Code Watcher", gui);
|
||||
this.mspMote = (MspMote) mote;
|
||||
super("Msp Code Watcher - " + mote, gui);
|
||||
simulation = simulationToVisualize;
|
||||
this.mspMote = (MspMote) mote;
|
||||
this.watchpointMote = (WatchpointMote) mote;
|
||||
|
||||
getContentPane().setLayout(new BorderLayout());
|
||||
|
||||
/* Breakpoints */
|
||||
breakpoints = mspMote.getBreakpointsContainer();
|
||||
|
||||
/* Create source file list */
|
||||
fileComboBox = new JComboBox();
|
||||
fileComboBox.addActionListener(new ActionListener() {
|
||||
|
@ -149,58 +151,68 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
}
|
||||
});
|
||||
updateFileComboBox();
|
||||
|
||||
|
||||
/* Browse code control (north) */
|
||||
JButton currentFileButton = new JButton(currentFileAction);
|
||||
JButton mapButton = new JButton(mapAction);
|
||||
|
||||
Box browseBox = Box.createHorizontalBox();
|
||||
browseBox.add(Box.createHorizontalStrut(10));
|
||||
browseBox.add(new JLabel("Program counter: "));
|
||||
browseBox.add(currentFileButton);
|
||||
browseBox.add(Box.createHorizontalGlue());
|
||||
browseBox.add(new JLabel("Browse: "));
|
||||
browseBox.add(fileComboBox);
|
||||
browseBox.add(Box.createHorizontalStrut(10));
|
||||
browseBox.add(mapButton);
|
||||
browseBox.add(Box.createHorizontalStrut(10));
|
||||
Box sourceCodeControl = Box.createHorizontalBox();
|
||||
sourceCodeControl.add(new JButton(stepAction));
|
||||
sourceCodeControl.add(Box.createHorizontalStrut(10));
|
||||
sourceCodeControl.add(new JLabel("Current location: "));
|
||||
sourceCodeControl.add(new JButton(currentFileAction));
|
||||
sourceCodeControl.add(Box.createHorizontalGlue());
|
||||
sourceCodeControl.add(new JLabel("Source files: "));
|
||||
sourceCodeControl.add(fileComboBox);
|
||||
sourceCodeControl.add(Box.createHorizontalStrut(5));
|
||||
sourceCodeControl.add(new JButton(mapAction));
|
||||
sourceCodeControl.add(Box.createHorizontalStrut(10));
|
||||
|
||||
/* Execution control panel (south) */
|
||||
JPanel controlPanel = new JPanel();
|
||||
JButton button = new JButton(stepAction);
|
||||
controlPanel.add(button);
|
||||
/* Execution control panel (south of source code panel) */
|
||||
|
||||
/* Layout */
|
||||
mainPane = new JTabbedPane();
|
||||
|
||||
sourceCodeUI = new CodeUI(watchpointMote);
|
||||
JPanel sourceCodePanel = new JPanel(new BorderLayout());
|
||||
sourceCodePanel.add(BorderLayout.CENTER, sourceCodeUI);
|
||||
sourceCodePanel.add(BorderLayout.SOUTH, sourceCodeControl);
|
||||
mainPane.addTab("Source code", null, sourceCodePanel, null); /* SOURCECODE */
|
||||
|
||||
|
||||
/* Main components: assembler and C code + breakpoints (center) */
|
||||
assCodeUI = new DebugUI(this.mspMote.getCPU(), true);
|
||||
breakpointsUI = new BreakpointsUI(breakpoints, this);
|
||||
sourceCodeUI = new CodeUI(breakpoints);
|
||||
leftSplitPane = new JSplitPane(
|
||||
JSplitPane.HORIZONTAL_SPLIT,
|
||||
new JScrollPane(assCodeUI),
|
||||
new JScrollPane(breakpointsUI)
|
||||
);
|
||||
leftSplitPane.setOneTouchExpandable(true);
|
||||
leftSplitPane.setDividerLocation(0.0);
|
||||
rightSplitPane = new JSplitPane(
|
||||
JSplitPane.HORIZONTAL_SPLIT,
|
||||
leftSplitPane,
|
||||
new JScrollPane(sourceCodeUI)
|
||||
);
|
||||
rightSplitPane.setOneTouchExpandable(true);
|
||||
rightSplitPane.setDividerLocation(0.0);
|
||||
for (Component c: assCodeUI.getComponents()) {
|
||||
c.setBackground(Color.WHITE);
|
||||
}
|
||||
mainPane.addTab("Instructions", null, assCodeUI, null);
|
||||
|
||||
add(BorderLayout.NORTH, browseBox);
|
||||
add(BorderLayout.CENTER, rightSplitPane);
|
||||
add(BorderLayout.SOUTH, controlPanel);
|
||||
breakpointsUI = new BreakpointsUI(mspMote, this);
|
||||
mainPane.addTab("Breakpoints", null, breakpointsUI, "Right-click source code to add"); /* BREAKPOINTS */
|
||||
|
||||
add(BorderLayout.CENTER, mainPane);
|
||||
|
||||
/* Listen for breakpoint changes */
|
||||
watchpointMote.addWatchpointListener(watchpointListener = new WatchpointListener() {
|
||||
public void watchpointTriggered(final Watchpoint watchpoint) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
logger.info("Watchpoint triggered: " + watchpoint);
|
||||
if (simulation.isRunning()) {
|
||||
return;
|
||||
}
|
||||
breakpointsUI.selectBreakpoint(watchpoint);
|
||||
sourceCodeUI.updateBreakpoints();
|
||||
showCurrentPC();
|
||||
}
|
||||
});
|
||||
}
|
||||
public void watchpointsChanged() {
|
||||
sourceCodeUI.updateBreakpoints();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/* Observe when simulation starts/stops */
|
||||
simulation.addObserver(simObserver = new Observer() {
|
||||
public void update(Observable obs, Object obj) {
|
||||
if (!simulation.isRunning()) {
|
||||
stepAction.setEnabled(true);
|
||||
updateInfo();
|
||||
showCurrentPC();
|
||||
} else {
|
||||
stepAction.setEnabled(false);
|
||||
}
|
||||
|
@ -208,7 +220,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
});
|
||||
|
||||
setSize(750, 500);
|
||||
updateInfo();
|
||||
showCurrentPC();
|
||||
}
|
||||
|
||||
private void updateFileComboBox() {
|
||||
|
@ -221,25 +233,12 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
fileComboBox.setSelectedIndex(0);
|
||||
}
|
||||
|
||||
public void displaySourceFile(File file, final int line) {
|
||||
if (file != null &&
|
||||
sourceCodeUI.displayedFile != null &&
|
||||
file.compareTo(sourceCodeUI.displayedFile) == 0) {
|
||||
/* No need to reload source file */
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
sourceCodeUI.displayLine(line);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
/* Load source file from disk */
|
||||
String[] codeData = readTextFile(file);
|
||||
if (codeData == null) {
|
||||
return;
|
||||
}
|
||||
sourceCodeUI.displayNewCode(file, codeData, line);
|
||||
public void displaySourceFile(final File file, final int line, final boolean markCurrent) {
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
mainPane.setSelectedIndex(SOURCECODE); /* code */
|
||||
sourceCodeUI.displayNewCode(file, line, markCurrent);
|
||||
}});
|
||||
}
|
||||
|
||||
private void sourceFileSelectionChanged() {
|
||||
|
@ -249,32 +248,40 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
}
|
||||
|
||||
File selectedFile = sourceFiles[index-1];
|
||||
displaySourceFile(selectedFile, -1);
|
||||
displaySourceFile(selectedFile, -1, false);
|
||||
}
|
||||
|
||||
private void updateInfo() {
|
||||
private void showCurrentPC() {
|
||||
/* Instructions */
|
||||
assCodeUI.updateRegs();
|
||||
assCodeUI.repaint();
|
||||
|
||||
/* Source */
|
||||
updateCurrentSourceCodeFile();
|
||||
if (currentCodeFile == null) {
|
||||
File file = currentCodeFile;
|
||||
Integer line = currentLineNumber;
|
||||
if (file == null || line == null) {
|
||||
currentFileAction.setEnabled(false);
|
||||
currentFileAction.putValue(Action.NAME, "[unknown]");
|
||||
currentFileAction.putValue(Action.SHORT_DESCRIPTION, null);
|
||||
return;
|
||||
}
|
||||
currentFileAction.setEnabled(true);
|
||||
currentFileAction.putValue(Action.NAME, currentCodeFile.getName() + ":" + currentLineNumber);
|
||||
currentFileAction.putValue(Action.SHORT_DESCRIPTION, currentCodeFile.getAbsolutePath() + ":" + currentLineNumber);
|
||||
fileComboBox.setSelectedItem(currentCodeFile.getName());
|
||||
currentFileAction.putValue(Action.NAME, file.getName() + ":" + line);
|
||||
currentFileAction.putValue(Action.SHORT_DESCRIPTION, file.getAbsolutePath() + ":" + line);
|
||||
fileComboBox.setSelectedItem(file.getName());
|
||||
|
||||
displaySourceFile(currentCodeFile, currentLineNumber);
|
||||
displaySourceFile(file, line, true);
|
||||
}
|
||||
|
||||
public void closePlugin() {
|
||||
watchpointMote.removeWatchpointListener(watchpointListener);
|
||||
watchpointListener = null;
|
||||
|
||||
simulation.deleteObserver(simObserver);
|
||||
simObserver = null;
|
||||
|
||||
/* TODO XXX Unregister breakpoints? */
|
||||
}
|
||||
|
||||
private void updateCurrentSourceCodeFile() {
|
||||
|
@ -285,8 +292,12 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
if (debug == null) {
|
||||
return;
|
||||
}
|
||||
DebugInfo debugInfo = debug.getDebugInfo(mspMote.getCPU().reg[MSP430.PC]);
|
||||
int pc = mspMote.getCPU().getPC();
|
||||
DebugInfo debugInfo = debug.getDebugInfo(pc);
|
||||
if (debugInfo == null) {
|
||||
if (pc != 0) {
|
||||
logger.warn("No sourcecode info at " + String.format("0x%04x", mspMote.getCPU().getPC()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -321,6 +332,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
private void tryMapDebugInfo() {
|
||||
final String[] debugFiles;
|
||||
try {
|
||||
|
||||
ELFDebug debug = ((MspMoteType)mspMote.getType()).getELF().getDebug();
|
||||
debugFiles = debug != null ? debug.getSourceFiles() : null;
|
||||
if (debugFiles == null) {
|
||||
|
@ -343,7 +355,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
"\"Next File\" proceeds to the next source file in the debug info.\n\n" +
|
||||
debugFiles[counter] + " (" + (counter+1) + '/' + debugFiles.length + ')',
|
||||
"Select source file to locate", JOptionPane.YES_NO_CANCEL_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE, null,
|
||||
JOptionPane.QUESTION_MESSAGE, null,
|
||||
new String[] { "Next File", "Locate File", "Cancel"}, "Next File");
|
||||
if (n == JOptionPane.CANCEL_OPTION || n == JOptionPane.CLOSED_OPTION) {
|
||||
return null;
|
||||
|
@ -421,14 +433,14 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
optionPane.setOptions(new String[] { "OK" });
|
||||
optionPane.setInitialValue("OK");
|
||||
JDialog dialog = optionPane.createDialog(
|
||||
GUI.getTopParentContainer(),
|
||||
"Mapping debug info to real sources");
|
||||
GUI.getTopParentContainer(),
|
||||
"Mapping debug info to real sources");
|
||||
dialog.setVisible(true);
|
||||
|
||||
|
||||
replace = replaceInput.getText();
|
||||
replacement = replacementInput.getText();
|
||||
}
|
||||
|
||||
|
||||
replace = replace.replace('\\', '/');
|
||||
replacement = replacement.replace('\\', '/');
|
||||
return new String[] { replace, replacement };
|
||||
|
@ -444,7 +456,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
updateFileComboBox();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static File[] getSourceFiles(MspMote mote, String[] map) {
|
||||
final String[] sourceFiles;
|
||||
try {
|
||||
|
@ -465,7 +477,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
} catch (IOException e1) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Verify that files exist */
|
||||
ArrayList<File> existing = new ArrayList<File>();
|
||||
for (String sourceFile: sourceFiles) {
|
||||
|
@ -512,7 +524,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
"Make sure the source files were not moved after the firmware compilation.\n" +
|
||||
"\n" +
|
||||
"If you want to manually locate the sources, click \"Map\" button.",
|
||||
"No source files found",
|
||||
"No source files found",
|
||||
JOptionPane.WARNING_MESSAGE);
|
||||
return true;
|
||||
}
|
||||
|
@ -530,7 +542,7 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
}
|
||||
sorted.add(index, file);
|
||||
}
|
||||
|
||||
|
||||
/* Add Contiki source first */
|
||||
if (contikiSource != null && contikiSource.exists()) {
|
||||
sorted.add(0, contikiSource);
|
||||
|
@ -539,63 +551,21 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
return sorted.toArray(new File[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to open and read given text file.
|
||||
*
|
||||
* @param file File
|
||||
* @return Line-by-line text in file
|
||||
*/
|
||||
public static String[] readTextFile(File file) {
|
||||
if (GUI.isVisualizedInApplet()) {
|
||||
/* Download from web server instead */
|
||||
String path = file.getPath();
|
||||
|
||||
/* Extract Contiki build path */
|
||||
String contikiBuildPath = GUI.getExternalToolsSetting("PATH_CONTIKI_BUILD");
|
||||
String contikiWebPath = GUI.getExternalToolsSetting("PATH_CONTIKI_WEB");
|
||||
|
||||
if (!path.startsWith(contikiBuildPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
/* Replace Contiki parent path with web server code base */
|
||||
path = contikiWebPath + '/' + path.substring(contikiBuildPath.length());
|
||||
path = path.replace('\\', '/');
|
||||
URL url = new URL(GUI.getAppletCodeBase(), path);
|
||||
String data = StringUtils.loadFromURL(url);
|
||||
return data!=null?data.split("\n"):null;
|
||||
} catch (MalformedURLException e) {
|
||||
logger.warn("Failure to read source code: " + e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String data = StringUtils.loadFromFile(file);
|
||||
return data!=null?data.split("\n"):null;
|
||||
}
|
||||
|
||||
public Collection<Element> getConfigXML() {
|
||||
Vector<Element> config = new Vector<Element>();
|
||||
ArrayList<Element> config = new ArrayList<Element>();
|
||||
Element element;
|
||||
|
||||
element = new Element("split_1");
|
||||
element.addContent("" + leftSplitPane.getDividerLocation());
|
||||
|
||||
element = new Element("tab");
|
||||
element.addContent("" + mainPane.getSelectedIndex());
|
||||
config.add(element);
|
||||
|
||||
element = new Element("split_2");
|
||||
element.addContent("" + rightSplitPane.getDividerLocation());
|
||||
config.add(element);
|
||||
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
|
||||
for (Element element : configXML) {
|
||||
if (element.getName().equals("split_1")) {
|
||||
leftSplitPane.setDividerLocation(Integer.parseInt(element.getText()));
|
||||
} else if (element.getName().equals("split_2")) {
|
||||
rightSplitPane.setDividerLocation(Integer.parseInt(element.getText()));
|
||||
if (element.getName().equals("tab")) {
|
||||
mainPane.setSelectedIndex(Integer.parseInt(element.getText()));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -608,11 +578,11 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
if (currentCodeFile == null) {
|
||||
return;
|
||||
}
|
||||
displaySourceFile(currentCodeFile, currentLineNumber);
|
||||
displaySourceFile(currentCodeFile, currentLineNumber, true);
|
||||
}
|
||||
};
|
||||
|
||||
private AbstractAction mapAction = new AbstractAction("Map") {
|
||||
private AbstractAction mapAction = new AbstractAction("Locate sources") {
|
||||
private static final long serialVersionUID = -3929432830596292495L;
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
|
@ -622,14 +592,13 @@ public class MspCodeWatcher extends VisPlugin implements MotePlugin {
|
|||
|
||||
private AbstractAction stepAction = new AbstractAction("Step instruction") {
|
||||
private static final long serialVersionUID = 3520750710757816575L;
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
mspMote.getCPU().stepInstructions(1);
|
||||
} catch (EmulationException ex) {
|
||||
logger.fatal("Error: ", ex);
|
||||
}
|
||||
updateInfo();
|
||||
showCurrentPC();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2012, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: CodeUI.java,v 1.8 2009/09/23 08:16:06 fros4943 Exp $
|
||||
*/
|
||||
|
||||
package se.sics.cooja.util;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.File;
|
||||
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.text.JTextComponent;
|
||||
|
||||
import jsyntaxpane.SyntaxDocument;
|
||||
import jsyntaxpane.actions.DefaultSyntaxAction;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import se.sics.cooja.WatchpointMote;
|
||||
|
||||
public class JSyntaxAddBreakpoint extends DefaultSyntaxAction {
|
||||
private static Logger logger = Logger.getLogger(JSyntaxAddBreakpoint.class);
|
||||
|
||||
public JSyntaxAddBreakpoint() {
|
||||
super("addbreakpoint");
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem menuItem = (JMenuItem) e.getSource();
|
||||
Action action = menuItem.getAction();
|
||||
WatchpointMote watchpointMote = (WatchpointMote) action.getValue("WatchpointMote");
|
||||
if (watchpointMote == null) {
|
||||
logger.warn("Error: No source, cannot configure breakpoint");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = (File) action.getValue("WatchpointFile");
|
||||
Integer line = (Integer) action.getValue("WatchpointLine");
|
||||
Integer address = (Integer) action.getValue("WatchpointAddress");
|
||||
if (file == null || line == null || address == null) {
|
||||
logger.warn("Error: Bad breakpoint info, cannot add breakpoint");
|
||||
return;
|
||||
}
|
||||
|
||||
watchpointMote.addBreakpoint(file, line, address);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright (c) 2012, Swedish Institute of Computer Science.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: CodeUI.java,v 1.8 2009/09/23 08:16:06 fros4943 Exp $
|
||||
*/
|
||||
|
||||
package se.sics.cooja.util;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.io.File;
|
||||
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JMenuItem;
|
||||
|
||||
import jsyntaxpane.actions.DefaultSyntaxAction;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import se.sics.cooja.Watchpoint;
|
||||
import se.sics.cooja.WatchpointMote;
|
||||
|
||||
public class JSyntaxRemoveBreakpoint extends DefaultSyntaxAction {
|
||||
private static Logger logger = Logger.getLogger(JSyntaxRemoveBreakpoint.class);
|
||||
|
||||
public JSyntaxRemoveBreakpoint() {
|
||||
super("removebreakpoint");
|
||||
}
|
||||
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
JMenuItem menuItem = (JMenuItem) e.getSource();
|
||||
Action action = menuItem.getAction();
|
||||
WatchpointMote watchpointMote = (WatchpointMote) action.getValue("WatchpointMote");
|
||||
if (watchpointMote == null) {
|
||||
logger.warn("Error: No source, cannot configure breakpoint");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = (File) action.getValue("WatchpointFile");
|
||||
Integer line = (Integer) action.getValue("WatchpointLine");
|
||||
Integer address = (Integer) action.getValue("WatchpointAddress");
|
||||
if (file == null || line == null || address == null) {
|
||||
logger.warn("Error: Bad breakpoint info, cannot remove breakpoint");
|
||||
return;
|
||||
}
|
||||
for (Watchpoint w: watchpointMote.getBreakpoints()) {
|
||||
if (file.equals(w.getCodeFile()) && line.equals(w.getLineNumber()) && address.equals(w.getExecutableAddress())) {
|
||||
watchpointMote.removeBreakpoint(w);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue