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.
*
* 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
* 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;
@ -34,57 +34,165 @@ package se.sics.cooja.mspmote.plugins;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.Vector;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
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 {
private static Logger logger = Logger.getLogger(BreakpointsUI.class);
private JTable breakpointsTable = null;
private Breakpoints breakpoints = null;
private MspBreakpointContainer 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 String[] tableColumnNames = {
private final String[] tableColumnNames = {
"Address",
"File",
"Line",
"File:Line",
"Breaks",
"Remove"
};
public String getColumnName(int col) { return tableColumnNames[col].toString(); }
public int getRowCount() { return breakpoints.getBreakpoints().size(); }
public int getColumnCount() { return tableColumnNames.length; }
public String getColumnName(int col) {
return tableColumnNames[col].toString();
}
public int getRowCount() {
return breakpoints.getBreakpointsCount();
}
public int getColumnCount() {
return tableColumnNames.length;
}
public Object getValueAt(int row, int col) {
// Display executable address in hexadecimal
MspBreakpoint breakpoint = breakpoints.getBreakpoints()[row];
/* Executable address in hexadecimal */
if (col == 0) {
Integer address = breakpoints.getBreakpoints().get(row).getExecutableAddress();
Integer address = breakpoint.getExecutableAddress();
return "0x" + Integer.toHexString(address.intValue());
}
// Display only name of file
/* Source file + line number */
if (col == 1) {
File file = breakpoints.getBreakpoints().get(row).getCodeFile();
File file = breakpoint.getCodeFile();
if (file == null) {
return "";
}
return file.getName();
return file.getName() + ":" + breakpoint.getLineNumber();
}
// Display line number
/* Stops simulation */
if (col == 2) {
Integer line = breakpoints.getBreakpoints().get(row).getLineNumber();
if (line == null) {
return "";
}
return line;
return breakpoint.stopsSimulation();
}
return new Boolean(false);
@ -93,138 +201,23 @@ public class BreakpointsUI extends JPanel {
return getColumnClass(col) == Boolean.class;
}
public void setValueAt(Object value, int row, int col) {
fireTableCellUpdated(row, col);
Integer address = breakpoints.getBreakpoints().get(row).getExecutableAddress();
MspBreakpoint breakpoint = breakpoints.getBreakpoints()[row];
if (col == 2) {
/* Toggle stop state */
breakpoint.setStopsSimulation(!breakpoint.stopsSimulation());
fireTableCellUpdated(row, col);
return;
}
/* Remove breakpoint */
Integer address = breakpoint.getExecutableAddress();
breakpoints.removeBreakpoint(address);
fireTableCellUpdated(row, col);
}
public Class getColumnClass(int c) {
public Class<?> getColumnClass(int c) {
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.
*
* 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
* 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;
@ -37,12 +37,12 @@ import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.Enumeration;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;
import javax.swing.*;
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.Token;
import se.sics.mspsim.extutil.highlight.TokenTypes;
@ -57,9 +57,9 @@ public class CodeUI extends JPanel {
private JPanel panel = 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 int tokensStartPos[] = null;
@ -67,7 +67,7 @@ public class CodeUI extends JPanel {
/**
* @param breakpoints Breakpoints
*/
public CodeUI(Breakpoints breakpoints) {
public CodeUI(MspBreakpointContainer breakpoints) {
this.breakpoints = breakpoints;
setLayout(new BorderLayout());
@ -76,14 +76,17 @@ public class CodeUI extends JPanel {
add(panel, BorderLayout.CENTER);
displayNoCode();
breakpoints.addBreakpointListener(new ActionListener() {
breakpoints.addWatchpointListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (codeList != null) {
codeList.updateUI();
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (codeList != null) {
codeList.updateUI();
}
}
});
}
});
}
/**
@ -97,17 +100,19 @@ public class CodeUI extends JPanel {
panel.repaint();
}
});
currentFile = null;
displayedFile = null;
return;
}
private void createTokens(Vector<String> codeData) {
private void createTokens(String[] codeData) {
/* Merge code lines */
String code = "";
StringBuilder sb = new StringBuilder();
for (String line: codeData) {
code += line + "\n";
sb.append(line);
sb.append('\n');
}
String code = sb.toString();
/* Scan code */
CScanner cScanner = new CScanner();
@ -116,30 +121,30 @@ public class CodeUI extends JPanel {
nrTokens = cScanner.scan(code.toCharArray(), 0, code.length());
/* Extract tokens */
Vector<Token> codeTokensVector = new Vector<Token>();
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.size()][];
int[] newTokensStartPos = new int[codeData.size()];
Token newTokensArray[][] = new Token[codeData.length][];
int[] newTokensStartPos = new int[codeData.length];
int lineStart=0, lineEnd=-1;
Enumeration<Token> tokensEnum = codeTokensVector.elements();
Token currentToken = tokensEnum.nextElement();
Iterator<Token> tokens = codeTokensVector.iterator();
Token currentToken = tokens.next();
for (int i=0; i < newTokensArray.length; i++) {
lineStart = lineEnd + 1;
lineEnd = lineStart + codeData.get(i).length();
lineEnd = lineStart + codeData[i].length();
newTokensStartPos[i] = lineStart;;
/* Advance tokens until correct line */
while (currentToken.position + currentToken.symbol.name.length() < lineStart) {
if (!tokensEnum.hasMoreElements()) {
if (!tokens.hasNext()) {
break;
}
currentToken = tokensEnum.nextElement();
currentToken = tokens.next();
}
/* Advance tokens until last token on line */
@ -147,10 +152,10 @@ public class CodeUI extends JPanel {
while (currentToken.position < lineEnd) {
lineTokens.add(currentToken);
if (!tokensEnum.hasMoreElements()) {
if (!tokens.hasNext()) {
break;
}
currentToken = tokensEnum.nextElement();
currentToken = tokens.next();
}
if (currentToken == null) {
@ -177,10 +182,10 @@ public class CodeUI extends JPanel {
* @param codeData Source code
* @param lineNr Line numer
*/
public void displayNewCode(final File codeFile, final Vector<String> codeData, final int lineNr) {
currentFile = codeFile;
public void displayNewCode(final File codeFile, final String[] codeData, final int lineNr) {
displayedFile = codeFile;
if (codeData == null || codeData.size() == 0) {
if (codeData == null || codeData.length == 0) {
displayNoCode();
return;
}
@ -216,7 +221,7 @@ public class CodeUI extends JPanel {
displayLine(lineNr);
}
});
}
}
/**
* Mark given line number in shown source code.
@ -224,21 +229,24 @@ public class CodeUI extends JPanel {
* @param lineNumber Line number
*/
public void displayLine(final int lineNumber) {
if (codeList == null) {
if (codeList == null || lineNumber < 0) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
codeList.updateUI();
}
});
return;
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (lineNumber > 0) {
((CodeCellRenderer) codeList.getCellRenderer()).changeCurrentLine(lineNumber);
int index = lineNumber - 1;
codeList.setSelectedIndex(index);
((CodeCellRenderer) codeList.getCellRenderer()).changeCurrentLine(lineNumber);
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.ensureIndexIsVisible(Math.max(0, index-3));
codeList.ensureIndexIsVisible(Math.min(index+3, codeList.getModel().getSize()));
codeList.ensureIndexIsVisible(index);
codeList.updateUI();
}
});
@ -259,7 +267,7 @@ public class CodeUI extends JPanel {
codeList.setSelectedIndex(currentLine - 1);
}
});
JPopupMenu popupMenu = createPopupMenu(currentFile, currentLine);
JPopupMenu popupMenu = createPopupMenu(displayedFile, currentLine);
popupMenu.setLocation(menuLocation);
popupMenu.setInvoker(codeList);
@ -269,10 +277,7 @@ public class CodeUI extends JPanel {
private JPopupMenu createPopupMenu(final File codeFile, final int lineNr) {
final Integer executableAddress = breakpoints.getExecutableAddressOf(codeFile, lineNr);
boolean breakpointExists = false;
if (executableAddress != null) {
breakpointExists = breakpoints.breakpointExists(executableAddress);
}
boolean breakpointExists = breakpoints.breakpointExists(codeFile, lineNr);
JPopupMenu menuMotePlugins = new JPopupMenu();
JMenuItem headerMenuItem = new JMenuItem("Breakpoints:");
@ -308,27 +313,27 @@ public class CodeUI extends JPanel {
}
private class CodeListModel extends AbstractListModel {
private Vector<String> codeData;
private String[] codeData;
public CodeListModel(Vector<String> codeData) {
public CodeListModel(String[] codeData) {
super();
this.codeData = codeData;
}
public int getSize() {
if (codeData == null || codeData.isEmpty()) {
if (codeData == null || codeData.length == 0) {
return 0;
}
return codeData.size();
return codeData.length;
}
public Object getElementAt(int index) {
if (codeData == null || codeData.isEmpty()) {
if (codeData == null || codeData.length == 0) {
return "No code to display";
}
return codeData.get(index);
return codeData[index];
}
}
@ -399,7 +404,9 @@ public class CodeUI extends JPanel {
String html = "<html>";
/* 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 */
if (tokens == null || tokens.length == 0 || lineStartPos < 0) {
@ -460,7 +467,6 @@ public class CodeUI extends JPanel {
return html;
}
public Component getListCellRendererComponent(
JList list,
Object value,
@ -487,8 +493,7 @@ public class CodeUI extends JPanel {
}
setEnabled(list.isEnabled());
Integer executableAddress = breakpoints.getExecutableAddressOf(currentFile, lineNr);
if (breakpoints.breakpointExists(executableAddress)) {
if (breakpoints.breakpointExists(displayedFile, lineNr)) {
setFont(list.getFont().deriveFont(Font.BOLD));
} else {
setFont(list.getFont());