Print

Print


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=