updated code watcher user interfaces: added support for disabling breakpoints without removing them + several minor fixes

This commit is contained in:
fros4943 2009-06-11 10:06:47 +00:00
parent c19c8a16ad
commit a8aa75fa8d
2 changed files with 208 additions and 210 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2007, Swedish Institute of Computer Science. * Copyright (c) 2009, Swedish Institute of Computer Science.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id: BreakpointsUI.java,v 1.2 2008/11/03 18:10:34 fros4943 Exp $ * $Id: BreakpointsUI.java,v 1.3 2009/06/11 10:06:47 fros4943 Exp $
*/ */
package se.sics.cooja.mspmote.plugins; package se.sics.cooja.mspmote.plugins;
@ -34,57 +34,165 @@ package se.sics.cooja.mspmote.plugins;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File; import java.io.File;
import java.util.Vector;
import javax.swing.*; import javax.swing.*;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import se.sics.cooja.mspmote.plugins.MspCodeWatcher.Breakpoints; /**
import se.sics.cooja.mspmote.plugins.MspCodeWatcher.Breakpoints.Breakpoint; * Displays a set of breakpoints.
*
* @author Fredrik Osterlind
*/
public class BreakpointsUI extends JPanel { public class BreakpointsUI extends JPanel {
private static Logger logger = Logger.getLogger(BreakpointsUI.class); private static Logger logger = Logger.getLogger(BreakpointsUI.class);
private JTable breakpointsTable = null; private MspBreakpointContainer breakpoints = null;
private Breakpoints breakpoints = null; private JTable table = null;
public BreakpointsUI(MspBreakpointContainer breakpoints, final MspCodeWatcher codeWatcher) {
this.breakpoints = breakpoints;
/* Breakpoints table */
table = new JTable(tableModel) {
public String getToolTipText(MouseEvent e) {
/* Tooltips: show full file paths */
java.awt.Point p = e.getPoint();
int rowIndex = table.rowAtPoint(p);
int colIndex = table.columnAtPoint(p);
int realColumnIndex = table.convertColumnIndexToModel(colIndex);
if (realColumnIndex != 1) {
return null;
}
MspBreakpoint[] allBreakpoints = BreakpointsUI.this.breakpoints.getBreakpoints();
if (rowIndex < 0 || rowIndex >= allBreakpoints.length) {
return null;
}
File file = allBreakpoints[rowIndex].getCodeFile();
if (file == null) {
return null;
}
return file.getPath();
}
};
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
table.getColumnModel().getColumn(0).setPreferredWidth(60); /* XXX */
table.getColumnModel().getColumn(0).setMaxWidth(60);
table.getColumnModel().getColumn(2).setPreferredWidth(60);
table.getColumnModel().getColumn(2).setMaxWidth(60);
table.getColumnModel().getColumn(3).setPreferredWidth(60);
table.getColumnModel().getColumn(3).setMaxWidth(60);
/* Show source file on breakpoint mouse click */
table.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
java.awt.Point p = e.getPoint();
int rowIndex = table.rowAtPoint(p);
int colIndex = table.columnAtPoint(p);
int realColumnIndex = table.convertColumnIndexToModel(colIndex);
if (realColumnIndex != 1 && realColumnIndex != 2) {
return;
}
MspBreakpoint[] allBreakpoints = BreakpointsUI.this.breakpoints.getBreakpoints();
if (rowIndex < 0 || rowIndex >= allBreakpoints.length) {
return;
}
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);
}
});
setLayout(new BorderLayout());
add(BorderLayout.NORTH, table.getTableHeader());
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) {
return;
}
final int breakpointIndex = index;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
table.setRowSelectionInterval(breakpointIndex, breakpointIndex);
}
});
}
private AbstractTableModel tableModel = new AbstractTableModel() { private AbstractTableModel tableModel = new AbstractTableModel() {
private String[] tableColumnNames = { private final String[] tableColumnNames = {
"Address", "Address",
"File", "File:Line",
"Line", "Breaks",
"Remove" "Remove"
}; };
public String getColumnName(int col) {
public String getColumnName(int col) { return tableColumnNames[col].toString(); } return tableColumnNames[col].toString();
public int getRowCount() { return breakpoints.getBreakpoints().size(); } }
public int getColumnCount() { return tableColumnNames.length; } public int getRowCount() {
return breakpoints.getBreakpointsCount();
}
public int getColumnCount() {
return tableColumnNames.length;
}
public Object getValueAt(int row, int col) { public Object getValueAt(int row, int col) {
// Display executable address in hexadecimal MspBreakpoint breakpoint = breakpoints.getBreakpoints()[row];
/* Executable address in hexadecimal */
if (col == 0) { if (col == 0) {
Integer address = breakpoints.getBreakpoints().get(row).getExecutableAddress(); Integer address = breakpoint.getExecutableAddress();
return "0x" + Integer.toHexString(address.intValue()); return "0x" + Integer.toHexString(address.intValue());
} }
// Display only name of file /* Source file + line number */
if (col == 1) { if (col == 1) {
File file = breakpoints.getBreakpoints().get(row).getCodeFile(); File file = breakpoint.getCodeFile();
if (file == null) { if (file == null) {
return ""; return "";
} }
return file.getName(); return file.getName() + ":" + breakpoint.getLineNumber();
} }
// Display line number /* Stops simulation */
if (col == 2) { if (col == 2) {
Integer line = breakpoints.getBreakpoints().get(row).getLineNumber(); return breakpoint.stopsSimulation();
if (line == null) {
return "";
}
return line;
} }
return new Boolean(false); return new Boolean(false);
@ -93,138 +201,23 @@ public class BreakpointsUI extends JPanel {
return getColumnClass(col) == Boolean.class; return getColumnClass(col) == Boolean.class;
} }
public void setValueAt(Object value, int row, int col) { public void setValueAt(Object value, int row, int col) {
fireTableCellUpdated(row, col); MspBreakpoint breakpoint = breakpoints.getBreakpoints()[row];
Integer address = breakpoints.getBreakpoints().get(row).getExecutableAddress();
if (col == 2) {
/* Toggle stop state */
breakpoint.setStopsSimulation(!breakpoint.stopsSimulation());
fireTableCellUpdated(row, col);
return;
}
/* Remove breakpoint */
Integer address = breakpoint.getExecutableAddress();
breakpoints.removeBreakpoint(address); breakpoints.removeBreakpoint(address);
fireTableCellUpdated(row, col);
} }
public Class getColumnClass(int c) { public Class<?> getColumnClass(int c) {
return getValueAt(0, c).getClass(); return getValueAt(0, c).getClass();
} }
}; };
public BreakpointsUI(Breakpoints breakpoints, final MspCodeWatcher codeWatcher) {
this.breakpoints = breakpoints;
breakpoints.addBreakpointListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Breakpoint triggered = BreakpointsUI.this.breakpoints.getLastTriggered();
if (triggered != null) {
flashBreakpoint(triggered);
}
breakpointsTable.repaint();
}
});
breakpointsTable = new JTable(tableModel) {
public String getToolTipText(MouseEvent e) {
String tip = null;
java.awt.Point p = e.getPoint();
int rowIndex = breakpointsTable.rowAtPoint(p);
int colIndex = breakpointsTable.columnAtPoint(p);
int realColumnIndex = breakpointsTable.convertColumnIndexToModel(colIndex);
if (realColumnIndex == 1) {
Vector<Breakpoint> allBreakpoints = BreakpointsUI.this.breakpoints.getBreakpoints();
if (rowIndex < 0 || rowIndex >= allBreakpoints.size()) {
return "";
}
File file = allBreakpoints.get(rowIndex).getCodeFile();
if (file == null) {
return "";
} else {
tip = file.getPath();
}
}
return tip;
}
};
/* Open file on mouse click */
breakpointsTable.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent e) {
java.awt.Point p = e.getPoint();
int rowIndex = breakpointsTable.rowAtPoint(p);
int colIndex = breakpointsTable.columnAtPoint(p);
int realColumnIndex = breakpointsTable.convertColumnIndexToModel(colIndex);
if (realColumnIndex == 1 || realColumnIndex == 2) {
Vector<Breakpoint> allBreakpoints = BreakpointsUI.this.breakpoints.getBreakpoints();
if (rowIndex < 0 || rowIndex >= allBreakpoints.size()) {
return;
}
File file = allBreakpoints.get(rowIndex).getCodeFile();
int line = allBreakpoints.get(rowIndex).getLineNumber();
if (file == null) {
return;
} else {
/* Display source code */
codeWatcher.displaySourceFile(file, line);
}
}
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
});
setLayout(new BorderLayout());
add(breakpointsTable.getTableHeader(), BorderLayout.PAGE_START);
add(breakpointsTable, BorderLayout.CENTER);
}
private int flashCounter = 0;
private Color oldColor;
private void flashBreakpoint(Breakpoint breakpoint) {
int index = breakpoints.getBreakpoints().indexOf(breakpoint);
breakpointsTable.setRowSelectionInterval(index, index);
oldColor = breakpointsTable.getSelectionBackground();
breakpointsTable.setSelectionBackground(Color.RED);
flashCounter = 8;
final Timer timer = new Timer(100, null);
timer.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (flashCounter-- <= 0) {
timer.stop();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
breakpointsTable.setSelectionBackground(oldColor);
}
});
return;
}
// Toggle background color
if (breakpointsTable.getSelectionBackground() != Color.RED) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
breakpointsTable.setSelectionBackground(Color.RED);
}
});
} else {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
breakpointsTable.setSelectionBackground(oldColor);
}
});
}
}
});
timer.start();
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2007, Swedish Institute of Computer Science. * Copyright (c) 2009, Swedish Institute of Computer Science.
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id: CodeUI.java,v 1.5 2008/11/03 18:10:52 fros4943 Exp $ * $Id: CodeUI.java,v 1.6 2009/06/11 10:06:47 fros4943 Exp $
*/ */
package se.sics.cooja.mspmote.plugins; package se.sics.cooja.mspmote.plugins;
@ -37,12 +37,12 @@ import java.awt.event.ActionListener;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; import java.awt.event.MouseListener;
import java.io.File; import java.io.File;
import java.util.Enumeration; import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector; import java.util.Vector;
import javax.swing.*; import javax.swing.*;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import se.sics.cooja.mspmote.plugins.MspCodeWatcher.Breakpoints;
import se.sics.mspsim.extutil.highlight.CScanner; import se.sics.mspsim.extutil.highlight.CScanner;
import se.sics.mspsim.extutil.highlight.Token; import se.sics.mspsim.extutil.highlight.Token;
import se.sics.mspsim.extutil.highlight.TokenTypes; import se.sics.mspsim.extutil.highlight.TokenTypes;
@ -57,9 +57,9 @@ public class CodeUI extends JPanel {
private JPanel panel = null; private JPanel panel = null;
private JList codeList = null; private JList codeList = null;
private File currentFile = null;
private Breakpoints breakpoints = null; private MspBreakpointContainer breakpoints = null;
protected File displayedFile = null;
private Token tokensArray[][] = null; private Token tokensArray[][] = null;
private int tokensStartPos[] = null; private int tokensStartPos[] = null;
@ -67,7 +67,7 @@ public class CodeUI extends JPanel {
/** /**
* @param breakpoints Breakpoints * @param breakpoints Breakpoints
*/ */
public CodeUI(Breakpoints breakpoints) { public CodeUI(MspBreakpointContainer breakpoints) {
this.breakpoints = breakpoints; this.breakpoints = breakpoints;
setLayout(new BorderLayout()); setLayout(new BorderLayout());
@ -76,14 +76,17 @@ public class CodeUI extends JPanel {
add(panel, BorderLayout.CENTER); add(panel, BorderLayout.CENTER);
displayNoCode(); displayNoCode();
breakpoints.addBreakpointListener(new ActionListener() { breakpoints.addWatchpointListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (codeList != null) { SwingUtilities.invokeLater(new Runnable() {
codeList.updateUI(); public void run() {
} if (codeList != null) {
codeList.updateUI();
}
}
});
} }
}); });
} }
/** /**
@ -97,17 +100,19 @@ public class CodeUI extends JPanel {
panel.repaint(); panel.repaint();
} }
}); });
currentFile = null; displayedFile = null;
return; return;
} }
private void createTokens(Vector<String> codeData) { private void createTokens(String[] codeData) {
/* Merge code lines */ /* Merge code lines */
String code = ""; StringBuilder sb = new StringBuilder();
for (String line: codeData) { for (String line: codeData) {
code += line + "\n"; sb.append(line);
sb.append('\n');
} }
String code = sb.toString();
/* Scan code */ /* Scan code */
CScanner cScanner = new CScanner(); CScanner cScanner = new CScanner();
@ -116,30 +121,30 @@ public class CodeUI extends JPanel {
nrTokens = cScanner.scan(code.toCharArray(), 0, code.length()); nrTokens = cScanner.scan(code.toCharArray(), 0, code.length());
/* Extract tokens */ /* Extract tokens */
Vector<Token> codeTokensVector = new Vector<Token>(); ArrayList<Token> codeTokensVector = new ArrayList<Token>();
for (int i=0; i < nrTokens; i++) { for (int i=0; i < nrTokens; i++) {
Token token = cScanner.getToken(i); Token token = cScanner.getToken(i);
codeTokensVector.add(token); codeTokensVector.add(token);
} }
/* Create new line token array */ /* Create new line token array */
Token newTokensArray[][] = new Token[codeData.size()][]; Token newTokensArray[][] = new Token[codeData.length][];
int[] newTokensStartPos = new int[codeData.size()]; int[] newTokensStartPos = new int[codeData.length];
int lineStart=0, lineEnd=-1; int lineStart=0, lineEnd=-1;
Enumeration<Token> tokensEnum = codeTokensVector.elements(); Iterator<Token> tokens = codeTokensVector.iterator();
Token currentToken = tokensEnum.nextElement(); Token currentToken = tokens.next();
for (int i=0; i < newTokensArray.length; i++) { for (int i=0; i < newTokensArray.length; i++) {
lineStart = lineEnd + 1; lineStart = lineEnd + 1;
lineEnd = lineStart + codeData.get(i).length(); lineEnd = lineStart + codeData[i].length();
newTokensStartPos[i] = lineStart;; newTokensStartPos[i] = lineStart;;
/* Advance tokens until correct line */ /* Advance tokens until correct line */
while (currentToken.position + currentToken.symbol.name.length() < lineStart) { while (currentToken.position + currentToken.symbol.name.length() < lineStart) {
if (!tokensEnum.hasMoreElements()) { if (!tokens.hasNext()) {
break; break;
} }
currentToken = tokensEnum.nextElement(); currentToken = tokens.next();
} }
/* Advance tokens until last token on line */ /* Advance tokens until last token on line */
@ -147,10 +152,10 @@ public class CodeUI extends JPanel {
while (currentToken.position < lineEnd) { while (currentToken.position < lineEnd) {
lineTokens.add(currentToken); lineTokens.add(currentToken);
if (!tokensEnum.hasMoreElements()) { if (!tokens.hasNext()) {
break; break;
} }
currentToken = tokensEnum.nextElement(); currentToken = tokens.next();
} }
if (currentToken == null) { if (currentToken == null) {
@ -177,10 +182,10 @@ public class CodeUI extends JPanel {
* @param codeData Source code * @param codeData Source code
* @param lineNr Line numer * @param lineNr Line numer
*/ */
public void displayNewCode(final File codeFile, final Vector<String> codeData, final int lineNr) { public void displayNewCode(final File codeFile, final String[] codeData, final int lineNr) {
currentFile = codeFile; displayedFile = codeFile;
if (codeData == null || codeData.size() == 0) { if (codeData == null || codeData.length == 0) {
displayNoCode(); displayNoCode();
return; return;
} }
@ -216,7 +221,7 @@ public class CodeUI extends JPanel {
displayLine(lineNr); displayLine(lineNr);
} }
}); });
} }
/** /**
* Mark given line number in shown source code. * Mark given line number in shown source code.
@ -224,21 +229,24 @@ public class CodeUI extends JPanel {
* @param lineNumber Line number * @param lineNumber Line number
*/ */
public void displayLine(final int lineNumber) { public void displayLine(final int lineNumber) {
if (codeList == null) { if (codeList == null || lineNumber < 0) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
codeList.updateUI();
}
});
return; return;
} }
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
public void run() { public void run() {
if (lineNumber > 0) { ((CodeCellRenderer) codeList.getCellRenderer()).changeCurrentLine(lineNumber);
((CodeCellRenderer) codeList.getCellRenderer()).changeCurrentLine(lineNumber); int index = lineNumber - 1;
int index = lineNumber - 1; codeList.setSelectedIndex(index);
codeList.setSelectedIndex(index);
codeList.ensureIndexIsVisible(Math.max(0, index-3)); codeList.ensureIndexIsVisible(Math.max(0, index-3));
codeList.ensureIndexIsVisible(Math.min(index+3, codeList.getModel().getSize())); codeList.ensureIndexIsVisible(Math.min(index+3, codeList.getModel().getSize()));
codeList.ensureIndexIsVisible(index); codeList.ensureIndexIsVisible(index);
}
codeList.updateUI(); codeList.updateUI();
} }
}); });
@ -259,7 +267,7 @@ public class CodeUI extends JPanel {
codeList.setSelectedIndex(currentLine - 1); codeList.setSelectedIndex(currentLine - 1);
} }
}); });
JPopupMenu popupMenu = createPopupMenu(currentFile, currentLine); JPopupMenu popupMenu = createPopupMenu(displayedFile, currentLine);
popupMenu.setLocation(menuLocation); popupMenu.setLocation(menuLocation);
popupMenu.setInvoker(codeList); popupMenu.setInvoker(codeList);
@ -269,10 +277,7 @@ public class CodeUI extends JPanel {
private JPopupMenu createPopupMenu(final File codeFile, final int lineNr) { private JPopupMenu createPopupMenu(final File codeFile, final int lineNr) {
final Integer executableAddress = breakpoints.getExecutableAddressOf(codeFile, lineNr); final Integer executableAddress = breakpoints.getExecutableAddressOf(codeFile, lineNr);
boolean breakpointExists = false; boolean breakpointExists = breakpoints.breakpointExists(codeFile, lineNr);
if (executableAddress != null) {
breakpointExists = breakpoints.breakpointExists(executableAddress);
}
JPopupMenu menuMotePlugins = new JPopupMenu(); JPopupMenu menuMotePlugins = new JPopupMenu();
JMenuItem headerMenuItem = new JMenuItem("Breakpoints:"); JMenuItem headerMenuItem = new JMenuItem("Breakpoints:");
@ -308,27 +313,27 @@ public class CodeUI extends JPanel {
} }
private class CodeListModel extends AbstractListModel { private class CodeListModel extends AbstractListModel {
private Vector<String> codeData; private String[] codeData;
public CodeListModel(Vector<String> codeData) { public CodeListModel(String[] codeData) {
super(); super();
this.codeData = codeData; this.codeData = codeData;
} }
public int getSize() { public int getSize() {
if (codeData == null || codeData.isEmpty()) { if (codeData == null || codeData.length == 0) {
return 0; return 0;
} }
return codeData.size(); return codeData.length;
} }
public Object getElementAt(int index) { public Object getElementAt(int index) {
if (codeData == null || codeData.isEmpty()) { if (codeData == null || codeData.length == 0) {
return "No code to display"; return "No code to display";
} }
return codeData.get(index); return codeData[index];
} }
} }
@ -399,7 +404,9 @@ public class CodeUI extends JPanel {
String html = "<html>"; String html = "<html>";
/* Add line number */ /* Add line number */
html += "<font color=\"333333\">" + lineNr + ": </font>"; String lineString = "0000" + Integer.toString(lineNr);
lineString = lineString.substring(lineString.length() - 4);
html += "<font color=\"333333\">" + lineString + ": </font>";
/* Add code */ /* Add code */
if (tokens == null || tokens.length == 0 || lineStartPos < 0) { if (tokens == null || tokens.length == 0 || lineStartPos < 0) {
@ -460,7 +467,6 @@ public class CodeUI extends JPanel {
return html; return html;
} }
public Component getListCellRendererComponent( public Component getListCellRendererComponent(
JList list, JList list,
Object value, Object value,
@ -487,8 +493,7 @@ public class CodeUI extends JPanel {
} }
setEnabled(list.isEnabled()); setEnabled(list.isEnabled());
Integer executableAddress = breakpoints.getExecutableAddressOf(currentFile, lineNr); if (breakpoints.breakpointExists(displayedFile, lineNr)) {
if (breakpoints.breakpointExists(executableAddress)) {
setFont(list.getFont().deriveFont(Font.BOLD)); setFont(list.getFont().deriveFont(Font.BOLD));
} else { } else {
setFont(list.getFont()); setFont(list.getFont());