package org.yamcs.ui.eventviewer;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableRowSorter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yamcs.ConfigurationException;
import org.yamcs.YConfiguration;
import org.yamcs.YamcsException;
import org.yamcs.api.YamcsConnectDialog;
import org.yamcs.api.YamcsConnectionProperties;
import org.yamcs.api.YamcsConnectDialog.YamcsConnectDialogResult;
import org.yamcs.api.ws.ConnectionListener;
import org.yamcs.protobuf.Yamcs.Event;
import org.yamcs.protobuf.Yamcs.Event.EventSeverity;
import org.yamcs.ui.YamcsConnector;
import org.yamcs.utils.TimeEncoding;
import com.csvreader.CsvWriter;
public class EventViewer extends JFrame implements ActionListener, ItemListener, MenuListener, ConnectionListener {
private static final long serialVersionUID = 1L;
static Logger log= LoggerFactory.getLogger(EventViewer.class);
// colors taken from USS configuration
final Color iconColorGreen = new Color(0x86B78A);
final Color iconColorRed = new Color(0xB88687);
Color iconColorGrey; // obtained
// during
// gui
// build
EventTableModel tableModel = null;
TableRowSorter<EventTableModel> tableSorter = null;
public JTextArea logTextArea = null;
JMenuItem miAutoScroll = null;
JMenuItem miShowErrors = null;
JMenuItem miRetrievePast = null;
EventTable eventTable = null;
JScrollPane eventPane = null;
JLabel labelEventCount = null;
JLabel labelWarnings = null;
JLabel labelErrors = null;
JLabel fwLabel = null;
JLabel upLabel = null;
JLabel dnLabel = null;
Icon fwOKIcon = null;
Icon fwNOKIcon = null;
Icon upOKIcon = null;
Icon upNOKIcon = null;
Icon dnOKIcon = null;
Icon dnNOKIcon = null;
int eventCount = 0;
int warningCount = 0;
int errorCount = 0;
JFileChooser filechooser = null;
PreferencesDialog preferencesDialog = null;
EventReceiver eventReceiver = null;
YamcsConnector yconnector = null;
String currentUrl = null;
String currentChannel = null;
boolean connected = false;
Thread connectingThread = null;
private String soundFile = null;
List<Map<String,String>> extraColumns = null;
private Clip alertClip = null;
private JPopupMenu popupMenu = null;
/** Table model with filtering table */
private FilteringRulesTable rules = null;
/** View menu */
private JMenu viewMenu = null;
/** Mapping of filtering rules into menu */
private HashMap<JCheckBoxMenuItem, Integer> viewMenuFilterChkBoxes = null;
boolean authenticationEnabled = false;
/**
* Read properties from configuration file
*/
private void readConfiguration() throws ConfigurationException {
YConfiguration cfg = null;
cfg = YConfiguration.getConfiguration("event-viewer");
if(cfg.containsKey("soundfile")) {
soundFile = cfg.getString("soundfile");
}
if(cfg.containsKey("extraColumns")) {
extraColumns=cfg.getList("extraColumns");
}
}
/**
* Access to table with filtering rules
* @return Instance of the filtering table
*/
public FilteringRulesTable getFilteringRulesTable() {
if (rules == null) {
rules = new FilteringRulesTable();
}
return rules;
}
public EventTableModel getEventTable() {
return tableModel;
}
public EventViewer(YamcsConnector yc, final EventReceiver eventReceiver) throws ConfigurationException {
super();
YConfiguration config = YConfiguration.getConfiguration("yamcs-ui");
if(config.containsKey("authenticationEnabled")) {
authenticationEnabled = config.getBoolean("authenticationEnabled");
}
this.yconnector = yc;
this.eventReceiver = eventReceiver;
readConfiguration();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent arg0) {
eventTable.storePreferences();
dispose();
}
});
setIconImage(getIcon("yamcs-event-32.png").getImage());
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("shutting down");
yconnector.disconnect();
}
});
eventCount = 0;
warningCount = 0;
errorCount = 0;
//
// menu
//
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_F);
menuBar.add(menu);
// Ctrl on win/linux, Command on mac
int menuKey=Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
JMenuItem menuItem = new JMenuItem("Connect to Yamcs...");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, menuKey));
menuItem.addActionListener(this);
menuItem.setActionCommand("connect");
menu.add(menuItem);
menu.addSeparator();
miRetrievePast = new JMenuItem("Retrieve Past Events...");
miRetrievePast.addActionListener(this);
miRetrievePast.setActionCommand("retrieve_past");
menu.add(miRetrievePast);
miRetrievePast.setEnabled(false);
menu.addSeparator();
menuItem = new JMenuItem("Save As...", KeyEvent.VK_S);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, menuKey));
menuItem.addActionListener(this);
menuItem.setActionCommand("save");
menu.add(menuItem);
menu.addSeparator();
menuItem = new JMenuItem("Quit", KeyEvent.VK_Q);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, menuKey));
menuItem.getAccessibleContext().setAccessibleDescription("Quit the event viewer");
menuItem.addActionListener(this);
menuItem.setActionCommand("exit");
menu.add(menuItem);
// Edit menu
menu = new JMenu("Edit");
menu.setMnemonic(KeyEvent.VK_E);
menuItem = new JMenuItem("Preferences", KeyEvent.VK_P);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, menuKey));
menuItem.getAccessibleContext().setAccessibleDescription("Edit preferences");
menuItem.addActionListener(this);
menuItem.setActionCommand("preferences");
menu.add(menuItem);
menuBar.add(menu);
// View menu
viewMenu = new JMenu("View");
viewMenu.setMnemonic(KeyEvent.VK_V);
viewMenu.addMenuListener(this);
miAutoScroll = new JCheckBoxMenuItem("Auto-Scroll");
miAutoScroll.setSelected(true);
viewMenu.add(miAutoScroll);
viewMenu.addSeparator();
menuItem = new JMenuItem("Clear", KeyEvent.VK_C);
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, menuKey));
menuItem.addActionListener(this);
menuItem.setActionCommand("clear");
viewMenu.add(menuItem);
menuBar.add(viewMenu);
populateViewMenu();
viewMenu.addSeparator();
//
// frame content
//
Box panel = Box.createHorizontalBox();
getContentPane().add(panel, BorderLayout.SOUTH);
panel.add(Box.createHorizontalStrut(20));
panel.add(new JLabel("Total Events:"));
labelEventCount = new JLabel(String.valueOf(eventCount));
labelEventCount.setPreferredSize(new Dimension(50, labelEventCount.getPreferredSize().height));
labelEventCount.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
labelEventCount.setHorizontalAlignment(SwingConstants.RIGHT);
panel.add(labelEventCount);
panel.add(Box.createHorizontalStrut(20));
panel.add(new JLabel("Warnings:"));
labelWarnings = new JLabel(String.valueOf(warningCount));
labelWarnings.setPreferredSize(new Dimension(50, labelWarnings.getPreferredSize().height));
labelWarnings.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
labelWarnings.setHorizontalAlignment(SwingConstants.RIGHT);
panel.add(labelWarnings);
panel.add(Box.createHorizontalStrut(20));
panel.add(new JLabel("Errors:"));
labelErrors = new JLabel(String.valueOf(errorCount));
labelErrors.setPreferredSize(new Dimension(50, labelErrors.getPreferredSize().height));
labelErrors.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
labelErrors.setHorizontalAlignment(SwingConstants.RIGHT);
panel.add(labelErrors);
panel.add(Box.createHorizontalGlue());
fwOKIcon = getIcon("fwLinkActive.gif");
fwNOKIcon = getIcon("fwLinkInactive.gif");
upOKIcon = getIcon("upLinkActive.gif");
upNOKIcon = getIcon("upLinkInactive.gif");
dnOKIcon = getIcon("dnLinkActive.gif");
dnNOKIcon = getIcon("dnLinkInactive.gif");
fwLabel = new JLabel(fwNOKIcon);
fwLabel.setOpaque(true);
fwLabel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
panel.add(fwLabel);
iconColorGrey = fwLabel.getBackground();
upLabel = new JLabel(upNOKIcon);
upLabel.setOpaque(true);
upLabel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
panel.add(upLabel);
dnLabel = new JLabel(dnNOKIcon);
dnLabel.setOpaque(true);
dnLabel.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
panel.add(dnLabel);
// event table
tableModel = new EventTableModel(getFilteringRulesTable(), extraColumns);
eventTable = new EventTable(tableModel);
eventTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
eventTable.setPreferredScrollableViewportSize(new Dimension(920, 400));
tableSorter = new TableRowSorter<EventTableModel>(tableModel);
eventTable.setRowSorter(tableSorter);
final TableColumnModel tcm = eventTable.getColumnModel();
tcm.getColumn(eventTable.convertColumnIndexToView(EventTableModel.SOURCE_COL)).setMaxWidth(200);
tcm.getColumn(eventTable.convertColumnIndexToView(EventTableModel.GENERATION_TIME_COL)).setMaxWidth(200);
tcm.getColumn(eventTable.convertColumnIndexToView(EventTableModel.RECEPTION_TIME_COL)).setMaxWidth(200);
tcm.getColumn(eventTable.convertColumnIndexToView(EventTableModel.EVENT_TYPE_COL)).setMaxWidth(150);
tcm.getColumn(eventTable.convertColumnIndexToView(EventTableModel.SOURCE_COL)).setPreferredWidth(100);
tcm.getColumn(eventTable.convertColumnIndexToView(EventTableModel.GENERATION_TIME_COL)).setPreferredWidth(200);
tcm.getColumn(eventTable.convertColumnIndexToView(EventTableModel.RECEPTION_TIME_COL)).setPreferredWidth(100);
tcm.getColumn(eventTable.convertColumnIndexToView(EventTableModel.EVENT_TYPE_COL)).setPreferredWidth(100);
tcm.getColumn(eventTable.convertColumnIndexToView(EventTableModel.EVENT_TEXT_COL)).setPreferredWidth(400);
eventPane = new JScrollPane(eventTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
// status log area
logTextArea = new JTextArea(5, 20);
logTextArea.setEditable(false);
JScrollPane logPane = new JScrollPane(logTextArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, eventPane, logPane);
split.setResizeWeight(1.0);
split.setContinuousLayout(true);
getContentPane().add(split, BorderLayout.CENTER);
// popup menu
popupMenu = new JPopupMenu();
JMenuItem item = new JMenuItem("New filtering rule");
item.setActionCommand("new_rule_popup");
item.addActionListener(this);
popupMenu.add(item);
item=new JMenuItem("Details...");
item.setActionCommand("show_event_details");
item.addActionListener(this);
popupMenu.add(item);
popupMenu.setBorder(new BevelBorder(BevelBorder.RAISED));
eventTable.addMouseListener(new MousePopupListener());
// prepare model names
updateStatus();
pack();
setLocation(30, 30);
setVisible(true);
eventReceiver.setEventViewer(this);
yconnector.addConnectionListener(this);
}
public void populateViewMenu() {
if (viewMenuFilterChkBoxes == null) {
viewMenuFilterChkBoxes = new HashMap<JCheckBoxMenuItem, Integer>(25);
}
for (JCheckBoxMenuItem item : viewMenuFilterChkBoxes.keySet()) {
viewMenu.remove(item);
}
viewMenuFilterChkBoxes.clear();
JCheckBoxMenuItem item = null;
Vector<FilteringRule> rules = getFilteringRulesTable().getRules();
String label = "";
for (int i = 0; i < rules.size(); ++i) {
FilteringRule rule = rules.elementAt(i);
label = (rule.isShowOn()) ? "Show - " : "Hide - ";
label += rule.getName();
item = new JCheckBoxMenuItem(label);
item.setSelected(rule.isActive());
getFilteringRulesTable().writeFilteringRules();
item.addActionListener(this);
item.setActionCommand("switch_rule_status");
viewMenu.add(item);
viewMenuFilterChkBoxes.put(item, i);
}
}
/**
* Shows event in the detail dialog
* @param event Event to be presented
*/
private void showEventInDetailDialog(Event event) {
EventDialog detailDialog = new EventDialog(this);
detailDialog.setEvent(event);
detailDialog.setVisible(true);
}
// ***********
// An inner class to check whether mouse events are the popup trigger
class MousePopupListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
checkPopup(e);
}
@Override
public void mouseClicked(MouseEvent e) {
checkPopup(e);
if (e.getClickCount() == 2) {
JTable target = (JTable) e.getSource();
int row = target.getSelectedRow();
showEventInDetailDialog(((EventTableModel)target.getModel()).getEvent(row));
}
}
@Override
public void mouseReleased(MouseEvent e) {
checkPopup(e);
}
private void checkPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
// show the popup menu and select the row under the mouse pointer.
// If multiple rows are selected keep them selected, unless the right
// click landed on a previously unselected row.
int row = eventTable.rowAtPoint(e.getPoint());
if(!eventTable.getSelectionModel().isSelectedIndex(row)) {
eventTable.getSelectionModel().setSelectionInterval(row, row);
} else {
popupMenu.show(eventTable, e.getX(), e.getY());
}
}
}
}
// ****************
public ImageIcon getIcon(String imagename) {
return new ImageIcon(getClass().getResource("/org/yamcs/images/" + imagename));
}
public void updateStatus() {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
StringBuffer title = new StringBuffer("Event Viewer");
if (yconnector.isConnected()) {
if (miRetrievePast != null) miRetrievePast.setEnabled(true);
title.append(" (connected)");
fwLabel.setBackground(iconColorGreen);
fwLabel.setIcon(fwOKIcon);
upLabel.setBackground(iconColorGreen);
upLabel.setIcon(upOKIcon);
dnLabel.setBackground(iconColorGreen);
dnLabel.setIcon(dnOKIcon);
} else if (yconnector.isConnecting()) {
if (miRetrievePast != null)
miRetrievePast.setEnabled(false);
title.append(" (connecting)");
fwLabel.setBackground(iconColorGrey);
upLabel.setBackground(iconColorGrey);
dnLabel.setBackground(iconColorGrey);
} else {
if (miRetrievePast != null)
miRetrievePast.setEnabled(false);
title.append(" (not connected)");
fwLabel.setBackground(iconColorGrey);
upLabel.setBackground(iconColorGrey);
dnLabel.setBackground(iconColorGrey);
}
setTitle(title.toString());
}
});
}
@Override
public void connected(String url) {
log("Connected to "+url);
updateStatus();
}
@Override
public void connecting(String url) {
log("Connecting to "+url);
updateStatus();
}
@Override
public void disconnected() {
log("Disconnected");
updateStatus();
}
@Override
public void connectionFailed(String url, YamcsException exception) {
log("Connection to "+url+" failed: "+exception);
updateStatus();
}
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd.equals("connect")) {
YamcsConnectDialogResult r = YamcsConnectDialog.showDialog(this, true, authenticationEnabled);
if( r.isOk() ) {
yconnector.connect(r.getConnectionProperties());
}
} else if (cmd.equals("retrieve_past")) {
eventReceiver.retrievePastEvents();
} else if (cmd.equals("switch_rule_status")) {
JCheckBoxMenuItem item = (JCheckBoxMenuItem) e.getSource();
int index = viewMenuFilterChkBoxes.get(item);
getFilteringRulesTable().switchRuleActivation(index, item.isSelected());
} else if (cmd.equals("clear")) {
clearTable();
} else if (cmd.equals("save")) {
saveTableAs();
} else if (cmd.equals("exit")) {
processWindowEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
} else if (cmd.equals("preferences")) {
getPreferencesDialog().setVisible(true);
} else if (cmd.equals("new_rule_popup")) {
int[] rows = eventTable.getSelectedRows();
for (int row : rows) {
FilteringRule rule = new FilteringRule();
Event event = ((EventTableModel) eventTable.getModel()).getEvent(row);
rule.setSource(event.getSource());
rule.setEventType(event.getType());
rule.setEventText(event.getMessage());
rule.setSeverity(event.getSeverity());
getPreferencesDialog().addNewRule(rule);
}
getPreferencesDialog().setVisible(true);
} else if (cmd.equals("show_event_details")) {
showEventInDetailDialog(((EventTableModel)eventTable.getModel()).getEvent(eventTable.getSelectedRow()));
}
}
private void showAlertPopupDialog(Event event) {
int messageType = JOptionPane.INFORMATION_MESSAGE;
switch (event.getSeverity()) {
case INFO:
messageType = JOptionPane.INFORMATION_MESSAGE;
break;
case WARNING:
messageType = JOptionPane.WARNING_MESSAGE;
break;
case ERROR:
messageType = JOptionPane.ERROR_MESSAGE;
break;
default:
messageType = JOptionPane.INFORMATION_MESSAGE;
}
JOptionPane.showMessageDialog(this, event.toString(), "Alert message", messageType);
}
/**
* Shows Preferences dialog (modal)
*/
private PreferencesDialog getPreferencesDialog() {
if (preferencesDialog == null) {
preferencesDialog = new PreferencesDialog(this, ModalityType.APPLICATION_MODAL);
}
return preferencesDialog;
}
@Override
public void itemStateChanged(ItemEvent arg0) {
}
@Override
public void log(final String s) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
logTextArea.append(TimeEncoding.toCombinedFormat(TimeEncoding.currentInstant()) + " " + s + "\n");
}
});
}
void clearTable() {
tableModel.clear();
eventCount = 0;
warningCount = 0;
errorCount = 0;
labelEventCount.setText(String.valueOf(eventCount));
labelWarnings.setText(String.valueOf(warningCount));
labelErrors.setText(String.valueOf(errorCount));
eventTable.repaint();
}
void showMessage(String msg) {
JOptionPane.showMessageDialog(this, msg, "Event Viewer", JOptionPane.ERROR_MESSAGE);
}
class ExtendedFileFilter extends FileFilter {
public String ext;
private String desc;
public ExtendedFileFilter(String ext, String desc) {
this.ext = ext;
this.desc = desc;
}
@Override
public boolean accept(File f) {
return f.isDirectory() || f.getName().toLowerCase().endsWith("." + ext);
}
@Override
public String getDescription() {
return desc;
}
public File appendExtensionIfNeeded(File f) {
return accept(f) ? f : new File(f.getPath() + "." + ext);
}
}
void saveTableAs() {
if (filechooser == null) {
filechooser = new JFileChooser() {
private static final long serialVersionUID = 1L;
@Override
public File getSelectedFile() {
File file = super.getSelectedFile();
if (getFileFilter() instanceof ExtendedFileFilter) {
file = ((ExtendedFileFilter) getFileFilter()).appendExtensionIfNeeded(file);
}
return file;
}
@Override
public void approveSelection() {
File file=getSelectedFile();
if(file.exists()) {
int response=JOptionPane.showConfirmDialog(filechooser, "The file "+file+" already exists. Do you want to replace the existing file?", "Overwrite file", JOptionPane.YES_NO_OPTION);
if(response!=JOptionPane.YES_OPTION) {
return;
}
}
super.approveSelection();
}
};
filechooser.setMultiSelectionEnabled(false);
FileFilter csvFilter=new ExtendedFileFilter("csv", "CSV File");
filechooser.addChoosableFileFilter(csvFilter);
FileFilter txtFilter=new ExtendedFileFilter("txt", "Text File");
filechooser.addChoosableFileFilter(txtFilter);
filechooser.setFileFilter(csvFilter); // By default, choose CSV
}
int ret = filechooser.showSaveDialog(this);
if (ret == JFileChooser.APPROVE_OPTION) {
File file=filechooser.getSelectedFile();
CsvWriter writer=null;
try {
writer=new CsvWriter(new FileOutputStream(file), '\t', Charset.forName("UTF-8"));
int cols = tableModel.getColumnCount();
String[] colNames = new String[cols];
colNames[0] = "Source";
colNames[1] = "Generation Time";
colNames[2] = "Reception Time";
colNames[3] = "Event Type";
colNames[4] = "Event Text";
for (int i = 5; i < cols; i++) {
colNames[i] = tableModel.getColumnName(i);
}
writer.writeRecord(colNames);
writer.setForceQualifier(true);
int iend = tableModel.getRowCount();
for (int i = 0; i < iend; i++) {
String[] rec = new String[cols];
rec[0] = (String) tableModel.getValueAt(i, 0);
rec[1] = (String) tableModel.getValueAt(i, 1);
rec[2] = (String) tableModel.getValueAt(i, 2);
rec[3] = (String) tableModel.getValueAt(i, 3);
rec[4] = ((Event) tableModel.getValueAt(i, 4)).getMessage();
for (int j = 5; j < cols; j++) {
rec[j] = (String) tableModel.getValueAt(i, j);
}
writer.writeRecord(rec);
}
} catch (IOException e) {
e.printStackTrace();
showMessage("Could not export events to file '" + file.getPath() + "': " + e.getMessage());
} finally {
writer.close();
}
log("Saved table to " + file.getAbsolutePath());
}
}
public void addEvents(final List<Event> events) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
tableModel.addEvents(events);
for (Event event : events) {
switch (event.getSeverity()) {
case WARNING:
++warningCount;
break;
case ERROR:
++errorCount;
break;
}
++eventCount;
}
labelEventCount.setText(String.valueOf(eventCount));
labelWarnings.setText(String.valueOf(warningCount));
labelErrors.setText(String.valueOf(errorCount));
eventTable.revalidate();
eventPane.validate();
if (miAutoScroll.isSelected()) {
updateVerticalScrollPosition();
}
}
});
}
/**
* Add event. This method is used for incoming events.
* @param event Event to be added.
*/
public void addEvent(final Event event) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
switch (event.getSeverity()) {
case WARNING:
++warningCount;
labelWarnings.setText(String.valueOf(warningCount));
break;
case ERROR:
++errorCount;
labelErrors.setText(String.valueOf(errorCount));
break;
}
++eventCount;
labelEventCount.setText(String.valueOf(eventCount));
tableModel.addEvent(event);
// auto-resize text column (does not resize scrollview)
/*
* TableColumn col = eventTable.getColumnModel().getColumn(4);
* Component cell = eventTable.getCellRenderer(0,
* 4).getTableCellRendererComponent(eventTable, event, false,
* false, 0, 4); int w = cell.getPreferredSize().width + 10; if
* (w > col.getPreferredWidth()) { col.setPreferredWidth(w); }
*/
eventTable.revalidate();
eventPane.validate();
if (miAutoScroll.isSelected()) {
updateVerticalScrollPosition();
}
// alert the user if necessary
AlertType alert = getFilteringRulesTable().getAlertType(event);
if (alert.alertSound) {
playAlertSound();
}
if (alert.alertPopup) {
showAlertPopupDialog(event);
}
}
});
}
/**
* Adjusts vertical scroll position
* (horizontal position remains unchanged)
*/
private void updateVerticalScrollPosition() {
if(eventTable.getRowCount()<=0) return;
int row = eventTable.convertRowIndexToView(eventTable.getRowCount()-1);
int col = eventTable.convertColumnIndexToView(0);
Rectangle rect = eventTable.getCellRect(row, col, true);
// Retain view's x position
int x = eventTable.getVisibleRect().x;
// y should correctly show full contents of multiline text cells.
int y = rect.y;
int textViewColumn = eventTable.convertColumnIndexToView(EventTableModel.EVENT_TEXT_COL);
TableCellRenderer renderer = eventTable.getCellRenderer(row, textViewColumn);
if (renderer instanceof EventTableRenderer) {
Object value = eventTable.getValueAt(row, textViewColumn);
// Trigger an update of the row height
int actualHeight = ((EventTableRenderer)renderer).updateCalculatedHeight(eventTable, value, row);
y += (actualHeight - rect.height);
}
rect.setLocation(new Point(x, y));
eventTable.scrollRectToVisible(rect);
}
/**
* Play the sound
*/
private void playAlertSound() {
new Thread(new Runnable() {
@Override
public void run() {
playSoundFile();
}
}).start();
}
/**
* Access to sound clip.
*
* @return
*/
private Clip getAlertClip() {
if (alertClip == null) {
String defFileName = "/org/yamcs/sounds/alert.wav";
try {
AudioInputStream inputStream = null;
if (soundFile == null) {
inputStream = AudioSystem.getAudioInputStream(new BufferedInputStream(getClass().getResourceAsStream(defFileName)));
} else {
inputStream = AudioSystem.getAudioInputStream(new File(soundFile));
}
AudioFormat format = inputStream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, format);
alertClip = (Clip)AudioSystem.getLine(info);
alertClip.open(inputStream);
} catch (Exception e) {
log.warn("Error occured while playing sound clip ", e);
alertClip = null;
}
}
return alertClip;
}
/**
* Plays file. This method is not synchronized.
*
* @param fileName File with the sound resource
* @todo This method should be accessed only by one thread.....
*/
private void playSoundFile() {
Clip clip = null;
try {
clip = getAlertClip();
if (clip == null)
return;
clip.stop();
clip.setFramePosition(0);
clip.start();
// sleep while the sound is playing
Thread.sleep(clip.getMicrosecondLength());
} catch (InterruptedException ie) {
// ok
} catch (Exception e) {
System.err.println("Error occured while playing the clip: " + e.getMessage());
} finally {
if (clip != null) {
clip.stop();
clip.setFramePosition(0);
}
}
}
private static void printUsageAndExit() {
System.err.println("Usage event-viewer.sh yamcsurl");
System.err.println("Example:\n\tevent-viewer.sh http://localhost:8090/yops");
System.exit(-1);
}
void test(EventViewer ev) {
// test
for (int evId = 0; evId < 12; ++evId) {
Event.Builder builder = Event.newBuilder();
builder.setGenerationTime(5000);
builder.setReceptionTime(56000);
builder.setMessage("This is eventX message");
builder.setSource("ACES");
builder.setType("ASW_CMD_ERR aaa");
builder.setSeqNumber(evId);
builder.setSeverity(EventSeverity.ERROR);
Event event = builder.build();
ev.addEvent(event);
}
for (int evId = 0; evId < 12; ++evId) {
Event.Builder builder = Event.newBuilder();
builder.setGenerationTime(5000);
builder.setReceptionTime(56000);
builder.setMessage("This is event message");
builder.setSource("ACES_X");
builder.setType("ASW_CMD_ERR");
builder.setSeqNumber(evId);
Event event = builder.build();
ev.addEvent(event);
}
}
//Not used for the moment. TODO
public void setStatusTm(String opsname, String value) {
if (opsname.equals("CDMCS_FWLINK_STATUS")) {
if (value.equalsIgnoreCase("OK")) {
fwLabel.setBackground(iconColorGreen);
fwLabel.setIcon(fwOKIcon);
} else {
fwLabel.setBackground(iconColorRed);
fwLabel.setIcon(fwNOKIcon);
}
fwLabel.setToolTipText(opsname + " = " + value);
} else if (opsname.equals("CDMCS_UPLINK_STATUS")) {
if (value.equalsIgnoreCase("OK")) {
upLabel.setIcon(upOKIcon);
upLabel.setBackground(iconColorGreen);
} else {
upLabel.setIcon(upNOKIcon);
upLabel.setBackground(iconColorRed);
}
upLabel.setToolTipText(opsname + " = " + value);
} else if (opsname.equals("CDMCS_DOWNLINK_STATUS")) {
if (value.equalsIgnoreCase("OK")) {
dnLabel.setIcon(dnOKIcon);
dnLabel.setBackground(iconColorGreen);
} else {
dnLabel.setIcon(dnNOKIcon);
dnLabel.setBackground(iconColorRed);
}
dnLabel.setToolTipText(opsname + " = " + value);
}
}
/**
* Application entry point.
*
* @param args
* @throws IOException
* @throws ConfigurationException
* @throws URISyntaxException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws ClassNotFoundException
*/
public static void main(String[] args) throws IOException, ConfigurationException, URISyntaxException, ClassNotFoundException, InstantiationException, IllegalAccessException {
if (args.length > 1) printUsageAndExit();
YConfiguration.setup();
YamcsConnectionProperties ycd = null;
if(args.length==1) {
if (args[0].startsWith("http")) {
ycd = YamcsConnectionProperties.parse(args[0]);
} else {
printUsageAndExit();
}
}
YamcsConnector yconnector=new YamcsConnector("EventViewer");
YamcsEventReceiver eventReceiver = new YamcsEventReceiver(yconnector);
EventViewer ev = new EventViewer(yconnector, eventReceiver);
if(ycd!=null) yconnector.connect(ycd);
}
@Override
public void menuSelected(MenuEvent e) {
populateViewMenu();
}
@Override
public void menuDeselected(MenuEvent e) {
// do nothing
}
@Override
public void menuCanceled(MenuEvent e) {
// do nothing
}
}