added new optional features: time formatting, hide-duplicate-packets, hide-airshot-packets
This commit is contained in:
parent
bda04947e7
commit
492cd5f721
1 changed files with 213 additions and 48 deletions
|
@ -40,20 +40,24 @@ import java.awt.datatransfer.StringSelection;
|
|||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Observable;
|
||||
import java.util.Observer;
|
||||
import java.util.Properties;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.JCheckBoxMenuItem;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
|
@ -68,9 +72,12 @@ import javax.swing.JTable;
|
|||
import javax.swing.JTextField;
|
||||
import javax.swing.JTextPane;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.RowFilter;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.TableModel;
|
||||
import javax.swing.table.TableRowSorter;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.jdom.Element;
|
||||
|
@ -116,9 +123,11 @@ public class RadioLogger extends VisPlugin {
|
|||
private JSplitPane splitPane;
|
||||
private JTextPane verboseBox = null;
|
||||
|
||||
private boolean formatTimeString = true;
|
||||
|
||||
private final static String[] COLUMN_NAMES = {
|
||||
"No.",
|
||||
"Time",
|
||||
"No. ",
|
||||
"Time ms",
|
||||
"From",
|
||||
"To",
|
||||
"Data"
|
||||
|
@ -126,6 +135,7 @@ public class RadioLogger extends VisPlugin {
|
|||
|
||||
private final Simulation simulation;
|
||||
private final JTable dataTable;
|
||||
private TableRowSorter<TableModel> logFilter;
|
||||
private ArrayList<RadioConnectionLog> connections = new ArrayList<RadioConnectionLog>();
|
||||
private RadioMedium radioMedium;
|
||||
private Observer radioMediumObserver;
|
||||
|
@ -149,7 +159,7 @@ public class RadioLogger extends VisPlugin {
|
|||
JMenu fileMenu = new JMenu("File");
|
||||
JMenu editMenu = new JMenu("Edit");
|
||||
JMenu analyzerMenu = new JMenu("Analyzer");
|
||||
JMenu payloadMenu = new JMenu("Payload");
|
||||
JMenu payloadMenu = new JMenu("View");
|
||||
|
||||
menuBar.add(fileMenu);
|
||||
menuBar.add(editMenu);
|
||||
|
@ -169,11 +179,15 @@ public class RadioLogger extends VisPlugin {
|
|||
lowpanAnalyzersPcap.add(new IPHCPacketAnalyzer());
|
||||
lowpanAnalyzersPcap.add(new IPv6PacketAnalyzer());
|
||||
lowpanAnalyzersPcap.add(new ICMPv6Analyzer());
|
||||
|
||||
model = new AbstractTableModel() {
|
||||
|
||||
private static final long serialVersionUID = 1692207305977527004L;
|
||||
|
||||
public String getColumnName(int col) {
|
||||
if (col == COLUMN_TIME && formatTimeString) {
|
||||
return "Time";
|
||||
}
|
||||
return COLUMN_NAMES[col];
|
||||
}
|
||||
|
||||
|
@ -186,10 +200,19 @@ public class RadioLogger extends VisPlugin {
|
|||
}
|
||||
|
||||
public Object getValueAt(int row, int col) {
|
||||
if (row < 0 || row >= connections.size()) {
|
||||
return "";
|
||||
}
|
||||
RadioConnectionLog conn = connections.get(row);
|
||||
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) {
|
||||
if (formatTimeString) {
|
||||
return LogListener.getFormattedTime(conn.startTime);
|
||||
}
|
||||
return Long.toString(conn.startTime / Simulation.MILLISECOND);
|
||||
} else if (col == COLUMN_FROM) {
|
||||
return "" + conn.connection.getSource().getMote().getID();
|
||||
|
@ -251,14 +274,19 @@ public class RadioLogger extends VisPlugin {
|
|||
public String getToolTipText(MouseEvent e) {
|
||||
java.awt.Point p = e.getPoint();
|
||||
int rowIndex = rowAtPoint(p);
|
||||
if (rowIndex < 0) {
|
||||
return super.getToolTipText(e);
|
||||
}
|
||||
int modelRowIndex = convertRowIndexToModel(rowIndex);
|
||||
int colIndex = columnAtPoint(p);
|
||||
int realColumnIndex = convertColumnIndexToModel(colIndex);
|
||||
if (rowIndex < 0 || realColumnIndex < 0) {
|
||||
int modelColumnIndex = convertColumnIndexToModel(colIndex);
|
||||
if (modelRowIndex < 0 || modelColumnIndex < 0) {
|
||||
return super.getToolTipText(e);
|
||||
}
|
||||
|
||||
RadioConnectionLog conn = connections.get(rowIndex);
|
||||
if (realColumnIndex == COLUMN_TIME) {
|
||||
/* TODO This entry may represent several hidden connections */
|
||||
RadioConnectionLog conn = connections.get(modelRowIndex);
|
||||
if (modelColumnIndex == COLUMN_TIME) {
|
||||
return
|
||||
"<html>" +
|
||||
"Start time (us): " + conn.startTime +
|
||||
|
@ -267,9 +295,9 @@ public class RadioLogger extends VisPlugin {
|
|||
"<br><br>" +
|
||||
"Duration (us): " + (conn.endTime - conn.startTime) +
|
||||
"</html>";
|
||||
} else if (realColumnIndex == COLUMN_FROM) {
|
||||
} else if (modelColumnIndex == COLUMN_FROM) {
|
||||
return conn.connection.getSource().getMote().toString();
|
||||
} else if (realColumnIndex == COLUMN_TO) {
|
||||
} else if (modelColumnIndex == COLUMN_TO) {
|
||||
Radio[] dests = conn.connection.getDestinations();
|
||||
if (dests.length == 0) {
|
||||
return "No destinations";
|
||||
|
@ -286,7 +314,7 @@ public class RadioLogger extends VisPlugin {
|
|||
}
|
||||
tip.append("</html>");
|
||||
return tip.toString();
|
||||
} else if (realColumnIndex == COLUMN_DATA) {
|
||||
} else if (modelColumnIndex == COLUMN_DATA) {
|
||||
if (conn.tooltip == null) {
|
||||
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() {
|
||||
public void keyPressed(KeyEvent e) {
|
||||
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() {
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
int row = dataTable.getSelectedRow();
|
||||
if (row >= 0) {
|
||||
RadioConnectionLog conn = connections.get(row);
|
||||
if (row < 0) {
|
||||
return;
|
||||
}
|
||||
int modelRowIndex = dataTable.convertRowIndexToModel(row);
|
||||
if (modelRowIndex >= 0) {
|
||||
RadioConnectionLog conn = connections.get(modelRowIndex);
|
||||
if (conn.tooltip == null) {
|
||||
prepareTooltipString(conn);
|
||||
}
|
||||
|
@ -338,6 +391,16 @@ public class RadioLogger extends VisPlugin {
|
|||
editMenu.add(new JMenuItem(clearAction));
|
||||
|
||||
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));
|
||||
|
||||
|
@ -369,12 +432,14 @@ public class RadioLogger extends VisPlugin {
|
|||
group.add(rbMenuItem);
|
||||
analyzerMenu.add(rbMenuItem);
|
||||
|
||||
|
||||
/* Load additional analyzers specified by projects (cooja.config) */
|
||||
String[] projectAnalyzerSuites =
|
||||
gui.getProjectConfig().getStringArrayValue(RadioLogger.class, "ANALYZERS");
|
||||
if (projectAnalyzerSuites != null) {
|
||||
for (String suiteName: projectAnalyzerSuites) {
|
||||
if (suiteName == null || suiteName.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
Class<? extends RadioLoggerAnalyzerSuite> suiteClass =
|
||||
gui.tryLoadClass(RadioLogger.this, RadioLoggerAnalyzerSuite.class, suiteName);
|
||||
try {
|
||||
|
@ -383,7 +448,7 @@ public class RadioLogger extends VisPlugin {
|
|||
rbMenuItem = new JRadioButtonMenuItem(createAnalyzerAction(
|
||||
suite.getDescription(), suiteName, suiteAnalyzers, false));
|
||||
group.add(rbMenuItem);
|
||||
popupMenu.add(rbMenuItem);
|
||||
analyzerMenu.add(rbMenuItem);
|
||||
logger.debug("Loaded radio logger analyzers: " + suite.getDescription());
|
||||
} catch (InstantiationException e1) {
|
||||
logger.warn("Failed to load analyzer suite '" + suiteName + "': " + e1.getMessage());
|
||||
|
@ -457,7 +522,7 @@ public class RadioLogger extends VisPlugin {
|
|||
if (isVisible) {
|
||||
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) {
|
||||
if (text.isEmpty()) {
|
||||
return;
|
||||
|
@ -514,18 +584,75 @@ public class RadioLogger extends VisPlugin {
|
|||
public void trySelectTime(final long time) {
|
||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
for (int i=0; i < connections.size(); i++) {
|
||||
if (connections.get(i).endTime < time) {
|
||||
continue;
|
||||
}
|
||||
dataTable.scrollRectToVisible(dataTable.getCellRect(i, 0, true));
|
||||
dataTable.setRowSelectionInterval(i, i);
|
||||
if (dataTable.getRowCount() == 0) {
|
||||
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) {
|
||||
byte[] data;
|
||||
if (conn.packet == null) {
|
||||
|
@ -646,6 +773,19 @@ public class RadioLogger extends VisPlugin {
|
|||
element.addContent(Integer.toString(splitPane.getDividerLocation()));
|
||||
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) {
|
||||
element = new Element("analyzers");
|
||||
element.setAttribute("name", analyzerName);
|
||||
|
@ -676,6 +816,12 @@ public class RadioLogger extends VisPlugin {
|
|||
aliases.put(payload, alias);
|
||||
} else if ("split".equals(name)) {
|
||||
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)) {
|
||||
String analyzerName = element.getAttributeValue("name");
|
||||
final Action action;
|
||||
|
@ -697,6 +843,9 @@ public class RadioLogger extends VisPlugin {
|
|||
long endTime;
|
||||
RadioConnection connection;
|
||||
RadioPacket packet;
|
||||
|
||||
RadioConnectionLog hiddenBy = null;
|
||||
int hides = 0;
|
||||
|
||||
String data = null;
|
||||
String tooltip = null;
|
||||
|
@ -729,6 +878,18 @@ public class RadioLogger extends VisPlugin {
|
|||
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,
|
||||
final ArrayList<PacketAnalyzer> analyzerList, boolean selected) {
|
||||
Action action = new AbstractAction(name) {
|
||||
|
@ -738,16 +899,7 @@ public class RadioLogger extends VisPlugin {
|
|||
if (analyzers != analyzerList) {
|
||||
analyzers = analyzerList;
|
||||
analyzerName = actionName;
|
||||
if (connections.size() > 0) {
|
||||
// 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("");
|
||||
rebuildAllEntries();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -764,7 +916,7 @@ public class RadioLogger extends VisPlugin {
|
|||
if (size > 0) {
|
||||
connections.clear();
|
||||
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();
|
||||
for (int i: selectedRows) {
|
||||
sb.append(i + 1).append('\t');
|
||||
sb.append(dataTable.getValueAt(i, COLUMN_TIME)).append('\t');
|
||||
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');
|
||||
int iModel = dataTable.convertRowIndexToModel(i);
|
||||
sb.append(connections.get(iModel).toString() + "\n");
|
||||
}
|
||||
|
||||
StringSelection stringSelection = new StringSelection(sb.toString());
|
||||
|
@ -799,11 +948,7 @@ public class RadioLogger extends VisPlugin {
|
|||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(int i=0; i < connections.size(); i++) {
|
||||
sb.append("" + (i + 1) + '\t');
|
||||
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');
|
||||
sb.append(connections.get(i).toString() + "\n");
|
||||
}
|
||||
|
||||
StringSelection stringSelection = new StringSelection(sb.toString());
|
||||
|
@ -844,11 +989,7 @@ public class RadioLogger extends VisPlugin {
|
|||
try {
|
||||
PrintWriter outStream = new PrintWriter(new FileWriter(saveFile));
|
||||
for(int i=0; i < connections.size(); i++) {
|
||||
outStream.print("" + (i + 1) + '\t');
|
||||
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.print(connections.get(i).toString() + "\n");
|
||||
}
|
||||
outStream.close();
|
||||
} catch (Exception ex) {
|
||||
|
@ -864,6 +1005,9 @@ public class RadioLogger extends VisPlugin {
|
|||
public void actionPerformed(ActionEvent e) {
|
||||
int selectedRow = dataTable.getSelectedRow();
|
||||
if (selectedRow < 0) return;
|
||||
selectedRow = dataTable.convertRowIndexToModel(selectedRow);
|
||||
if (selectedRow < 0) return;
|
||||
|
||||
long time = connections.get(selectedRow).startTime;
|
||||
|
||||
Plugin[] plugins = simulation.getGUI().getStartedPlugins();
|
||||
|
@ -884,6 +1028,9 @@ public class RadioLogger extends VisPlugin {
|
|||
public void actionPerformed(ActionEvent e) {
|
||||
int selectedRow = dataTable.getSelectedRow();
|
||||
if (selectedRow < 0) return;
|
||||
selectedRow = dataTable.convertRowIndexToModel(selectedRow);
|
||||
if (selectedRow < 0) return;
|
||||
|
||||
long time = connections.get(selectedRow).startTime;
|
||||
|
||||
Plugin[] plugins = simulation.getGUI().getStartedPlugins();
|
||||
|
@ -917,6 +1064,8 @@ public class RadioLogger extends VisPlugin {
|
|||
public void actionPerformed(ActionEvent e) {
|
||||
int selectedRow = dataTable.getSelectedRow();
|
||||
if (selectedRow < 0) return;
|
||||
selectedRow = dataTable.convertRowIndexToModel(selectedRow);
|
||||
if (selectedRow < 0) return;
|
||||
|
||||
String current = "";
|
||||
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() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
RadioConnectionLog[] cs = connections.toArray(new RadioConnectionLog[0]);
|
||||
|
|
Loading…
Reference in a new issue