Author: [log in to unmask] Date: Fri Mar 6 16:19:25 2015 New Revision: 2305 Log: More work on monitoring-app branch. Added: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/LogPanel.java java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/util/TableExporter.java Modified: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/Commands.java java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/LogTable.java java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/MenuBar.java java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/MonitoringApplication.java java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/SettingsDialog.java java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/util/DialogUtil.java java/branches/monitoring-app-HPSJAVA-442/src/main/resources/org/hps/monitoring/config/default_config.prop Modified: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/Commands.java ============================================================================= --- java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/Commands.java (original) +++ java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/Commands.java Fri Mar 6 16:19:25 2015 @@ -1,34 +1,48 @@ package org.hps.monitoring.application; /** - * These strings are used to identify ActionEvents in the MonitoringApplication. A few commands - * handled only by sub-components are not listed here. + * These strings are used to identify ActionEvents in the MonitoringApplication. + * A few commands handled only by sub-components are not listed here. */ final class Commands { - static final String SETTINGS_LOAD = "settingsLoad"; - static final String SETTINGS_LOAD_DEFAULT = "settingsLoadDefault"; - static final String SETTINGS_SAVE = "settingsSave"; - static final String SETTINGS_SHOW = "settingsShow"; + // Settings + static final String LOAD_SETTINGS = "loadSettings"; + static final String LOAD_DEFAULT_SETTINGS = "loadDefaultSettings"; + static final String SAVE_SETTINGS = "saveSettings"; + static final String SHOW_SETTINGS = "showSettings"; - static final String FILE_OPEN = "openFile"; - static final String FILE_CLOSE = "closeFile"; + // File open and close + static final String OPEN_FILE = "openFile"; + static final String CLOSE_FILE = "closeFile"; - static final String WINDOW_MAXIMIZE = "maximizeWindow"; - static final String WINDOW_MINIMIZE = "minimizeWindow"; - static final String WINDOW_DEFAULTS = "restoreDefaultWindow"; + // Window + static final String MAXIMIZE_WINDOW = "maximizeWindow"; + static final String MINIMIZE_WINDOW = "minimizeWindow"; + static final String DEFAULT_WINDOW = "defaultWindow"; + // Data source static final String DATA_SOURCE_CHANGED = "dataSourceChanged"; + // Event commands static final String CONNECT = "connect"; + static final String DISCONNECT = "disconnect"; static final String NEXT = "next"; static final String PAUSE = "pause"; static final String RESUME = "resume"; + // Save a screenshot + static final String SAVE_SCREENSHOT = "saveScreenshot"; + + // Save the plots + static final String SAVE_PLOTS = "savePlots"; + static final String CLEAR_PLOTS = "resetPlots"; + static final String EXIT = "exit"; - //////////////////////////////////////////// - + static final String LOG_LEVEL_FILTER_CHANGED = "logLevelFilterChanged"; + + //////////////////////////////////////////// static final String BLOCKING_CHANGED = "blockingChanged"; static final String CHOOSE_COMPACT_FILE = "chooseCompactFile"; static final String CHOOSE_LOG_FILE = "chooseLogFile"; @@ -38,7 +52,7 @@ static final String DATA_SOURCE_TYPE_CHANGED = "dataSourceTypeChanged"; static final String DETECTOR_NAME_CHANGED = "detectorNameChanged"; static final String DETECTOR_ALIAS_CHANGED = "detectorAliasChanged"; - static final String DISCONNECT = "disconnect"; + static final String DISCONNECT_ON_ERROR_CHANGED = "disconnectOnErrorChanged"; static final String DISCONNECT_ON_END_RUN_CHANGED = "disconnectOnEndRunChanged"; static final String EVENT_BUILDER_CHANGED = "eventBuilderChanged"; @@ -49,17 +63,10 @@ static final String LOG_TO_FILE_CHANGED = "logToFileChanged"; static final String LOG_TO_TERMINAL = "logToTerminal"; - static final String PROCESSING_STAGE_CHANGED = "processingStageChanged"; - static final String PLOTS_CLEAR = "resetPlots"; - static final String RESTORE_DEFAULT_GUI_LAYOUT = "restoreDefaultGuiLayout"; - - static final String SAVE_LOG_TABLE = "saveLogTable"; - static final String PLOTS_SAVE = "savePlots"; - static final String SCREENSHOT = "screenshot"; - + static final String PROCESSING_STAGE_CHANGED = "processingStageChanged"; + static final String SAVE_LOG_TABLE = "saveLogTable"; static final String SELECT_LOG_FILE = "logToFile"; - static final String SET_STEERING_RESOURCE = "setSteeringResource"; - + static final String SET_STEERING_RESOURCE = "setSteeringResource"; static final String STEERING_TYPE_CHANGED = "steeringTypeChanged"; static final String STEERING_RESOURCE_CHANGED = "steeringResourceChanged"; static final String USER_RUN_NUMBER_CHANGED = "userRunNumberChanged"; Added: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java ============================================================================= --- java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java (added) +++ java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java Fri Mar 6 16:19:25 2015 @@ -0,0 +1,76 @@ +package org.hps.monitoring.application; + +import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.logging.Level; + +import javax.swing.DefaultComboBoxModel; +import javax.swing.JComboBox; + +import org.hps.monitoring.application.model.ConfigurationModel; + +/** + * + * @author Jeremy McCormick <[log in to unmask]> + */ +public class LogLevelFilterComboBox extends JComboBox<Level> implements ActionListener, PropertyChangeListener { + + ConfigurationModel configurationModel; + + static final Level[] LOG_LEVELS = new Level[] { + Level.ALL, + Level.FINEST, + Level.FINER, + Level.FINE, + Level.CONFIG, + Level.INFO, + Level.WARNING, + Level.SEVERE + }; + + LogLevelFilterComboBox(ConfigurationModel configurationModel) { + + configurationModel.addPropertyChangeListener(this); + this.configurationModel = configurationModel; + + setModel(new DefaultComboBoxModel<Level>(LOG_LEVELS)); + setPrototypeDisplayValue(Level.WARNING); + setSelectedItem(Level.ALL); + setActionCommand(Commands.LOG_LEVEL_FILTER_CHANGED); + addActionListener(this); + setPreferredSize(new Dimension(100, getPreferredSize().height)); + setSize(new Dimension(100, getPreferredSize().height)); + } + + /** + * Push change in log level filtering to the configuration model. + */ + public void actionPerformed(ActionEvent event) { + if (event.getActionCommand().equals(Commands.LOG_LEVEL_FILTER_CHANGED)) { + configurationModel.removePropertyChangeListener(this); + try { + configurationModel.setLogLevelFilter((Level) getSelectedItem()); + } finally { + configurationModel.addPropertyChangeListener(this); + } + } + } + + /** + * Get change in log level filtering from the configuration model. + */ + public void propertyChange(PropertyChangeEvent event) { + if (event.getPropertyName().equals(ConfigurationModel.LOG_LEVEL_FILTER_PROPERTY)) { + Level newLevel = (Level) event.getNewValue(); + configurationModel.removePropertyChangeListener(this); + try { + setSelectedItem(newLevel); + } finally { + configurationModel.addPropertyChangeListener(this); + } + } + } +} Added: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/LogPanel.java ============================================================================= --- java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/LogPanel.java (added) +++ java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/LogPanel.java Fri Mar 6 16:19:25 2015 @@ -0,0 +1,55 @@ +package org.hps.monitoring.application; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.event.ActionListener; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; + +import org.hps.monitoring.application.model.ConfigurationModel; + +/** + * This is a simple GUI component for the log table and its controls. + * @author Jeremy McCormick <[log in to unmask]> + */ +public class LogPanel extends JPanel { + + LogTable logTable; + + LogPanel(ConfigurationModel configurationModel, ActionListener listener) { + + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + + logTable = new LogTable(configurationModel); + + JPanel controlsPanel = new JPanel(); + controlsPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5)); + + JLabel label = new JLabel("Log Level Filter"); + LogLevelFilterComboBox logFilterComboBox = new LogLevelFilterComboBox(configurationModel); + logFilterComboBox.setToolTipText("Messages below this level will be filtered out."); + controlsPanel.add(label); + controlsPanel.add(logFilterComboBox); + + JButton exportButton = new JButton("Export ..."); + exportButton.setActionCommand(Commands.SAVE_LOG_TABLE); + exportButton.addActionListener(listener); + controlsPanel.add(exportButton); + + JButton clearButton = new JButton("Clear"); + clearButton.setActionCommand(Commands.CLEAR_LOG_TABLE); + clearButton.addActionListener(listener); + controlsPanel.add(clearButton); + + JScrollPane tablePane = new JScrollPane(logTable); + controlsPanel.setMaximumSize(new Dimension(tablePane.getPreferredSize().width, 200)); + + add(controlsPanel, BorderLayout.PAGE_START); + add(tablePane, BorderLayout.PAGE_END); + } +} Modified: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/LogTable.java ============================================================================= --- java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/LogTable.java (original) +++ java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/LogTable.java Fri Mar 6 16:19:25 2015 @@ -1,37 +1,136 @@ package org.hps.monitoring.application; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; +import java.util.List; +import java.util.logging.Level; import java.util.logging.LogRecord; import javax.swing.JTable; -import javax.swing.table.DefaultTableModel; +import javax.swing.RowFilter; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableRowSorter; + +import org.hps.monitoring.application.model.ConfigurationModel; /** * This is a simple Swing component for the table of log messages. * @author Jeremy McCormick <[log in to unmask]> */ -class LogTable extends JTable { +class LogTable extends JTable implements PropertyChangeListener { - private DefaultTableModel model; - static final String[] logTableColumns = { "Date", "Level", "Message" }; + static final String[] COLUMN_NAMES = { "Date", "Level", "Message" }; + + LogRecordModel model; + TableRowSorter<LogRecordModel> sorter; - private final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS"); + Level filterLevel = Level.ALL; - LogTable() { - String data[][] = new String[0][0]; - model = new DefaultTableModel(data, logTableColumns); - this.setModel(model); + final static SimpleDateFormat formatter = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS"); + + LogTable(ConfigurationModel configurationModel) { + configurationModel.addPropertyChangeListener(this); + model = new LogRecordModel(); + setModel(model); + sorter = new TableRowSorter<LogRecordModel>(model); + sorter.setRowFilter(new LevelFilter()); + this.getColumnModel().getColumn(0).setCellRenderer(new DateRenderer()); + setRowSorter(sorter); setEnabled(false); - setAutoCreateRowSorter(true); } - - void clear() { - model.setRowCount(0); + + static class DateRenderer extends DefaultTableCellRenderer { + public void setValue(Object value) { + setText((value == null) ? "" : formatter.format(value)); + } + } + + class LevelFilter extends RowFilter<LogRecordModel, Integer> { + + public boolean include(Entry<? extends LogRecordModel, ? extends Integer> entry) { + LogRecordModel model = entry.getModel(); + LogRecord record = model.get(entry.getIdentifier()); + if (record.getLevel().intValue() >= filterLevel.intValue()) { + return true; + } + return false; + } } - - void insert(LogRecord record) { - Object[] row = new Object[] { dateFormat.format(new Date(record.getMillis())), record.getLevel(), record.getMessage() }; - model.insertRow(getRowCount(), row); + + static class LogRecordModel extends AbstractTableModel { + + List<LogRecord> records = new ArrayList<LogRecord>(); + + LogRecord get(Integer rowIndex) { + return records.get(rowIndex); + } + + void add(LogRecord record) { + records.add(record); + fireTableDataChanged(); + } + + @Override + public int getRowCount() { + return records.size(); + } + + @Override + public int getColumnCount() { + return COLUMN_NAMES.length; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + LogRecord record = records.get(rowIndex); + switch (columnIndex) { + case 0: + return new Date(record.getMillis()); + case 1: + return record.getLevel(); + case 2: + return record.getMessage(); + default: + return null; + } + } + + @Override + public Class<?> getColumnClass(int columnIndex) { + switch (columnIndex) { + case 0: + return Date.class; + case 1: + return String.class; + case 2: + return String.class; + default: + return Object.class; + } + } + + @Override + public String getColumnName(int columnIndex) { + return COLUMN_NAMES[columnIndex]; + } + + void clear() { + records.clear(); + fireTableDataChanged(); + } + } + + /** + * Get change in log level filtering from the configuration model. + */ + public void propertyChange(PropertyChangeEvent event) { + if (event.getPropertyName().equals(ConfigurationModel.LOG_LEVEL_FILTER_PROPERTY)) { + filterLevel = (Level) event.getNewValue(); + model.fireTableDataChanged(); + } } } Modified: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/MenuBar.java ============================================================================= --- java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/MenuBar.java (original) +++ java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/MenuBar.java Fri Mar 6 16:19:25 2015 @@ -1,17 +1,18 @@ package org.hps.monitoring.application; import static org.hps.monitoring.application.Commands.EXIT; -import static org.hps.monitoring.application.Commands.FILE_CLOSE; -import static org.hps.monitoring.application.Commands.FILE_OPEN; -import static org.hps.monitoring.application.Commands.PLOTS_CLEAR; -import static org.hps.monitoring.application.Commands.PLOTS_SAVE; -import static org.hps.monitoring.application.Commands.SETTINGS_LOAD; -import static org.hps.monitoring.application.Commands.SETTINGS_LOAD_DEFAULT; -import static org.hps.monitoring.application.Commands.SETTINGS_SAVE; -import static org.hps.monitoring.application.Commands.SETTINGS_SHOW; -import static org.hps.monitoring.application.Commands.WINDOW_DEFAULTS; -import static org.hps.monitoring.application.Commands.WINDOW_MAXIMIZE; -import static org.hps.monitoring.application.Commands.WINDOW_MINIMIZE; +import static org.hps.monitoring.application.Commands.CLOSE_FILE; +import static org.hps.monitoring.application.Commands.OPEN_FILE; +import static org.hps.monitoring.application.Commands.CLEAR_PLOTS; +import static org.hps.monitoring.application.Commands.SAVE_PLOTS; +import static org.hps.monitoring.application.Commands.LOAD_SETTINGS; +import static org.hps.monitoring.application.Commands.LOAD_DEFAULT_SETTINGS; +import static org.hps.monitoring.application.Commands.SAVE_SCREENSHOT; +import static org.hps.monitoring.application.Commands.SAVE_SETTINGS; +import static org.hps.monitoring.application.Commands.SHOW_SETTINGS; +import static org.hps.monitoring.application.Commands.DEFAULT_WINDOW; +import static org.hps.monitoring.application.Commands.MAXIMIZE_WINDOW; +import static org.hps.monitoring.application.Commands.MINIMIZE_WINDOW; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -54,14 +55,14 @@ openFileItem = new JMenuItem("Open File ..."); openFileItem.setMnemonic(KeyEvent.VK_P); - openFileItem.setActionCommand(FILE_OPEN); + openFileItem.setActionCommand(OPEN_FILE); openFileItem.addActionListener(listener); openFileItem.setToolTipText("Open an EVIO or LCIO data file"); fileMenu.add(openFileItem); closeFileItem = new JMenuItem("Close File"); closeFileItem.setMnemonic(KeyEvent.VK_C); - closeFileItem.setActionCommand(FILE_CLOSE); + closeFileItem.setActionCommand(CLOSE_FILE); closeFileItem.addActionListener(listener); closeFileItem.setToolTipText("Close the current file data source"); fileMenu.add(closeFileItem); @@ -79,7 +80,7 @@ JMenuItem settingsItem = new JMenuItem("Open Settings Window ..."); settingsItem.setMnemonic(KeyEvent.VK_O); - settingsItem.setActionCommand(SETTINGS_SHOW); + settingsItem.setActionCommand(SHOW_SETTINGS); settingsItem.addActionListener(listener); settingsItem.setToolTipText("Show settings dialog"); settingsMenu.add(settingsItem); @@ -87,21 +88,21 @@ JMenuItem loadConfigItem = new JMenuItem("Load Settings ..."); loadConfigItem.addActionListener(listener); loadConfigItem.setMnemonic(KeyEvent.VK_L); - loadConfigItem.setActionCommand(SETTINGS_LOAD); + loadConfigItem.setActionCommand(LOAD_SETTINGS); loadConfigItem.setToolTipText("Load settings from a properties file"); settingsMenu.add(loadConfigItem); JMenuItem saveConfigItem = new JMenuItem("Save Settings ..."); saveConfigItem.addActionListener(listener); saveConfigItem.setMnemonic(KeyEvent.VK_S); - saveConfigItem.setActionCommand(SETTINGS_SAVE); + saveConfigItem.setActionCommand(SAVE_SETTINGS); saveConfigItem.setToolTipText("Save configuration to a properties file"); settingsMenu.add(saveConfigItem); JMenuItem defaultSettingsItem = new JMenuItem("Load Default Settings"); defaultSettingsItem.addActionListener(listener); defaultSettingsItem.setMnemonic(KeyEvent.VK_D); - defaultSettingsItem.setActionCommand(SETTINGS_LOAD_DEFAULT); + defaultSettingsItem.setActionCommand(LOAD_DEFAULT_SETTINGS); defaultSettingsItem.setToolTipText("Load the default settings"); settingsMenu.add(defaultSettingsItem); @@ -111,7 +112,7 @@ JMenuItem savePlotsItem = new JMenuItem("Save Plots ..."); savePlotsItem.setMnemonic(KeyEvent.VK_S); - savePlotsItem.setActionCommand(PLOTS_SAVE); + savePlotsItem.setActionCommand(SAVE_PLOTS); savePlotsItem.addActionListener(listener); savePlotsItem.setEnabled(true); savePlotsItem.setToolTipText("Save plots to AIDA file"); @@ -119,19 +120,31 @@ JMenuItem clearPlotsItem = new JMenuItem("Clear plots"); clearPlotsItem.setMnemonic(KeyEvent.VK_C); - clearPlotsItem.setActionCommand(PLOTS_CLEAR); + clearPlotsItem.setActionCommand(CLEAR_PLOTS); clearPlotsItem.addActionListener(listener); clearPlotsItem.setEnabled(true); clearPlotsItem.setToolTipText("Clear the AIDA plots"); plotsMenu.add(clearPlotsItem); + JMenu toolsMenu = new JMenu("Tools"); + toolsMenu.setMnemonic(KeyEvent.VK_T); + add(toolsMenu); + + JMenuItem screenshotItem = new JMenuItem("Save Screenshot ..."); + screenshotItem.setMnemonic(KeyEvent.VK_S); + screenshotItem.setActionCommand(SAVE_SCREENSHOT); + screenshotItem.addActionListener(listener); + screenshotItem.setEnabled(true); + screenshotItem.setToolTipText("Save a screenshot to a graphics file"); + toolsMenu.add(screenshotItem); + JMenu windowMenu = new JMenu("Window"); windowMenu.setMnemonic(KeyEvent.VK_W); add(windowMenu); JMenuItem maximizeItem = new JMenuItem("Maximize"); maximizeItem.setMnemonic(KeyEvent.VK_M); - maximizeItem.setActionCommand(WINDOW_MAXIMIZE); + maximizeItem.setActionCommand(MAXIMIZE_WINDOW); maximizeItem.addActionListener(listener); maximizeItem.setEnabled(true); maximizeItem.setToolTipText("Maximize the application window"); @@ -139,7 +152,7 @@ JMenuItem minimizeItem = new JMenuItem("Minimize"); minimizeItem.setMnemonic(KeyEvent.VK_I); - minimizeItem.setActionCommand(WINDOW_MINIMIZE); + minimizeItem.setActionCommand(MINIMIZE_WINDOW); minimizeItem.addActionListener(listener); minimizeItem.setEnabled(true); minimizeItem.setToolTipText("Minimize the application window"); @@ -147,7 +160,7 @@ JMenuItem defaultsItem = new JMenuItem("Restore Defaults"); defaultsItem.setMnemonic(KeyEvent.VK_D); - defaultsItem.setActionCommand(WINDOW_DEFAULTS); + defaultsItem.setActionCommand(DEFAULT_WINDOW); defaultsItem.addActionListener(listener); defaultsItem.setEnabled(true); defaultsItem.setToolTipText("Restore the window defaults"); Modified: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/MonitoringApplication.java ============================================================================= --- java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/MonitoringApplication.java (original) +++ java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/MonitoringApplication.java Fri Mar 6 16:19:25 2015 @@ -1,47 +1,39 @@ package org.hps.monitoring.application; -import static org.hps.monitoring.application.Commands.CONNECT; -import static org.hps.monitoring.application.Commands.DATA_SOURCE_CHANGED; -import static org.hps.monitoring.application.Commands.DISCONNECT; -import static org.hps.monitoring.application.Commands.EXIT; -import static org.hps.monitoring.application.Commands.FILE_CLOSE; -import static org.hps.monitoring.application.Commands.FILE_OPEN; -import static org.hps.monitoring.application.Commands.NEXT; -import static org.hps.monitoring.application.Commands.PAUSE; -import static org.hps.monitoring.application.Commands.PLOTS_CLEAR; -import static org.hps.monitoring.application.Commands.PLOTS_SAVE; -import static org.hps.monitoring.application.Commands.RESUME; -import static org.hps.monitoring.application.Commands.SETTINGS_LOAD; -import static org.hps.monitoring.application.Commands.SETTINGS_LOAD_DEFAULT; -import static org.hps.monitoring.application.Commands.SETTINGS_SAVE; -import static org.hps.monitoring.application.Commands.SETTINGS_SHOW; -import static org.hps.monitoring.application.Commands.WINDOW_DEFAULTS; -import static org.hps.monitoring.application.Commands.WINDOW_MAXIMIZE; -import static org.hps.monitoring.application.Commands.WINDOW_MINIMIZE; import hep.aida.jfree.AnalysisFactory; import hep.aida.jfree.plotter.PlotterRegion; import hep.aida.jfree.plotter.PlotterRegionListener; +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; +import java.io.PrintStream; import java.util.ArrayList; import java.util.List; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; - +import java.util.logging.StreamHandler; + +import javax.imageio.ImageIO; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; +import javax.swing.JTable; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileNameExtensionFilter; import org.hps.monitoring.application.DataSourceComboBox.DataSourceItem; +import org.hps.monitoring.application.LogTable.LogRecordModel; import org.hps.monitoring.application.model.Configuration; import org.hps.monitoring.application.model.ConfigurationModel; import org.hps.monitoring.application.model.ConnectionStatusModel; @@ -49,6 +41,7 @@ import org.hps.monitoring.application.util.DialogUtil; import org.hps.monitoring.application.util.ErrorHandler; import org.hps.monitoring.application.util.EvioFileFilter; +import org.hps.monitoring.application.util.TableExporter; import org.hps.monitoring.plotting.MonitoringAnalysisFactory; import org.hps.monitoring.plotting.MonitoringPlotFactory; import org.hps.monitoring.subsys.StatusCode; @@ -58,6 +51,7 @@ import org.hps.record.composite.CompositeRecordProcessor; import org.hps.record.enums.DataSourceType; import org.lcsim.util.aida.AIDA; +import org.lcsim.util.log.DefaultLogFormatter; /** * This is the primary class that implements the monitoring GUI application. @@ -69,12 +63,15 @@ */ final class MonitoringApplication implements ActionListener, PropertyChangeListener, SystemStatusListener { - // Setup application logging. + // Statically initialize logging, which will be fully setup later. static final Logger logger; static { logger = Logger.getLogger(MonitoringApplication.class.getSimpleName()); } - Handler logHandler; + static final Level DEFAULT_LEVEL = Level.ALL; + + // Default log stream. + PrintStream logStream = System.out; // Application error handling. final ErrorHandler errorHandler; @@ -99,7 +96,7 @@ // Filters for opening files. static final FileFilter lcioFilter = new FileNameExtensionFilter("LCIO files", "slcio"); static final EvioFileFilter evioFilter = new EvioFileFilter(); - + /** * Default log handler. */ @@ -109,7 +106,7 @@ * This method inserts a record into the log table. */ public void publish(LogRecord record) { - frame.logTable.insert(record); + getLogRecordModel().add(record); } public void close() throws SecurityException { @@ -118,6 +115,14 @@ public void flush() { } } + + LogRecordModel getLogRecordModel() { + return frame.logPanel.logTable.model; + } + + LogTable getLogTable() { + return frame.logPanel.logTable; + } /** * Instantiate and show the monitoring application with the given configuration. @@ -183,70 +188,59 @@ public void actionPerformed(ActionEvent e) { String cmd = e.getActionCommand(); - if (CONNECT.equals(cmd)) { + if (Commands.CONNECT.equals(cmd)) { // Run the start session method on a separate thread. new Thread() { public void run() { startSession(); } }.start(); - } else if (DISCONNECT.equals(cmd)) { + } else if (Commands.DISCONNECT.equals(cmd)) { // Run the stop session method on a separate thread. new Thread() { public void run() { stopSession(); } }.start(); - } else if (PLOTS_SAVE.equals(cmd)) { + } else if (Commands.SAVE_PLOTS.equals(cmd)) { savePlots(); - } else if (EXIT.equals(cmd)) { + } else if (Commands.EXIT.equals(cmd)) { exit(); - } else if (PAUSE.equals(cmd)) { + } else if (Commands.PAUSE.equals(cmd)) { processing.pause(); - } else if (NEXT.equals(cmd)) { + } else if (Commands.NEXT.equals(cmd)) { processing.next(); - } else if (RESUME.equals(cmd)) { + } else if (Commands.RESUME.equals(cmd)) { processing.resume(); - } else if (SETTINGS_SHOW.equals(cmd)) { + } else if (Commands.SHOW_SETTINGS.equals(cmd)) { showSettingsDialog(); - } else if (SETTINGS_LOAD.equals(cmd)) { + } else if (Commands.LOAD_SETTINGS.equals(cmd)) { loadSettings(); - } else if (SETTINGS_SAVE.equals(cmd)) { + } else if (Commands.SAVE_SETTINGS.equals(cmd)) { saveSettings(); - } else if (PLOTS_CLEAR.equals(cmd)) { + } else if (Commands.CLEAR_PLOTS.equals(cmd)) { clearPlots(); - } else if (SETTINGS_LOAD_DEFAULT.equals(cmd)) { + } else if (Commands.LOAD_DEFAULT_SETTINGS.equals(cmd)) { loadDefaultSettings(); - } else if (FILE_OPEN.equals(cmd)) { + } else if (Commands.OPEN_FILE.equals(cmd)) { openFile(); - } else if (WINDOW_DEFAULTS.equals(cmd)) { + } else if (Commands.DEFAULT_WINDOW.equals(cmd)) { restoreDefaultWindow(); - } else if (WINDOW_MAXIMIZE.equals(cmd)) { + } else if (Commands.MAXIMIZE_WINDOW.equals(cmd)) { maximizeWindow(); - } else if (WINDOW_MINIMIZE.equals(cmd)) { + } else if (Commands.MINIMIZE_WINDOW.equals(cmd)) { minimizeWindow(); - } else if (FILE_CLOSE.equals(cmd)) { + } else if (Commands.CLOSE_FILE.equals(cmd)) { closeFile(); - } - - /*else if (CHOOSE_LOG_FILE.equals(cmd)) { - //chooseLogFile(); - } else if (LOG_TO_TERMINAL.equals(cmd)) { - //logToTerminal(); - } else if (SCREENSHOT.equals(cmd)) { - //chooseScreenshot(); - } else if (SAVE_LOG_TABLE.equals(cmd)) { - //saveLogTableToFile(); - } else if (CLEAR_LOG_TABLE.equals(cmd)) { - //clearLogTable(); - } else if (LOG_LEVEL_CHANGED.equals(cmd)) { - //setLogLevel(); - } else if (VALIDATE_DATA_FILE.equals(cmd)) { - //if (fileValidationThread == null) { - // new FileValidationThread().start(); - //} - } - */ + } else if (Commands.SAVE_SCREENSHOT.equals(cmd)) { + saveScreenshot(); + } else if (Commands.LOG_LEVEL_CHANGED.equals(cmd)) { + setLogLevel(); + } else if (Commands.SAVE_LOG_TABLE.equals(cmd)) { + saveLogTable(); + } else if (Commands.CLEAR_LOG_TABLE.equals(cmd)) { + getLogRecordModel().clear(); + } } /** @@ -277,10 +271,18 @@ * Setup the logger. */ void setupLogger() { - logHandler = new LogHandler(); logger.setUseParentHandlers(false); - logger.addHandler(logHandler); - logger.setLevel(Level.ALL); + logger.addHandler(new LogHandler()); + logger.addHandler(new StreamHandler(logStream, new DefaultLogFormatter()) { + public void publish(LogRecord record) { + super.publish(record); + flush(); + } + }); + for (Handler handler : logger.getHandlers()) { + handler.setLevel(DEFAULT_LEVEL); + } + logger.setLevel(DEFAULT_LEVEL); logger.info("logging initialized"); } @@ -292,9 +294,9 @@ // Set the Configuration on the ConfigurationModel which will trigger all the PropertyChangelListeners. configurationModel.setConfiguration(configuration); if (configuration.getFile() != null) - logger.config("loaded configuration from file: " + configuration.getFile().getPath()); + logger.config("loaded config from file " + configuration.getFile().getPath()); else - logger.config("loaded configuration from resource: " + configuration.getResourcePath()); + logger.config("loaded config from resource " + configuration.getResourcePath()); } /** @@ -453,9 +455,7 @@ try { AIDA.defaultInstance().saveAs(fileName); logger.info("saved plots to file: " + fileName); - DialogUtil.showInfoDialog(frame, - "Plots Saved", - "Plots were successfully saved to AIDA file."); + DialogUtil.showInfoDialog(frame, "Plots Saved", "Plots were successfully saved to AIDA file."); } catch (IOException e) { errorHandler.setError(e).setMessage("Error Saving Plots").printStackTrace().log().showErrorDialog(); } @@ -470,9 +470,7 @@ "Are you sure you want to clear the plots", "Clear Plots Confirmation"); if (confirmation == JOptionPane.YES_OPTION) { AIDA.defaultInstance().clearAll(); - DialogUtil.showInfoDialog(frame, - "Plots Clear", - "The AIDA plots were cleared."); + DialogUtil.showInfoDialog(frame, "Plots Clear", "The AIDA plots were cleared."); } logger.info("plots were cleared"); } @@ -483,9 +481,7 @@ void loadDefaultSettings() { configuration = new Configuration(MonitoringApplication.DEFAULT_CONFIGURATION); configurationModel.setConfiguration(configuration); - DialogUtil.showInfoDialog(frame, - "Default Configuration Loaded", - "The default configuration was loaded."); + DialogUtil.showInfoDialog(frame, "Default Configuration Loaded", "The default configuration was loaded."); logger.config("default settings loaded"); } @@ -493,7 +489,7 @@ * Show the settings dialog window. */ void showSettingsDialog() { - frame.settingsDialog.setVisible(true); + frame.settingsDialog.setVisible(true); } /** @@ -542,9 +538,7 @@ File f = fc.getSelectedFile(); configuration.writeToFile(f); logger.info("saved configuration to file: " + f.getPath()); - DialogUtil.showInfoDialog(frame, - "Settings Saved", - "Settings were saved successfully."); + DialogUtil.showInfoDialog(frame, "Settings Saved", "Settings were saved successfully."); } } @@ -561,9 +555,7 @@ configuration = new Configuration(f); loadConfiguration(configuration); logger.info("loaded configuration from file: " + f.getPath()); - DialogUtil.showInfoDialog(frame, - "Settings Loaded", - "Settings were loaded successfully."); + DialogUtil.showInfoDialog(frame, "Settings Loaded", "Settings were loaded successfully."); } } @@ -600,4 +592,82 @@ } } } + + /** + * Save a screenshot to a file using a file chooser. + */ + void saveScreenshot() { + JFileChooser fc = new JFileChooser(); + fc.setAcceptAllFileFilterUsed(false); + fc.setDialogTitle("Save Screenshot"); + FileNameExtensionFilter pngFilter = new FileNameExtensionFilter("png file (*.png)", "png"); + String format = pngFilter.getExtensions()[0]; + fc.addChoosableFileFilter(pngFilter); + fc.setCurrentDirectory(new File(".")); + int r = fc.showSaveDialog(frame); + if (r == JFileChooser.APPROVE_OPTION) { + String fileName = fc.getSelectedFile().getPath(); + if (!fileName.endsWith("." + format)) { + fileName += "." + format; + } + writeScreenshot(fileName, format); + DialogUtil.showInfoDialog(frame, "Screenshot Saved", "Screenshot was saved to file."); + logger.info("saved screenshot to " + fileName); + } + } + + /** + * Save a screenshot to an output file. + * @param fileName The name of the output file. + */ + void writeScreenshot(String fileName, String format) { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + Rectangle screenRectangle = new Rectangle(screenSize); + try { + Robot robot = new Robot(); + BufferedImage image = robot.createScreenCapture(screenRectangle); + ImageIO.write(image, format, new File(fileName)); + } catch (Exception e) { + errorHandler.setError(e).setMessage("Failed to take screenshot.").printStackTrace().log().showErrorDialog(); + } + } + + /** + * Set the log level from the configuration model. + */ + void setLogLevel() { + Level newLevel = configurationModel.getLogLevel(); + if (logger.getLevel() != newLevel) { + logger.setLevel(newLevel); + logger.log(Level.INFO, "Log Level was changed to <" + configurationModel.getLogLevel().toString() + ">"); + } + } + + /** + * Export a JTable's data to a comma-delimited text file using a file chooser. + */ + void saveTable(JTable table) { + JFileChooser fc = new JFileChooser(); + fc.setDialogTitle("Save Table to Text File"); + fc.setCurrentDirectory(new File(".")); + int r = fc.showSaveDialog(frame); + if (r == JFileChooser.APPROVE_OPTION) { + String fileName = fc.getSelectedFile().getPath(); + try { + TableExporter.export(table, fileName, ','); + logger.info("saved table data to " + fileName); + DialogUtil.showInfoDialog(frame, "Table Data Saved", "The table was exported successfully."); + } catch (IOException e) { + DialogUtil.showErrorDialog(frame, "Table Export Error", "The table export failed."); + logger.warning("failed to save table data to " + fileName); + } + } + } + + /** + * Save the log table to a file using a file chooser. + */ + void saveLogTable() { + saveTable(frame.logPanel.logTable); + } } Modified: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java ============================================================================= --- java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java (original) +++ java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java Fri Mar 6 16:19:25 2015 @@ -9,7 +9,6 @@ import javax.swing.BoxLayout; import javax.swing.JComponent; import javax.swing.JFrame; -import javax.swing.JMenuBar; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSeparator; @@ -27,7 +26,7 @@ RunPanel runPanel; PlotPanel plotPanel; PlotInfoPanel plotInfoPanel; - LogTable logTable; + LogPanel logPanel; SystemStatusTable systemStatusTable; JPanel buttonsPanel; @@ -107,8 +106,8 @@ JTabbedPane tableTabbedPane = new JTabbedPane(); // Create the log table and add it to the tabs. - logTable = new LogTable(); - tableTabbedPane.addTab("Log Messages", new JScrollPane(logTable)); + logPanel = new LogPanel(application.configurationModel, application); + tableTabbedPane.addTab("Log Messages", logPanel); // Create the system monitor. systemStatusTable = new SystemStatusTable(); Modified: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/SettingsDialog.java ============================================================================= --- java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/SettingsDialog.java (original) +++ java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/SettingsDialog.java Fri Mar 6 16:19:25 2015 @@ -34,6 +34,10 @@ public void windowClosing(WindowEvent e) { setVisible(false); } + + public void windowOpened(WindowEvent event) { + SettingsDialog.this.setLocationRelativeTo(null); + } }); } } Modified: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java ============================================================================= --- java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java (original) +++ java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java Fri Mar 6 16:19:25 2015 @@ -27,6 +27,7 @@ public static final String FREEZE_CONDITIONS_PROPERTY = "FreezeConditions"; public static final String LOG_FILE_NAME_PROPERTY = "LogFileName"; public static final String LOG_LEVEL_PROPERTY = "LogLevel"; + public static final String LOG_LEVEL_FILTER_PROPERTY = "LogLevelFilter"; public static final String LOG_TO_FILE_PROPERTY = "LogToFile"; public static final String MAX_EVENTS_PROPERTY = "MaxEvents"; public static final String STEERING_TYPE_PROPERTY = "SteeringType"; @@ -82,6 +83,16 @@ configuration.set(LOG_LEVEL_PROPERTY, level.getName()); firePropertyChange(LOG_LEVEL_PROPERTY, oldValue, getLogLevel()); } + + public Level getLogLevelFilter() { + return Level.parse(configuration.get(LOG_LEVEL_FILTER_PROPERTY)); + } + + public void setLogLevelFilter(Level level) { + Level oldValue = getLogLevelFilter(); + configuration.set(LOG_LEVEL_FILTER_PROPERTY, level.getName()); + firePropertyChange(LOG_LEVEL_FILTER_PROPERTY, oldValue, getLogLevelFilter()); + } public SteeringType getSteeringType() { return SteeringType.valueOf(configuration.get(STEERING_TYPE_PROPERTY)); Modified: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/util/DialogUtil.java ============================================================================= --- java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/util/DialogUtil.java (original) +++ java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/util/DialogUtil.java Fri Mar 6 16:19:25 2015 @@ -53,6 +53,21 @@ }; SwingUtilities.invokeLater(runnable); } + + /** + * + * @param component + * @param error + * @param title + */ + public static void showErrorDialog(final Component component, final String title, final String message) { + final Runnable runnable = new Runnable() { + public void run() { + JOptionPane.showMessageDialog(component, message, title, JOptionPane.ERROR_MESSAGE); + } + }; + SwingUtilities.invokeLater(runnable); + } /** * @@ -76,11 +91,12 @@ * @param title * @return */ - public static int showConfirmationDialog(final Component parent, String message, String title) { + public static int showConfirmationDialog(final Component parent, final String title, final String message) { Object[] options = { "Yes", "No", "Cancel" }; int result = JOptionPane.showOptionDialog( parent, - message, title, + message, + title, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, Added: java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/util/TableExporter.java ============================================================================= --- java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/util/TableExporter.java (added) +++ java/branches/monitoring-app-HPSJAVA-442/src/main/java/org/hps/monitoring/application/util/TableExporter.java Fri Mar 6 16:19:25 2015 @@ -0,0 +1,62 @@ +package org.hps.monitoring.application.util; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; + +import javax.swing.JTable; +import javax.swing.table.TableModel; + +/** + * This is a utility for exporting a JTable's model data to a text file. + * Non-numeric fields are all contained in double quotes. + * + * @author Jeremy McCormick <[log in to unmask]> + */ +public final class TableExporter { + + private TableExporter() { + } + + /** + * Export the given table to a text file. + * @param table The JTable component. + * @param path The output file path. + * @param fieldDelimiter The field delimiter to use. + * @throws IOException if there are errors writing the file. + */ + public static void export(JTable table, String path, char fieldDelimiter) throws IOException { + + StringBuffer buffer = new StringBuffer(); + TableModel model = table.getModel(); + int rowCount = model.getRowCount(); + int columnCount = model.getColumnCount(); + + // Column headers. + for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { + buffer.append("\"" + model.getColumnName(columnIndex) + "\"" + fieldDelimiter); + } + buffer.setLength(buffer.length() - 1); + buffer.append('\n'); + + // Row data. + for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) { + for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) { + Object value = model.getValueAt(rowIndex, columnIndex); + if (Number.class.isAssignableFrom(model.getColumnClass(columnIndex))) { + buffer.append(value); + } else { + buffer.append("\"" + value + "\"" + fieldDelimiter); + } + } + buffer.setLength(buffer.length() - 1); + buffer.append('\n'); + } + + // Write string buffer to file. + BufferedWriter out = new BufferedWriter(new FileWriter(path)); + out.write(buffer.toString()); + out.flush(); + out.close(); + } +} Modified: java/branches/monitoring-app-HPSJAVA-442/src/main/resources/org/hps/monitoring/config/default_config.prop ============================================================================= --- java/branches/monitoring-app-HPSJAVA-442/src/main/resources/org/hps/monitoring/config/default_config.prop (original) +++ java/branches/monitoring-app-HPSJAVA-442/src/main/resources/org/hps/monitoring/config/default_config.prop Fri Mar 6 16:19:25 2015 @@ -8,6 +8,7 @@ EventBuilderClassName=org.hps.evio.LCSimEngRunEventBuilder #LogFileName= LogLevel=ALL +LogLevelFilter=ALL LogToFile=false MaxEvents=-1 #SteeringFile=