added new optional features: time formatting, hide-duplicate-packets, hide-airshot-packets

This commit is contained in:
Fredrik Osterlind 2013-08-14 12:32:23 +02:00
parent bda04947e7
commit 492cd5f721

View File

@ -40,20 +40,24 @@ import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Observable; import java.util.Observable;
import java.util.Observer; import java.util.Observer;
import java.util.Properties; import java.util.Properties;
import java.util.regex.PatternSyntaxException;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.Action; import javax.swing.Action;
import javax.swing.ButtonGroup; import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.JMenuBar; import javax.swing.JMenuBar;
@ -68,9 +72,12 @@ import javax.swing.JTable;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.JTextPane; import javax.swing.JTextPane;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import javax.swing.RowFilter;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener; import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.jdom.Element; import org.jdom.Element;
@ -116,9 +123,11 @@ public class RadioLogger extends VisPlugin {
private JSplitPane splitPane; private JSplitPane splitPane;
private JTextPane verboseBox = null; private JTextPane verboseBox = null;
private boolean formatTimeString = true;
private final static String[] COLUMN_NAMES = { private final static String[] COLUMN_NAMES = {
"No.", "No. ",
"Time", "Time ms",
"From", "From",
"To", "To",
"Data" "Data"
@ -126,6 +135,7 @@ public class RadioLogger extends VisPlugin {
private final Simulation simulation; private final Simulation simulation;
private final JTable dataTable; private final JTable dataTable;
private TableRowSorter<TableModel> logFilter;
private ArrayList<RadioConnectionLog> connections = new ArrayList<RadioConnectionLog>(); private ArrayList<RadioConnectionLog> connections = new ArrayList<RadioConnectionLog>();
private RadioMedium radioMedium; private RadioMedium radioMedium;
private Observer radioMediumObserver; private Observer radioMediumObserver;
@ -149,7 +159,7 @@ public class RadioLogger extends VisPlugin {
JMenu fileMenu = new JMenu("File"); JMenu fileMenu = new JMenu("File");
JMenu editMenu = new JMenu("Edit"); JMenu editMenu = new JMenu("Edit");
JMenu analyzerMenu = new JMenu("Analyzer"); JMenu analyzerMenu = new JMenu("Analyzer");
JMenu payloadMenu = new JMenu("Payload"); JMenu payloadMenu = new JMenu("View");
menuBar.add(fileMenu); menuBar.add(fileMenu);
menuBar.add(editMenu); menuBar.add(editMenu);
@ -169,11 +179,15 @@ public class RadioLogger extends VisPlugin {
lowpanAnalyzersPcap.add(new IPHCPacketAnalyzer()); lowpanAnalyzersPcap.add(new IPHCPacketAnalyzer());
lowpanAnalyzersPcap.add(new IPv6PacketAnalyzer()); lowpanAnalyzersPcap.add(new IPv6PacketAnalyzer());
lowpanAnalyzersPcap.add(new ICMPv6Analyzer()); lowpanAnalyzersPcap.add(new ICMPv6Analyzer());
model = new AbstractTableModel() { model = new AbstractTableModel() {
private static final long serialVersionUID = 1692207305977527004L; private static final long serialVersionUID = 1692207305977527004L;
public String getColumnName(int col) { public String getColumnName(int col) {
if (col == COLUMN_TIME && formatTimeString) {
return "Time";
}
return COLUMN_NAMES[col]; return COLUMN_NAMES[col];
} }
@ -186,10 +200,19 @@ public class RadioLogger extends VisPlugin {
} }
public Object getValueAt(int row, int col) { public Object getValueAt(int row, int col) {
if (row < 0 || row >= connections.size()) {
return "";
}
RadioConnectionLog conn = connections.get(row); RadioConnectionLog conn = connections.get(row);
if (col == COLUMN_NO) { if (col == COLUMN_NO) {
return Long.toString(row + 1); if (!showDuplicates && conn.hides > 0) {
return (String) "" + (row + 1) + "+" + conn.hides;
}
return (String) "" + (row + 1);
} else if (col == COLUMN_TIME) { } else if (col == COLUMN_TIME) {
if (formatTimeString) {
return LogListener.getFormattedTime(conn.startTime);
}
return Long.toString(conn.startTime / Simulation.MILLISECOND); return Long.toString(conn.startTime / Simulation.MILLISECOND);
} else if (col == COLUMN_FROM) { } else if (col == COLUMN_FROM) {
return "" + conn.connection.getSource().getMote().getID(); return "" + conn.connection.getSource().getMote().getID();
@ -251,14 +274,19 @@ public class RadioLogger extends VisPlugin {
public String getToolTipText(MouseEvent e) { public String getToolTipText(MouseEvent e) {
java.awt.Point p = e.getPoint(); java.awt.Point p = e.getPoint();
int rowIndex = rowAtPoint(p); int rowIndex = rowAtPoint(p);
if (rowIndex < 0) {
return super.getToolTipText(e);
}
int modelRowIndex = convertRowIndexToModel(rowIndex);
int colIndex = columnAtPoint(p); int colIndex = columnAtPoint(p);
int realColumnIndex = convertColumnIndexToModel(colIndex); int modelColumnIndex = convertColumnIndexToModel(colIndex);
if (rowIndex < 0 || realColumnIndex < 0) { if (modelRowIndex < 0 || modelColumnIndex < 0) {
return super.getToolTipText(e); return super.getToolTipText(e);
} }
RadioConnectionLog conn = connections.get(rowIndex); /* TODO This entry may represent several hidden connections */
if (realColumnIndex == COLUMN_TIME) { RadioConnectionLog conn = connections.get(modelRowIndex);
if (modelColumnIndex == COLUMN_TIME) {
return return
"<html>" + "<html>" +
"Start time (us): " + conn.startTime + "Start time (us): " + conn.startTime +
@ -267,9 +295,9 @@ public class RadioLogger extends VisPlugin {
"<br><br>" + "<br><br>" +
"Duration (us): " + (conn.endTime - conn.startTime) + "Duration (us): " + (conn.endTime - conn.startTime) +
"</html>"; "</html>";
} else if (realColumnIndex == COLUMN_FROM) { } else if (modelColumnIndex == COLUMN_FROM) {
return conn.connection.getSource().getMote().toString(); return conn.connection.getSource().getMote().toString();
} else if (realColumnIndex == COLUMN_TO) { } else if (modelColumnIndex == COLUMN_TO) {
Radio[] dests = conn.connection.getDestinations(); Radio[] dests = conn.connection.getDestinations();
if (dests.length == 0) { if (dests.length == 0) {
return "No destinations"; return "No destinations";
@ -286,7 +314,7 @@ public class RadioLogger extends VisPlugin {
} }
tip.append("</html>"); tip.append("</html>");
return tip.toString(); return tip.toString();
} else if (realColumnIndex == COLUMN_DATA) { } else if (modelColumnIndex == COLUMN_DATA) {
if (conn.tooltip == null) { if (conn.tooltip == null) {
prepareTooltipString(conn); prepareTooltipString(conn);
} }
@ -296,6 +324,21 @@ public class RadioLogger extends VisPlugin {
} }
}; };
/* Toggle time format */
dataTable.getTableHeader().addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
int colIndex = dataTable.columnAtPoint(e.getPoint());
int columnIndex = dataTable.convertColumnIndexToModel(colIndex);
if (columnIndex != COLUMN_TIME) {
return;
}
formatTimeString = !formatTimeString;
dataTable.getColumnModel().getColumn(COLUMN_TIME).setHeaderValue(
dataTable.getModel().getColumnName(COLUMN_TIME));
repaint();
}
});
dataTable.addKeyListener(new KeyAdapter() { dataTable.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) { public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) { if (e.getKeyCode() == KeyEvent.VK_SPACE) {
@ -314,11 +357,21 @@ public class RadioLogger extends VisPlugin {
} }
}); });
logFilter = new TableRowSorter<TableModel>(model);
for (int i = 0, n = model.getColumnCount(); i < n; i++) {
logFilter.setSortable(i, false);
}
dataTable.setRowSorter(logFilter);
dataTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { dataTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) { public void valueChanged(ListSelectionEvent e) {
int row = dataTable.getSelectedRow(); int row = dataTable.getSelectedRow();
if (row >= 0) { if (row < 0) {
RadioConnectionLog conn = connections.get(row); return;
}
int modelRowIndex = dataTable.convertRowIndexToModel(row);
if (modelRowIndex >= 0) {
RadioConnectionLog conn = connections.get(modelRowIndex);
if (conn.tooltip == null) { if (conn.tooltip == null) {
prepareTooltipString(conn); prepareTooltipString(conn);
} }
@ -338,6 +391,16 @@ public class RadioLogger extends VisPlugin {
editMenu.add(new JMenuItem(clearAction)); editMenu.add(new JMenuItem(clearAction));
payloadMenu.add(new JMenuItem(aliasAction)); payloadMenu.add(new JMenuItem(aliasAction));
payloadMenu.add(new JCheckBoxMenuItem(showDuplicatesAction) {
public boolean isSelected() {
return showDuplicates;
}
});
payloadMenu.add(new JCheckBoxMenuItem(hideNoDestinationAction) {
public boolean isSelected() {
return hideNoDestinationPackets;
}
});
fileMenu.add(new JMenuItem(saveAction)); fileMenu.add(new JMenuItem(saveAction));
@ -369,12 +432,14 @@ public class RadioLogger extends VisPlugin {
group.add(rbMenuItem); group.add(rbMenuItem);
analyzerMenu.add(rbMenuItem); analyzerMenu.add(rbMenuItem);
/* Load additional analyzers specified by projects (cooja.config) */ /* Load additional analyzers specified by projects (cooja.config) */
String[] projectAnalyzerSuites = String[] projectAnalyzerSuites =
gui.getProjectConfig().getStringArrayValue(RadioLogger.class, "ANALYZERS"); gui.getProjectConfig().getStringArrayValue(RadioLogger.class, "ANALYZERS");
if (projectAnalyzerSuites != null) { if (projectAnalyzerSuites != null) {
for (String suiteName: projectAnalyzerSuites) { for (String suiteName: projectAnalyzerSuites) {
if (suiteName == null || suiteName.trim().isEmpty()) {
continue;
}
Class<? extends RadioLoggerAnalyzerSuite> suiteClass = Class<? extends RadioLoggerAnalyzerSuite> suiteClass =
gui.tryLoadClass(RadioLogger.this, RadioLoggerAnalyzerSuite.class, suiteName); gui.tryLoadClass(RadioLogger.this, RadioLoggerAnalyzerSuite.class, suiteName);
try { try {
@ -383,7 +448,7 @@ public class RadioLogger extends VisPlugin {
rbMenuItem = new JRadioButtonMenuItem(createAnalyzerAction( rbMenuItem = new JRadioButtonMenuItem(createAnalyzerAction(
suite.getDescription(), suiteName, suiteAnalyzers, false)); suite.getDescription(), suiteName, suiteAnalyzers, false));
group.add(rbMenuItem); group.add(rbMenuItem);
popupMenu.add(rbMenuItem); analyzerMenu.add(rbMenuItem);
logger.debug("Loaded radio logger analyzers: " + suite.getDescription()); logger.debug("Loaded radio logger analyzers: " + suite.getDescription());
} catch (InstantiationException e1) { } catch (InstantiationException e1) {
logger.warn("Failed to load analyzer suite '" + suiteName + "': " + e1.getMessage()); logger.warn("Failed to load analyzer suite '" + suiteName + "': " + e1.getMessage());
@ -457,7 +522,7 @@ public class RadioLogger extends VisPlugin {
if (isVisible) { if (isVisible) {
dataTable.scrollRectToVisible(dataTable.getCellRect(dataTable.getRowCount() - 1, 0, true)); dataTable.scrollRectToVisible(dataTable.getCellRect(dataTable.getRowCount() - 1, 0, true));
} }
setTitle("Radio messages: " + dataTable.getRowCount() + " messages seen"); setTitle("Radio messages: showing " + dataTable.getRowCount() + "/" + connections.size() + " packets");
} }
}); });
} }
@ -471,6 +536,11 @@ public class RadioLogger extends VisPlugin {
} }
} }
public void startPlugin() {
super.startPlugin();
rebuildAllEntries();
}
private void searchSelectNext(String text, boolean reverse) { private void searchSelectNext(String text, boolean reverse) {
if (text.isEmpty()) { if (text.isEmpty()) {
return; return;
@ -514,18 +584,75 @@ public class RadioLogger extends VisPlugin {
public void trySelectTime(final long time) { public void trySelectTime(final long time) {
java.awt.EventQueue.invokeLater(new Runnable() { java.awt.EventQueue.invokeLater(new Runnable() {
public void run() { public void run() {
for (int i=0; i < connections.size(); i++) { if (dataTable.getRowCount() == 0) {
if (connections.get(i).endTime < time) {
continue;
}
dataTable.scrollRectToVisible(dataTable.getCellRect(i, 0, true));
dataTable.setRowSelectionInterval(i, i);
return; return;
} }
for (int ai=0; ai < model.getRowCount(); ai++) {
int index = dataTable.convertRowIndexToModel(ai);
if (connections.get(index).endTime < time) {
continue;
}
dataTable.scrollRectToVisible(dataTable.getCellRect(ai, 0, true));
dataTable.setRowSelectionInterval(ai, ai);
return;
}
dataTable.scrollRectToVisible(dataTable.getCellRect(dataTable.getRowCount()-1, 0, true));
dataTable.setRowSelectionInterval(dataTable.getRowCount()-1, dataTable.getRowCount()-1);
} }
}); });
} }
private void applyFilter() {
for(RadioConnectionLog conn: connections) {
conn.data = null;
conn.tooltip = null;
conn.hides = 0;
conn.hiddenBy = null;
}
try {
logFilter.setRowFilter(null);
RowFilter<Object, Object> filter = new RowFilter<Object, Object>() {
public boolean include(RowFilter.Entry<? extends Object, ? extends Object> entry) {
int row = (Integer) entry.getIdentifier();
RadioConnectionLog current = connections.get(row);
byte[] currentData = current.packet.getPacketData();
if (!showDuplicates && row > 0) {
RadioConnectionLog previous = connections.get(row-1);
byte[] previousData = previous.packet.getPacketData();
if (!showDuplicates &&
Arrays.equals(previousData, currentData) &&
previous.connection.getSource() == current.connection.getSource() &&
Arrays.equals(previous.connection.getAllDestinations(), current.connection.getAllDestinations())) {
if (connections.get(row-1).hiddenBy == null) {
connections.get(row-1).hides++;
connections.get(row).hiddenBy = connections.get(row-1);
} else {
connections.get(row-1).hiddenBy.hides++;
connections.get(row).hiddenBy = connections.get(row-1).hiddenBy;
}
return false;
}
}
if (hideNoDestinationPackets) {
if (current.connection.getDestinations().length == 0) {
return false;
}
}
return true;
}
};
logFilter.setRowFilter(filter);
} catch (PatternSyntaxException e) {
logFilter.setRowFilter(null);
logger.warn("Error when setting table filter: " + e.getMessage());
}
}
private void prepareDataString(RadioConnectionLog conn) { private void prepareDataString(RadioConnectionLog conn) {
byte[] data; byte[] data;
if (conn.packet == null) { if (conn.packet == null) {
@ -646,6 +773,19 @@ public class RadioLogger extends VisPlugin {
element.addContent(Integer.toString(splitPane.getDividerLocation())); element.addContent(Integer.toString(splitPane.getDividerLocation()));
config.add(element); config.add(element);
if (formatTimeString) {
element = new Element("formatted_time");
config.add(element);
}
element = new Element("showdups");
element.addContent(Boolean.toString(showDuplicates));
config.add(element);
element = new Element("hidenodests");
element.addContent(Boolean.toString(hideNoDestinationPackets));
config.add(element);
if (analyzerName != null && analyzers != null) { if (analyzerName != null && analyzers != null) {
element = new Element("analyzers"); element = new Element("analyzers");
element.setAttribute("name", analyzerName); element.setAttribute("name", analyzerName);
@ -676,6 +816,12 @@ public class RadioLogger extends VisPlugin {
aliases.put(payload, alias); aliases.put(payload, alias);
} else if ("split".equals(name)) { } else if ("split".equals(name)) {
splitPane.setDividerLocation(Integer.parseInt(element.getText())); splitPane.setDividerLocation(Integer.parseInt(element.getText()));
} else if ("formatted_time".equals(name)) {
formatTimeString = true;
} else if ("showdups".equals(name)) {
showDuplicates = Boolean.parseBoolean(element.getText());
} else if ("hidenodests".equals(name)) {
hideNoDestinationPackets = Boolean.parseBoolean(element.getText());
} else if ("analyzers".equals(name)) { } else if ("analyzers".equals(name)) {
String analyzerName = element.getAttributeValue("name"); String analyzerName = element.getAttributeValue("name");
final Action action; final Action action;
@ -697,6 +843,9 @@ public class RadioLogger extends VisPlugin {
long endTime; long endTime;
RadioConnection connection; RadioConnection connection;
RadioPacket packet; RadioPacket packet;
RadioConnectionLog hiddenBy = null;
int hides = 0;
String data = null; String data = null;
String tooltip = null; String tooltip = null;
@ -729,6 +878,18 @@ public class RadioLogger extends VisPlugin {
return sb.toString(); return sb.toString();
} }
private void rebuildAllEntries() {
applyFilter();
if (connections.size() > 0) {
model.fireTableRowsUpdated(0, connections.size() - 1);
}
verboseBox.setText("");
setTitle("Radio messages: showing " + dataTable.getRowCount() + "/" + connections.size() + " packets");
simulation.getGUI().getDesktopPane().repaint();
}
private Action createAnalyzerAction(String name, final String actionName, private Action createAnalyzerAction(String name, final String actionName,
final ArrayList<PacketAnalyzer> analyzerList, boolean selected) { final ArrayList<PacketAnalyzer> analyzerList, boolean selected) {
Action action = new AbstractAction(name) { Action action = new AbstractAction(name) {
@ -738,16 +899,7 @@ public class RadioLogger extends VisPlugin {
if (analyzers != analyzerList) { if (analyzers != analyzerList) {
analyzers = analyzerList; analyzers = analyzerList;
analyzerName = actionName; analyzerName = actionName;
if (connections.size() > 0) { rebuildAllEntries();
// Remove the cached values
for(int i = 0; i < connections.size(); i++) {
RadioConnectionLog conn = connections.get(i);
conn.data = null;
conn.tooltip = null;
}
model.fireTableRowsUpdated(0, connections.size() - 1);
}
verboseBox.setText("");
} }
} }
}; };
@ -764,7 +916,7 @@ public class RadioLogger extends VisPlugin {
if (size > 0) { if (size > 0) {
connections.clear(); connections.clear();
model.fireTableRowsDeleted(0, size - 1); model.fireTableRowsDeleted(0, size - 1);
setTitle("Radio Logger: " + dataTable.getRowCount() + " packets"); setTitle("Radio messages: showing " + dataTable.getRowCount() + "/" + connections.size() + " packets");
} }
} }
}; };
@ -779,11 +931,8 @@ public class RadioLogger extends VisPlugin {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (int i: selectedRows) { for (int i: selectedRows) {
sb.append(i + 1).append('\t'); int iModel = dataTable.convertRowIndexToModel(i);
sb.append(dataTable.getValueAt(i, COLUMN_TIME)).append('\t'); sb.append(connections.get(iModel).toString() + "\n");
sb.append(dataTable.getValueAt(i, COLUMN_FROM)).append('\t');
sb.append(getDestString(connections.get(i))).append('\t');
sb.append(dataTable.getValueAt(i, COLUMN_DATA)).append('\n');
} }
StringSelection stringSelection = new StringSelection(sb.toString()); StringSelection stringSelection = new StringSelection(sb.toString());
@ -799,11 +948,7 @@ public class RadioLogger extends VisPlugin {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for(int i=0; i < connections.size(); i++) { for(int i=0; i < connections.size(); i++) {
sb.append("" + (i + 1) + '\t'); sb.append(connections.get(i).toString() + "\n");
sb.append("" + dataTable.getValueAt(i, COLUMN_TIME) + '\t');
sb.append("" + dataTable.getValueAt(i, COLUMN_FROM) + '\t');
sb.append("" + getDestString(connections.get(i)) + '\t');
sb.append("" + dataTable.getValueAt(i, COLUMN_DATA) + '\n');
} }
StringSelection stringSelection = new StringSelection(sb.toString()); StringSelection stringSelection = new StringSelection(sb.toString());
@ -844,11 +989,7 @@ public class RadioLogger extends VisPlugin {
try { try {
PrintWriter outStream = new PrintWriter(new FileWriter(saveFile)); PrintWriter outStream = new PrintWriter(new FileWriter(saveFile));
for(int i=0; i < connections.size(); i++) { for(int i=0; i < connections.size(); i++) {
outStream.print("" + (i + 1) + '\t'); outStream.print(connections.get(i).toString() + "\n");
outStream.print("" + dataTable.getValueAt(i, COLUMN_TIME) + '\t');
outStream.print("" + dataTable.getValueAt(i, COLUMN_FROM) + '\t');
outStream.print("" + getDestString(connections.get(i)) + '\t');
outStream.print("" + dataTable.getValueAt(i, COLUMN_DATA) + '\n');
} }
outStream.close(); outStream.close();
} catch (Exception ex) { } catch (Exception ex) {
@ -864,6 +1005,9 @@ public class RadioLogger extends VisPlugin {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
int selectedRow = dataTable.getSelectedRow(); int selectedRow = dataTable.getSelectedRow();
if (selectedRow < 0) return; if (selectedRow < 0) return;
selectedRow = dataTable.convertRowIndexToModel(selectedRow);
if (selectedRow < 0) return;
long time = connections.get(selectedRow).startTime; long time = connections.get(selectedRow).startTime;
Plugin[] plugins = simulation.getGUI().getStartedPlugins(); Plugin[] plugins = simulation.getGUI().getStartedPlugins();
@ -884,6 +1028,9 @@ public class RadioLogger extends VisPlugin {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
int selectedRow = dataTable.getSelectedRow(); int selectedRow = dataTable.getSelectedRow();
if (selectedRow < 0) return; if (selectedRow < 0) return;
selectedRow = dataTable.convertRowIndexToModel(selectedRow);
if (selectedRow < 0) return;
long time = connections.get(selectedRow).startTime; long time = connections.get(selectedRow).startTime;
Plugin[] plugins = simulation.getGUI().getStartedPlugins(); Plugin[] plugins = simulation.getGUI().getStartedPlugins();
@ -917,6 +1064,8 @@ public class RadioLogger extends VisPlugin {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
int selectedRow = dataTable.getSelectedRow(); int selectedRow = dataTable.getSelectedRow();
if (selectedRow < 0) return; if (selectedRow < 0) return;
selectedRow = dataTable.convertRowIndexToModel(selectedRow);
if (selectedRow < 0) return;
String current = ""; String current = "";
if (aliases != null && aliases.get(connections.get(selectedRow).data) != null) { if (aliases != null && aliases.get(connections.get(selectedRow).data) != null) {
@ -961,6 +1110,22 @@ public class RadioLogger extends VisPlugin {
} }
}; };
private boolean showDuplicates = false;
private AbstractAction showDuplicatesAction = new AbstractAction("Show duplicates") {
public void actionPerformed(ActionEvent e) {
showDuplicates = !showDuplicates;
rebuildAllEntries();
}
};
private boolean hideNoDestinationPackets = false;
private AbstractAction hideNoDestinationAction = new AbstractAction("Hide airshots") {
public void actionPerformed(ActionEvent e) {
hideNoDestinationPackets = !hideNoDestinationPackets;
rebuildAllEntries();
}
};
public String getConnectionsString() { public String getConnectionsString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
RadioConnectionLog[] cs = connections.toArray(new RadioConnectionLog[0]); RadioConnectionLog[] cs = connections.toArray(new RadioConnectionLog[0]);