Print

Print


Author: [log in to unmask]
Date: Tue Apr 21 14:48:39 2015
New Revision: 2772

Log:
Merge trunk changes into monitoring-app-dev branch..

Modified:
    java/branches/monitoring-app-dev/   (props changed)
    java/branches/monitoring-app-dev/pom.xml
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AddActionListener.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Commands.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DataSourceComboBox.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DatePanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventDashboard.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventProcessing.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/FieldPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogTable.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Main.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MenuBar.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplication.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsDialog.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusTable.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ToolbarPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/AbstractModel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/Configuration.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/HasConfigurationModel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/RunModel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SteeringType.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SystemStatusTableModel.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/package-info.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/AIDAServer.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/DialogUtil.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EtSystemUtil.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EvioFileFilter.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/SyncEventProcessor.java
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/TableExporter.java

Modified: java/branches/monitoring-app-dev/pom.xml
 =============================================================================
--- java/branches/monitoring-app-dev/pom.xml	(original)
+++ java/branches/monitoring-app-dev/pom.xml	Tue Apr 21 14:48:39 2015
@@ -7,7 +7,7 @@
         <groupId>org.hps</groupId>
         <artifactId>hps-parent</artifactId>
         <relativePath>../parent/pom.xml</relativePath>
-        <version>3.2-SNAPSHOT</version>
+        <version>3.3.1-SNAPSHOT</version>
     </parent>
     <scm>
         <url>http://java.freehep.org/svn/repos/hps/list/java/trunk/monitoring-app/</url>

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AbstractFieldsPanel.java	Tue Apr 21 14:48:39 2015
@@ -16,305 +16,362 @@
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JTextField;
+import javax.swing.SwingConstants;
 
 import org.hps.monitoring.application.model.ConfigurationModel;
 import org.hps.monitoring.application.model.HasConfigurationModel;
 
 /**
- * A <code>JPanel</code> which has a number of fields with the labels in the first column and the
- * components for showing/editing the fields in the second. It uses <code>GridBagConstraints</code>
- * for layout.
+ * A <code>JPanel</code> which has a number of fields with the labels in the first column and the components for
+ * showing/editing the fields in the second. It uses <code>GridBagConstraints</code> for layout.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-// TODO: This should use features of JFormattedTextField instead of plain JTextField.
-abstract class AbstractFieldsPanel extends JPanel implements PropertyChangeListener, HasConfigurationModel, ActionListener, AddActionListener {
-
-    private int currY = 0;
-    private Insets insets;
+@SuppressWarnings("serial")
+abstract class AbstractFieldsPanel extends JPanel implements PropertyChangeListener, HasConfigurationModel,
+ActionListener, AddActionListener {
+
+    /**
+     * Default button height in pixels.
+     */
+    private static final int DEFAULT_BUTTON_HEIGHT = 50;
+
+    /**
+     * Default button width in pixels.
+     */
+    private static final int DEFAULT_BUTTON_WIDTH = 100;
+
+    /**
+     * The configuration model for the component.
+     */
+    private ConfigurationModel configurationModel;
+
+    /**
+     * Grid Y which is incremented as components are added.
+     */
+    private int currentGridY = 0;
+
+    /**
+     * Flag which sets if this component and its children are editable.
+     */
     private boolean editable = false;
-    
-    protected ConfigurationModel configurationModel;
+
+    /**
+     * The default insets used for all internal <code>GridBagConstraints</code>.
+     */
+    private final Insets insets;
 
     /**
      * Class constructor.
+     */
+    protected AbstractFieldsPanel() {
+        this.insets = new Insets(1, 1, 1, 1);
+    }
+
+    /**
+     * Class constructor.
+     *
      * @param insets The insets for the panel.
      * @param editable Editable setting.
      */
-    protected AbstractFieldsPanel(Insets insets, boolean editable) {
+    protected AbstractFieldsPanel(final Insets insets, final boolean editable) {
         this.insets = insets;
         this.editable = editable;
     }
 
     /**
-     * Class constructor.
-     */
-    protected AbstractFieldsPanel() {
-        this.insets = new Insets(1, 1, 1, 1);
+     * True if property change event should be accepted.
+     *
+     * @param evt the property change event
+     * @return <code>true</code> if property change event should be accepted
+     */
+    boolean accept(final PropertyChangeEvent evt) {
+        return !"ancestor".equals(evt.getPropertyName());
+    }
+
+    /**
+     * Add an ActionListener to this component. By default this does nothing, but individual sub-components should
+     * attach this to individual components.
+     *
+     * @param listener the AcitonListener to add
+     */
+    @Override
+    public void addActionListener(final ActionListener listener) {
+        // Sub-classes should add the listener to the appropriate child components.
+    }
+
+    /**
+     * Add a button with text.
+     *
+     * @param text the text in the button
+     * @return the button component
+     */
+    protected final JButton addButton(final String text) {
+        final GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = this.currentGridY;
+        c.insets = this.insets;
+        c.anchor = GridBagConstraints.WEST;
+        c.gridwidth = 2;
+        final JButton button = new JButton(text);
+        button.setSize(new Dimension(DEFAULT_BUTTON_WIDTH, DEFAULT_BUTTON_HEIGHT));
+        this.add(button, c);
+        ++this.currentGridY;
+        return button;
+    }
+
+    /**
+     * Add a check box.
+     *
+     * @param name the name of the check box
+     * @param selected whether the check box is selected or not
+     * @param enabled whether it is enabled or not
+     * @return the JCheckBox component
+     */
+    protected final JCheckBox addCheckBox(final String name, final boolean selected, final boolean enabled) {
+
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = this.currentGridY;
+        c.insets = this.insets;
+        c.anchor = GridBagConstraints.WEST;
+        final JLabel label = new JLabel(name + ":");
+        this.add(label, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 1;
+        c.gridy = this.currentGridY;
+        c.insets = this.insets;
+        c.anchor = GridBagConstraints.EAST;
+        final JCheckBox checkbox = new JCheckBox();
+        checkbox.setSelected(selected);
+        checkbox.setEnabled(enabled);
+        this.add(checkbox, c);
+
+        ++this.currentGridY;
+
+        return checkbox;
+    }
+
+    /**
+     * Add a check box.
+     *
+     * @param name the name of the check box
+     * @param tooltip the tooltip text
+     * @param selected <code>true</code> if component is selected
+     * @param enabled <code>true</code> if component enabled
+     * @return The JCheckBox component.
+     */
+    protected final JCheckBox addCheckBox(final String name, final String tooltip, final boolean selected,
+            final boolean enabled) {
+        final JCheckBox c = this.addCheckBox(name, selected, enabled);
+        c.setToolTipText(tooltip);
+        return c;
+    }
+
+    /**
+     * Add a combo box.
+     *
+     * @param name the name of the combo box
+     * @param values the set of values for the combo box
+     * @return the JComboBox component
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    protected final JComboBox addComboBox(final String name, final Object[] values) {
+
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = this.currentGridY;
+        c.insets = this.insets;
+        c.anchor = GridBagConstraints.WEST;
+        final JLabel waitModeLabel = new JLabel(name);
+        waitModeLabel.setHorizontalAlignment(SwingConstants.LEFT);
+        this.add(waitModeLabel, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 1;
+        c.gridy = this.currentGridY;
+        c.insets = this.insets;
+        c.anchor = GridBagConstraints.EAST;
+        final JComboBox combo = new JComboBox(values);
+        combo.setEditable(this.editable);
+        this.add(combo, c);
+
+        ++this.currentGridY;
+
+        return combo;
+    }
+
+    /**
+     * Add a multiline combo box.
+     *
+     * @param name the name of the combo box
+     * @param values the values for the combo box
+     * @return the <code>JComboBox</code> component
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    protected final JComboBox addComboBoxMultiline(final String name, final String[] values) {
+
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridwidth = GridBagConstraints.REMAINDER;
+        c.gridy = this.currentGridY;
+        c.insets = this.insets;
+        c.anchor = GridBagConstraints.WEST;
+        final JLabel waitModeLabel = new JLabel(name + ":");
+        waitModeLabel.setHorizontalAlignment(SwingConstants.LEFT);
+        this.add(waitModeLabel, c);
+        ++this.currentGridY;
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridwidth = GridBagConstraints.REMAINDER;
+        c.gridy = this.currentGridY;
+        c.insets = this.insets;
+        c.anchor = GridBagConstraints.WEST;
+        final JComboBox combo = new JComboBox(values);
+        combo.setEditable(this.editable);
+        this.add(combo, c);
+
+        ++this.currentGridY;
+
+        return combo;
+    }
+
+    /**
+     * Add a labeled JComponent to the panel.
+     *
+     * @param name the label text
+     * @param component the component to add
+     */
+    void addComponent(final String name, final JComponent component) {
+
+        // Add the label.
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = this.currentGridY;
+        c.insets = this.insets;
+        c.anchor = GridBagConstraints.WEST;
+        final JLabel label = new JLabel(name + ":");
+        this.add(label, c);
+
+        // Add the component.
+        c = new GridBagConstraints();
+        c.gridx = 1;
+        c.gridy = this.currentGridY;
+        c.insets = this.insets;
+        c.anchor = GridBagConstraints.EAST;
+        this.add(component, c);
+
+        ++this.currentGridY;
     }
 
     /**
      * Add a field.
-     * @param name The name of the field.
-     * @param size The size of the field.
-     * @return The JTextField component.
-     */
-    protected final JTextField addField(String name, int size) {
-        return addField(name, "", size, this.editable);
+     *
+     * @param name the name of the field
+     * @param size the size of the field
+     * @return the <code>JTextField</code> component
+     */
+    protected final JTextField addField(final String name, final int size) {
+        return this.addField(name, "", size, this.editable);
     }
 
     /**
      * Add a field.
-     * @param name The name of the field.
-     * @param value The default value of the field.
-     * @param size The size of the field.
-     * @return The JTextField component.
-     */
-    protected final JTextField addField(String name, String value, int size) {
-        return addField(name, value, size, this.editable);
+     *
+     * @param name the name of the field
+     * @param value the default value of the field
+     * @param size the size of the field
+     * @return the <code>JTextField</code> component
+     */
+    protected final JTextField addField(final String name, final String value, final int size) {
+        return this.addField(name, value, size, this.editable);
     }
 
     /**
      * Add a field.
-     * @param name The name of the field.
-     * @param value The default value of the field.
-     * @param tooltip The tooltip text.
-     * @param size The size of the field.
-     * @param editable The editable setting.
-     * @return The JTextField component.
-     */
-    protected final JFormattedTextField addField(String name, String value, String tooltip, int size, boolean editable) {
-        JFormattedTextField f = addField(name, value, size, editable);
+     *
+     * @param name the name of the field
+     * @param value the default value of the field
+     * @param size the size of the field
+     * @param editable the editable setting
+     * @return the <code>JTextField</code> component
+     */
+    protected final JFormattedTextField addField(final String name, final String value, final int size,
+            final boolean editable) {
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = this.currentGridY;
+        c.insets = this.insets;
+        c.anchor = GridBagConstraints.WEST;
+        final JLabel label = new JLabel(name + ":");
+        this.add(label, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 1;
+        c.gridy = this.currentGridY;
+        c.insets = this.insets;
+        c.anchor = GridBagConstraints.EAST;
+        // JFormattedTextField field = new JFormattedTextField(value, size);
+        final JFormattedTextField field = new JFormattedTextField(value);
+        field.setColumns(size);
+        field.setHorizontalAlignment(SwingConstants.RIGHT);
+        field.setEditable(editable);
+        field.setBackground(Color.WHITE);
+        this.add(field, c);
+
+        ++this.currentGridY;
+
+        return field;
+    }
+
+    /**
+     * Add a field.
+     *
+     * @param name the name of the field
+     * @param value the default value of the field
+     * @param tooltip the tooltip text
+     * @param size the size of the field
+     * @param editable the editable setting
+     * @return the <code>JTextField</code> component
+     */
+    protected final JFormattedTextField addField(final String name, final String value, final String tooltip,
+            final int size, final boolean editable) {
+        final JFormattedTextField f = this.addField(name, value, size, editable);
         f.setToolTipText(tooltip);
         return f;
     }
 
     /**
-     * Add a field.
-     * @param name The name of the field.
-     * @param value The default value of the field.
-     * @param size The size of the field.
-     * @param editable The editable setting.
-     * @return The JTextField component.
-     */
-    protected final JFormattedTextField addField(String name, String value, int size, boolean editable) {
-        GridBagConstraints c = new GridBagConstraints();
-        c.gridx = 0;
-        c.gridy = currY;
-        c.insets = insets;
-        c.anchor = GridBagConstraints.WEST;
-        JLabel label = new JLabel(name + ":");
-        add(label, c);
-
-        c = new GridBagConstraints();
-        c.gridx = 1;
-        c.gridy = currY;
-        c.insets = insets;
-        c.anchor = GridBagConstraints.EAST;
-        // JFormattedTextField field = new JFormattedTextField(value, size);
-        JFormattedTextField field = new JFormattedTextField(value);
-        field.setColumns(size);
-        field.setHorizontalAlignment(JTextField.RIGHT);
-        field.setEditable(editable);
-        field.setBackground(Color.WHITE);
-        add(field, c);
-
-        ++currY;
-
-        return field;
-    }
-
-    /**
-     * Add a combo box.
-     * @param name The name of the combo box.
-     * @param values The set of values for the combo box.
-     * @return The JComboBox component.
-     */
-    protected final JComboBox addComboBox(String name, String[] values) {
-
-        // System.out.println("addComboBox = " + name);
-
-        GridBagConstraints c = new GridBagConstraints();
-        c.gridx = 0;
-        c.gridy = currY;
-        c.insets = insets;
-        c.anchor = GridBagConstraints.WEST;
-        JLabel waitModeLabel = new JLabel(name);
-        waitModeLabel.setHorizontalAlignment(JLabel.LEFT);
-        add(waitModeLabel, c);
-
-        c = new GridBagConstraints();
-        c.gridx = 1;
-        c.gridy = currY;
-        c.insets = insets;
-        c.anchor = GridBagConstraints.EAST;
-        JComboBox combo = new JComboBox(values);
-        // System.out.println("combo width = " + combo.getWidth());
-        // System.out.println("combo width = " + combo.getSize().getWidth());
-        combo.setEditable(editable);
-        add(combo, c);
-
-        ++currY;
-
-        return combo;
-    }
-
-    /**
-     * Add a multiline combo box.
-     * @param name The name of the combo box.
-     * @param values The values for the combo box.
-     * @return The JComboBox component.
-     */
-    protected final JComboBox addComboBoxMultiline(String name, String[] values) {
-
-        GridBagConstraints c = new GridBagConstraints();
-        c.gridx = 0;
-        c.gridwidth = GridBagConstraints.REMAINDER;
-        c.gridy = currY;
-        c.insets = insets;
-        c.anchor = GridBagConstraints.WEST;
-        JLabel waitModeLabel = new JLabel(name + ":");
-        waitModeLabel.setHorizontalAlignment(JLabel.LEFT);
-        add(waitModeLabel, c);
-        ++currY;
-
-        c = new GridBagConstraints();
-        c.gridx = 0;
-        c.gridwidth = GridBagConstraints.REMAINDER;
-        c.gridy = currY;
-        c.insets = insets;
-        c.anchor = GridBagConstraints.WEST;
-        JComboBox combo = new JComboBox(values);
-        // System.out.println("combo width = " + combo.getWidth());
-        // System.out.println("combo width = " + combo.getSize().getWidth());
-        combo.setEditable(editable);
-        add(combo, c);
-
-        ++currY;
-
-        return combo;
-    }
-
-    /**
-     * Add a check box.
-     * @param name The name of the check box.
-     * @param tooltip The tooltip text.
-     * @param selected Whether the box is selected or not.
-     * @param enabled Whether it is enabled or not.
-     * @return The JCheckBox component.
-     */
-    protected final JCheckBox addCheckBox(String name, String tooltip, boolean selected, boolean enabled) {
-        JCheckBox c = addCheckBox(name, selected, enabled);
-        c.setToolTipText(tooltip);
-        return c;
-    }
-
-    /**
-     * Add a check box.
-     * @param name The name of the check box.
-     * @param selected Whether the check box is selected or not.
-     * @param enabled Whether it is enabled or not.
-     * @return The JCheckBox component.
-     */
-    protected final JCheckBox addCheckBox(String name, boolean selected, boolean enabled) {
-
-        GridBagConstraints c = new GridBagConstraints();
-        c.gridx = 0;
-        c.gridy = currY;
-        c.insets = insets;
-        c.anchor = GridBagConstraints.WEST;
-        JLabel label = new JLabel(name + ":");
-        add(label, c);
-
-        c = new GridBagConstraints();
-        c.gridx = 1;
-        c.gridy = currY;
-        c.insets = insets;
-        c.anchor = GridBagConstraints.EAST;
-        JCheckBox checkbox = new JCheckBox();
-        checkbox.setSelected(selected);
-        checkbox.setEnabled(enabled);
-        add(checkbox, c);
-
-        ++currY;
-
-        return checkbox;
-    }
-
-    protected final JButton addButton(String text) {
-        GridBagConstraints c = new GridBagConstraints();
-        c.gridx = 0;
-        c.gridy = currY;
-        c.insets = insets;
-        c.anchor = GridBagConstraints.WEST;
-        c.gridwidth = 2;
-        JButton button = new JButton(text);
-        button.setSize(new Dimension(100, 50));
-        add(button, c);
-        ++currY;
-        return button;
-    }
-
-    /**
-     * Add an ActionListener to this component. By default this does nothing, but individual
-     * sub-components should attach this to individual components.
-     * @param listener The AcitonListener to add.
+     * Get the {@link org.hps.monitoring.application.model.ConfigurationModel} for this component.
+     *
+     * @return the {@link org.hps.monitoring.application.model.ConfigurationModel} for this component
      */
     @Override
-    public void addActionListener(ActionListener listener) {
-        // Sub-classes should add the listener to the appropriate child components.
-    }
-    
+    public ConfigurationModel getConfigurationModel() {
+        return this.configurationModel;
+    }
+
+    /**
+     * Handle a property change event.
+     *
+     * @param evt the property change event
+     */
+    @Override
+    public void propertyChange(final PropertyChangeEvent evt) {
+    }
+
     /**
      * Sub-classes should override this method to add their own listeners to update from the model.
+     *
+     * @param model the configuration model
      */
     @Override
-    public void setConfigurationModel(ConfigurationModel model) {
+    public void setConfigurationModel(final ConfigurationModel model) {
         this.configurationModel = model;
-        
+
         // This listener is used to push GUI values into the model.
         this.configurationModel.addPropertyChangeListener(this);
-    }        
-    
-    @Override
-    public ConfigurationModel getConfigurationModel() {
-        return configurationModel;
-    }
-    
-    /**
-     * Add a labeled JComponent to the panel.
-     * @param name The label text.
-     * @param component The component to add.
-     */
-    void addComponent(String name, JComponent component) {
-                
-        // Add the label.
-        GridBagConstraints c = new GridBagConstraints();
-        c.gridx = 0;
-        c.gridy = currY;
-        c.insets = insets;
-        c.anchor = GridBagConstraints.WEST;
-        JLabel label = new JLabel(name + ":");
-        add(label, c);
-
-        // Add the component.
-        c = new GridBagConstraints();
-        c.gridx = 1;
-        c.gridy = currY;
-        c.insets = insets;
-        c.anchor = GridBagConstraints.EAST;
-        add(component, c);
-
-        ++currY;
-    }
-    
-    boolean accept(PropertyChangeEvent evt) {
-        if (evt.getPropertyName().equals("ancestor")) {
-            return false;
-        } else {
-            return true;
-        }
-    }
-    
-    @Override
-    public void propertyChange(PropertyChangeEvent evt) {        
-    }    
-}
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AddActionListener.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AddActionListener.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/AddActionListener.java	Tue Apr 21 14:48:39 2015
@@ -2,7 +2,18 @@
 
 import java.awt.event.ActionListener;
 
+/**
+ * Mix-in interface for components which can be assigned an <code>ActionListener</code>.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
+ */
 interface AddActionListener {
 
+    /**
+     * Set an <code>ActionListener</code> for this component, which should assign it to appropriate child components
+     * that emit <code>ActionEvent</code> objects.
+     *
+     * @param listener the <code>ActionListener</code> to assign to this component
+     */
     void addActionListener(ActionListener listener);
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Commands.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Commands.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Commands.java	Tue Apr 21 14:48:39 2015
@@ -1,85 +1,256 @@
 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 <code>ActionEvent</code> commands in the MonitoringApplication.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 final class Commands {
 
-    // Settings
+    /**
+     * ET blocking setting changed.
+     */
+    static final String BLOCKING_CHANGED = "blockingChanged";
+
+    /**
+     * Choose a compact file for the detector description.
+     */
+    static final String CHOOSE_COMPACT_FILE = "chooseCompactFile";
+
+    /**
+     * Choose an LCSim job steering file.
+     */
+    static final String CHOOSE_STEERING_FILE = "chooseSteeringFile";
+
+    /**
+     * Clear the log table of all messages.
+     */
+    static final String CLEAR_LOG_TABLE = "clearLogTable";
+
+    /**
+     * Reset the underlying AIDA objects in the plot tree.
+     */
+    static final String CLEAR_PLOTS = "resetPlots";
+
+    /**
+     * Close the current input data file.
+     */
+    static final String CLOSE_FILE = "closeFile";
+
+    /**
+     * Change the current conditions tag.
+     */
+    static final String CONDITIONS_TAG_CHANGED = "conditionsTagChanged";
+
+    /**
+     * Connect to a new session.
+     */
+    static final String CONNECT = "connect";
+
+    /**
+     * Change the current data source.
+     */
+    static final String DATA_SOURCE_CHANGED = "dataSourceChanged";
+
+    /**
+     * Reset the application window to its default settings including scroll pane positions.
+     */
+    static final String DEFAULT_WINDOW = "defaultWindow";
+
+    /**
+     * Detector alias changed.
+     */
+    static final String DETECTOR_ALIAS_CHANGED = "detectorAliasChanged";
+
+    /**
+     * Name of detector changed.
+     */
+    static final String DETECTOR_NAME_CHANGED = "detectorNameChanged";
+
+    /**
+     * Disconnect the current session.
+     */
+    static final String DISCONNECT = "disconnect";
+
+    /**
+     * Disconnect on end run changed.
+     */
+    static final String DISCONNECT_ON_END_RUN_CHANGED = "disconnectOnEndRunChanged";
+
+    /**
+     * Disconnect on error changed.
+     */
+    static final String DISCONNECT_ON_ERROR_CHANGED = "disconnectOnErrorChanged";
+
+    /**
+     * Event builder setting changed.
+     */
+    static final String EVENT_BUILDER_CHANGED = "eventBuilderChanged";
+
+    /**
+     * Exit the application.
+     */
+    static final String EXIT = "exit";
+
+    /**
+     * Freeze conditions system after initialization.
+     */
+    static final String FREEZE_CONDITIONS_CHANGED = "freezeConditionsChanged";
+
+    /**
+     * Load the default properties file from a jar resource.
+     */
+    static final String LOAD_DEFAULT_SETTINGS = "loadDefaultSettings";
+
+    /**
+     * Load a settings properties file.
+     */
     static final String LOAD_SETTINGS = "loadSettings";
-    static final String LOAD_DEFAULT_SETTINGS = "loadDefaultSettings";
+
+    /**
+     * Global log level changed.
+     */
+    static final String LOG_LEVEL_CHANGED = "logLevelChanged";
+
+    /**
+     * Change the log level filter for showing messages in the log table.
+     */
+    static final String LOG_LEVEL_FILTER_CHANGED = "logLevelFilterChanged";
+
+    /**
+     * Send log messages to an output file.
+     */
+    static final String LOG_TO_FILE = "logToFile";
+
+    /**
+     * Send log messages to the terminal.
+     */
+    static final String LOG_TO_TERMINAL = "logToTerminal";
+
+    /**
+     * Maximize the application window.
+     */
+    static final String MAXIMIZE_WINDOW = "maximizeWindow";
+
+    /**
+     * Minimize the application window.
+     */
+    static final String MINIMIZE_WINDOW = "minimizeWindow";
+
+    /**
+     * Get the next event if paused.
+     */
+    static final String NEXT = "next";
+
+    /**
+     * Open an input data file.
+     */
+    static final String OPEN_FILE = "openFile";
+
+    /**
+     * Pause the event processing.
+     */
+    static final String PAUSE = "pause";
+
+    /**
+     * Action when plot is selected from a tab.
+     */
+    static final String PLOT_SELECTED = "PlotSelected";
+
+    /**
+     * Processing stage changed.
+     */
+    static final String PROCESSING_STAGE_CHANGED = "processingStageChanged";
+
+    /**
+     * Select one of the items from the recent files list to be the current data source.
+     */
+    static final String RECENT_FILE_SELECTED = "recentFileSelected";
+
+    /**
+     * Resume event processing if paused.
+     */
+    static final String RESUME = "resume";
+
+    /**
+     * Save the log table to a text file.
+     */
+    static final String SAVE_LOG_TABLE = "saveLogTable";
+
+    /**
+     * Save the plots to a ROOT, AIDA or PDF file.
+     */
+    static final String SAVE_PLOTS = "savePlots";
+
+    /**
+     * Save a screenshot from the window graphics.
+     */
+    static final String SAVE_SCREENSHOT = "saveScreenshot";
+
+    /**
+     * Save the currently selected plots tab graphic to a PDF file.
+     */
+    static final String SAVE_SELECTED_PLOTS = "saveSelectedPlots";
+
+    /**
+     * Save settings to a properties file.
+     */
     static final String SAVE_SETTINGS = "saveSettings";
+
+    /**
+     * Set the steering resource.
+     */
+    static final String SET_STEERING_RESOURCE = "setSteeringResource";
+
+    /**
+     * Okay button in settings panel.
+     */
+    static final String SETTINGS_OKAY_COMMAND = "settingsOkay";
+
+    /**
+     * Show the settings dialog.
+     */
     static final String SHOW_SETTINGS = "showSettings";
-    
-    // File open and close
-    static final String OPEN_FILE = "openFile";
-    static final String CLOSE_FILE = "closeFile"; 
-    static final String RECENT_FILE_SELECTED = "recentFileSelected";
-    
-    // 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";
-    
-    // Plotting actions
-    static final String SAVE_PLOTS = "savePlots";
-    static final String CLEAR_PLOTS = "resetPlots";
-    static final String SAVE_SELECTED_PLOTS = "saveSelectedPlots";
-    
-    // Exit the application.
-    static final String EXIT = "exit";
-           
-    // Log to file or standard print stream.
-    static final String LOG_TO_FILE = "logToFile";
-    static final String LOG_TO_TERMINAL = "logToTerminal";
-    
-    static final String LOG_LEVEL_FILTER_CHANGED = "logLevelFilterChanged";    
-    
-    static final String CONDITIONS_TAG_CHANGED = "conditionsTagChanged";
-    
+
+    /**
+     * Start the AIDA server.
+     */
     static final String START_AIDA_SERVER = "startAIDAServer";
+
+    /**
+     * Steering resource changed.
+     */
+    static final String STEERING_RESOURCE_CHANGED = "steeringResourceChanged";
+
+    /**
+     * Steering type changed (file or resource).
+     */
+    static final String STEERING_TYPE_CHANGED = "steeringTypeChanged";
+
+    /**
+     * Stop the AIDA server.
+     */
     static final String STOP_AIDA_SERVER = "stopAIDAServer";
-    
-    ////////////////////////////////////////////    
-    static final String BLOCKING_CHANGED = "blockingChanged";
-    static final String CHOOSE_COMPACT_FILE = "chooseCompactFile";
-    static final String CHOOSE_LOG_FILE = "chooseLogFile";
-    
-    static final String CHOOSE_STEERING_FILE = "chooseSteeringFile";
-    static final String CLEAR_LOG_TABLE = "clearLogTable";
-    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_ON_ERROR_CHANGED = "disconnectOnErrorChanged";
-    static final String DISCONNECT_ON_END_RUN_CHANGED = "disconnectOnEndRunChanged";
-    static final String EVENT_BUILDER_CHANGED = "eventBuilderChanged";
-    static final String FREEZE_CONDITIONS_CHANGED = "freezeConditionsChanged";
-    
-    static final String LOG_LEVEL_CHANGED = "logLevelChanged";
-    
-    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 STEERING_TYPE_CHANGED = "steeringTypeChanged";
-    static final String STEERING_RESOURCE_CHANGED = "steeringResourceChanged";
+
+    /**
+     * User run number in conditions system changed.
+     */
     static final String USER_RUN_NUMBER_CHANGED = "userRunNumberChanged";
+
+    /**
+     * Verbose setting changed.
+     */
     static final String VERBOSE_CHANGED = "verboseChanged";
-    static final String VALIDATE_DATA_FILE = "validateDataFile";
+
+    /**
+     * ET wait mode changed.
+     */
     static final String WAIT_MODE_CHANGED = "waitModeChanged";
-}
+
+    /**
+     * Do not allow class instantiation.
+     */
+    private Commands() {
+        throw new UnsupportedOperationException("Do no instantiate this class.");
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java	Tue Apr 21 14:48:39 2015
@@ -9,85 +9,144 @@
 
 /**
  * This is a table model for a collection of conditions objects.
- * @author Jeremy McCormick <[log in to unmask]>
  *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class ConditionsCollectionTableModel extends DefaultTableModel {
+@SuppressWarnings("serial")
+final class ConditionsCollectionTableModel extends DefaultTableModel {
 
-    ConditionsObjectCollection<?> collection;
-    int columnCount;
-    int rowCount;
-    String[] columnNames;
-    Class<?>[] columnTypes;
-    DatabaseConditionsManager manager;
-    
-    ConditionsCollectionTableModel(DatabaseConditionsManager manager, ConditionsObjectCollection<?> collection) {
-        
+    /**
+     * The {@link org.hps.conditions.api.ConditionsObjectCollection} for the model.
+     */
+    private final ConditionsObjectCollection<?> collection;
+
+    /**
+     * The number of columns.
+     */
+    private int columnCount;
+
+    /**
+     * The column names.
+     */
+    private String[] columnNames;
+
+    /**
+     * The column classes.
+     */
+    private Class<?>[] columnTypes;
+
+    /**
+     * The row count.
+     */
+    private final int rowCount;
+
+    /**
+     * Class constructor.
+     *
+     * @param manager the global conditions manager instance
+     * @param collection the {@link org.hps.conditions.api.ConditionsObjectCollection} providing data for the model
+     */
+    ConditionsCollectionTableModel(final DatabaseConditionsManager manager,
+            final ConditionsObjectCollection<?> collection) {
+
         // Set collection data.
         this.collection = collection;
-        rowCount = this.collection.size();
-        
-        String tableName = collection.getConditionsRecord().getTableName();                
-        TableMetaData tableInfo = manager.findTableMetaData(tableName);
+        this.rowCount = this.collection.size();
+
+        final String tableName = collection.getConditionsRecord().getTableName();
+        final TableMetaData tableInfo = manager.findTableMetaData(tableName);
 
         // Set column names and count from table meta data.
-        setupColumns(tableInfo);        
+        this.setupColumns(tableInfo);
     }
 
-    private void setupColumns(TableMetaData tableInfo) {
-
-        int fieldNameCount = tableInfo.getFieldNames().length;
-        columnCount = fieldNameCount + 1;
-        
-        columnTypes = new Class<?>[columnCount];                
-        columnNames = new String[columnCount];
-        
-        columnNames[0] = "id";
-        columnTypes[0] = int.class;
-        
-        for (int i = 0; i < fieldNameCount; i++) {
-            String fieldName = tableInfo.getFieldNames()[i];
-            columnNames[i + 1] = fieldName;
-            columnTypes[i + 1] = tableInfo.getFieldType(fieldName);
-        }
-    }
-
+    /**
+     * Get the class of a column.
+     *
+     * @param columnIndex the index of the column
+     */
     @Override
-    public int getRowCount() {
-        return rowCount;
-    }
-
-    @Override
-    public int getColumnCount() {
-        return columnCount;
-    }
-
-    @Override
-    public String getColumnName(int columnIndex) {
-        return columnNames[columnIndex];
-    }
-    
-    @Override
-    public Class<?> getColumnClass(int columnIndex) {
-        Class<?> columnClass = columnTypes[columnIndex];
-        if (columnClass.equals(int.class)) {
+    public Class<?> getColumnClass(final int columnIndex) {
+        final Class<?> columnClass = this.columnTypes[columnIndex];
+        if (int.class.equals(columnClass)) {
             return Integer.class;
-        } else if (columnClass.equals(float.class)) {
+        } else if (float.class.equals(columnClass)) {
             return Float.class;
-        } else if (columnClass.equals(double.class)) {
+        } else if (double.class.equals(columnClass)) {
             return Double.class;
         } else {
             return columnClass;
         }
     }
 
+    /**
+     * Get the number of columns.
+     *
+     * @return the number of columns
+     */
     @Override
-    public Object getValueAt(int rowIndex, int columnIndex) {
-        ConditionsObject object = collection.get(rowIndex);
+    public int getColumnCount() {
+        return this.columnCount;
+    }
+
+    /**
+     * Get the name of the column.
+     *
+     * @param columnIndex the column index
+     * @return the name of the column
+     */
+    @Override
+    public String getColumnName(final int columnIndex) {
+        return this.columnNames[columnIndex];
+    }
+
+    /**
+     * Get the row count.
+     *
+     * @return the row count
+     */
+    @Override
+    public int getRowCount() {
+        return this.rowCount;
+    }
+
+    /**
+     * Get a table cell value.
+     *
+     * @param rowIndex the row index
+     * @param columnIndex the column index
+     * @return the value of the cell
+     */
+    @Override
+    public Object getValueAt(final int rowIndex, final int columnIndex) {
+        final ConditionsObject object = this.collection.get(rowIndex);
         if (columnIndex == 0) {
             return object.getRowId();
         } else {
-            return object.getFieldValue(columnNames[columnIndex]);
+            return object.getFieldValue(this.columnNames[columnIndex]);
         }
     }
-}
+
+    /**
+     * Setup the columns from table meta data.
+     *
+     * @param tableInfo the {@link org.hps.conditions.database.TableMetaData} with the table info
+     */
+    private void setupColumns(final TableMetaData tableInfo) {
+
+        final int fieldNameCount = tableInfo.getFieldNames().length;
+        this.columnCount = fieldNameCount + 1;
+
+        this.columnTypes = new Class<?>[this.columnCount];
+        this.columnNames = new String[this.columnCount];
+
+        this.columnNames[0] = "id";
+        this.columnTypes[0] = int.class;
+
+        for (int i = 0; i < fieldNameCount; i++) {
+            final String fieldName = tableInfo.getFieldNames()[i];
+            this.columnNames[i + 1] = fieldName;
+            this.columnTypes[i + 1] = tableInfo.getFieldType(fieldName);
+        }
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsPanel.java	Tue Apr 21 14:48:39 2015
@@ -1,6 +1,3 @@
-/**
- * 
- */
 package org.hps.monitoring.application;
 
 import java.awt.BorderLayout;
@@ -29,65 +26,96 @@
 import org.lcsim.conditions.ConditionsListener;
 
 /**
- * @author Jeremy McCormick <[log in to unmask]>
+ * The component for showing conditions table records in the monitoring application tabs.
  *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-public class ConditionsPanel extends JPanel {
-    
-    JList<String> conditionsList = new JList<String>();
-    JTable conditionsTable = new JTable();
-    Map<String, ConditionsCollectionTableModel> tableModels;
-    
-    ConditionsPanel() {
-        super(new BorderLayout());
-        
-        conditionsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-        conditionsList.addListSelectionListener(new ListSelectionListener() {
-            @Override
-            public void valueChanged(ListSelectionEvent e) {
-                String tableName = (String) conditionsList.getSelectedValue();
-                TableModel model = tableModels.get(tableName);
-                conditionsTable.setModel(model);
-                conditionsTable.setRowSorter(new TableRowSorter(model));
-                conditionsTable.revalidate();
-            }            
-        });
-        
-        conditionsTable.setModel(new DefaultTableModel());
-               
-        JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, conditionsList, new JScrollPane(conditionsTable));
-        splitPane.setResizeWeight(0.6);
-        
-        add(splitPane);
-    }
-    
+@SuppressWarnings("serial")
+final class ConditionsPanel extends JPanel {
+
+    /**
+     * The listener for updating the panel when conditions are changed.
+     */
     class ConditionsPanelListener implements ConditionsListener {
 
+        /**
+         * Handle conditions change event.
+         *
+         * @param event the conditions change event
+         */
         @Override
-        public void conditionsChanged(ConditionsEvent event) {
+        public void conditionsChanged(final ConditionsEvent event) {
 
-            DatabaseConditionsManager manager = (DatabaseConditionsManager) event.getConditionsManager();
-            
-            tableModels = new LinkedHashMap<String, ConditionsCollectionTableModel>();            
-                         
+            final DatabaseConditionsManager manager = (DatabaseConditionsManager) event.getConditionsManager();
+
+            ConditionsPanel.this.tableModels = new LinkedHashMap<String, ConditionsCollectionTableModel>();
+
             // Set list of table names.
-            ConditionsRecordCollection records = 
-                    manager.getCachedConditions(ConditionsRecordCollection.class, "conditions").getCachedData();
+            final ConditionsRecordCollection records = manager.getCachedConditions(ConditionsRecordCollection.class,
+                    "conditions").getCachedData();
             records.sortByKey();
-            conditionsList.removeAll();
-            Set<String> tableNames = new LinkedHashSet<String>();
-            for (ConditionsRecord record : records) {                
+            ConditionsPanel.this.conditionsList.removeAll();
+            final Set<String> tableNames = new LinkedHashSet<String>();
+            for (final ConditionsRecord record : records) {
                 tableNames.add(record.getTableName());
-            }            
-            conditionsList.setListData(tableNames.toArray(new String[] {}));
-            
-            // Create list of table models.            
-            for (String tableName : tableNames) {
-                ConditionsObjectCollection<?> collection = manager.getCachedConditions(
-                                manager.findTableMetaData(tableName).getCollectionClass(), 
-                                tableName).getCachedData();
-                tableModels.put(tableName, new ConditionsCollectionTableModel(manager, collection));
+            }
+            ConditionsPanel.this.conditionsList.setListData(tableNames.toArray(new String[] {}));
+
+            // Create list of table models.
+            for (final String tableName : tableNames) {
+                final ConditionsObjectCollection<?> collection = manager.getCachedConditions(
+                        manager.findTableMetaData(tableName).getCollectionClass(), tableName).getCachedData();
+                ConditionsPanel.this.tableModels
+                        .put(tableName, new ConditionsCollectionTableModel(manager, collection));
             }
         }
     }
-}
+
+    /**
+     * The GUI component listing the conditions sets for the run.
+     */
+    private final JList<String> conditionsList = new JList<String>();
+
+    /**
+     * The table which shows the currently selected conditions set from the list.
+     */
+    private final JTable conditionsTable = new JTable();
+
+    /**
+     * Map of conditions set names to table models.
+     */
+    private Map<String, ConditionsCollectionTableModel> tableModels;
+
+    /**
+     * Class constructor which will initialize sub-components.
+     */
+    ConditionsPanel() {
+        super(new BorderLayout());
+
+        this.conditionsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        this.conditionsList.addListSelectionListener(new ListSelectionListener() {
+
+            /**
+             * The selection listener method implementation which will activate a new table in the conditions panel.
+             *
+             * @param e the list selection event
+             */
+            @Override
+            public void valueChanged(final ListSelectionEvent e) {
+                final String tableName = ConditionsPanel.this.conditionsList.getSelectedValue();
+                final TableModel model = ConditionsPanel.this.tableModels.get(tableName);
+                ConditionsPanel.this.conditionsTable.setModel(model);
+                ConditionsPanel.this.conditionsTable.setRowSorter(new TableRowSorter<TableModel>(model));
+                ConditionsPanel.this.conditionsTable.revalidate();
+            }
+        });
+
+        // Initialize with default table model.
+        this.conditionsTable.setModel(new DefaultTableModel());
+
+        final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, this.conditionsList, new JScrollPane(
+                this.conditionsTable));
+
+        this.add(splitPane);
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionSettingsPanel.java	Tue Apr 21 14:48:39 2015
@@ -15,189 +15,252 @@
 
 /**
  * Connection settings panel.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class ConnectionSettingsPanel extends AbstractFieldsPanel {
-
-    private JTextField etNameField;
-    private JTextField hostField;
-    private JTextField portField;
-    private JCheckBox blockingCheckBox;
-    private JCheckBox verboseCheckBox;
-    private JTextField stationNameField;
-    private JTextField chunkSizeField;
-    private JTextField queueSizeField;
-    private JTextField stationPositionField;
-    private JComboBox<?> waitModeComboBox;
-    private JTextField waitTimeField;
-    private JTextField prescaleField;
-
-    static final String[] waitModes = { 
-        Mode.SLEEP.name(), 
-        Mode.TIMED.name(), 
-        Mode.ASYNC.name() 
-    };
-
-    /**
-     * Class constructor.
-     */
-    ConnectionSettingsPanel() {
-
-        super(new Insets(5, 5, 5, 5), true);
-                        
-        setLayout(new GridBagLayout());
-
-        etNameField = addField("ET Name", "", 20);
-        etNameField.addPropertyChangeListener("value", this);
-
-        hostField = addField("Host", 20);
-        hostField.addPropertyChangeListener("value", this);
-
-        portField = addField("Port", 5);
-        portField.addPropertyChangeListener("value", this);
-
-        blockingCheckBox = addCheckBox("Blocking", false, true);
-        blockingCheckBox.setActionCommand(Commands.BLOCKING_CHANGED);
-        blockingCheckBox.addActionListener(this);
-
-        verboseCheckBox = addCheckBox("Verbose", false, true);
-        verboseCheckBox.setActionCommand(Commands.VERBOSE_CHANGED);
-        verboseCheckBox.addActionListener(this);
-
-        stationNameField = addField("Station Name", 10);
-        stationNameField.addPropertyChangeListener("value", this);
-
-        chunkSizeField = addField("Chunk Size", 3);
-        chunkSizeField.addPropertyChangeListener("value", this);
-
-        queueSizeField = addField("Queue Size", 3);
-        queueSizeField.addPropertyChangeListener("value", this);
-
-        stationPositionField = addField("Station Position", 3);
-        stationPositionField.addPropertyChangeListener("value", this);
-
-        waitModeComboBox = addComboBox("Wait Mode", waitModes);
-        waitModeComboBox.setActionCommand(Commands.WAIT_MODE_CHANGED);
-        waitModeComboBox.addActionListener(this);
-
-        waitTimeField = addField("Wait Time [microseconds]", 8);
-        waitTimeField.addPropertyChangeListener(this);
-
-        prescaleField = addField("Prescale", 8);
-        prescaleField.addPropertyChangeListener(this);
-    }
-
-    /**
-     * Enable or disable the connection panel GUI elements.
-     * @param e Set to true for enabled; false to disable.
-     */
-    void enableConnectionPanel(boolean e) {
-        etNameField.setEnabled(e);
-        hostField.setEnabled(e);
-        portField.setEnabled(e);
-        blockingCheckBox.setEnabled(e);
-        verboseCheckBox.setEnabled(e);
-        stationNameField.setEnabled(e);
-        chunkSizeField.setEnabled(e);
-        queueSizeField.setEnabled(e);
-        stationPositionField.setEnabled(e);
-        waitModeComboBox.setEnabled(e);
-        waitTimeField.setEnabled(e);
-        prescaleField.setEnabled(e);
-    }
-
-    /**
-     * Updates the GUI from changes in the ConfigurationModel.
+@SuppressWarnings("serial")
+final class ConnectionSettingsPanel extends AbstractFieldsPanel {
+
+    /**
+     * Update the GUI from changes in the {@link org.hps.monitoring.application.model.ConfigurationModel}.
      */
     public class ConnectionSettingsChangeListener implements PropertyChangeListener {
+
+        /**
+         * Handle a property change from the model.
+         *
+         * @param the <code>PropertyChangeEvent</code> to handle
+         */
         @Override
-        public void propertyChange(PropertyChangeEvent evt) {                       
-            configurationModel.removePropertyChangeListener(this);
+        public void propertyChange(final PropertyChangeEvent evt) {
+            ConnectionSettingsPanel.this.getConfigurationModel().removePropertyChangeListener(this);
             try {
-                Object value = evt.getNewValue();
+                final Object value = evt.getNewValue();
                 if (evt.getPropertyName().equals(ConfigurationModel.ET_NAME_PROPERTY)) {
-                    etNameField.setText((String) value);
+                    ConnectionSettingsPanel.this.etNameField.setText((String) value);
                 } else if (evt.getPropertyName().equals(ConfigurationModel.HOST_PROPERTY)) {
-                    hostField.setText((String) value);
+                    ConnectionSettingsPanel.this.hostField.setText((String) value);
                 } else if (evt.getPropertyName().equals(ConfigurationModel.PORT_PROPERTY)) {
-                    portField.setText(value.toString());
+                    ConnectionSettingsPanel.this.portField.setText(value.toString());
                 } else if (evt.getPropertyName().equals(ConfigurationModel.BLOCKING_PROPERTY)) {
-                    blockingCheckBox.setSelected((Boolean) value);
+                    ConnectionSettingsPanel.this.blockingCheckBox.setSelected((Boolean) value);
                 } else if (evt.getPropertyName().equals(ConfigurationModel.VERBOSE_PROPERTY)) {
-                    verboseCheckBox.setSelected((Boolean) value);
+                    ConnectionSettingsPanel.this.verboseCheckBox.setSelected((Boolean) value);
                 } else if (evt.getPropertyName().equals(ConfigurationModel.STATION_NAME_PROPERTY)) {
-                    stationNameField.setText((String) value);
+                    ConnectionSettingsPanel.this.stationNameField.setText((String) value);
                 } else if (evt.getPropertyName().equals(ConfigurationModel.CHUNK_SIZE_PROPERTY)) {
-                    chunkSizeField.setText(value.toString());
+                    ConnectionSettingsPanel.this.chunkSizeField.setText(value.toString());
                 } else if (evt.getPropertyName().equals(ConfigurationModel.QUEUE_SIZE_PROPERTY)) {
-                    queueSizeField.setText(value.toString());
+                    ConnectionSettingsPanel.this.queueSizeField.setText(value.toString());
                 } else if (evt.getPropertyName().equals(ConfigurationModel.STATION_POSITION_PROPERTY)) {
-                    stationPositionField.setText(value.toString());
+                    ConnectionSettingsPanel.this.stationPositionField.setText(value.toString());
                 } else if (evt.getPropertyName().equals(ConfigurationModel.WAIT_MODE_PROPERTY)) {
-                    waitModeComboBox.setSelectedItem(((Mode) value).name());
+                    ConnectionSettingsPanel.this.waitModeComboBox.setSelectedItem(((Mode) value).name());
                 } else if (evt.getPropertyName().equals(ConfigurationModel.WAIT_TIME_PROPERTY)) {
-                    waitTimeField.setText(value.toString());
+                    ConnectionSettingsPanel.this.waitTimeField.setText(value.toString());
                 } else if (evt.getPropertyName().equals(ConfigurationModel.PRESCALE_PROPERTY)) {
-                    prescaleField.setText(value.toString());
+                    ConnectionSettingsPanel.this.prescaleField.setText(value.toString());
                 }
             } finally {
-                configurationModel.addPropertyChangeListener(this);
+                ConnectionSettingsPanel.this.getConfigurationModel().addPropertyChangeListener(this);
             }
         }
     }
 
     /**
+     * The available wait mode settings (sleep, timed and asynchronous).
+     */
+    private static final String[] WAIT_MODES = {Mode.SLEEP.name(), Mode.TIMED.name(), Mode.ASYNC.name()};
+
+    /**
+     * Check box for blocking setting.
+     */
+    private final JCheckBox blockingCheckBox;
+
+    /**
+     * Field for chunk size.
+     */
+    private final JTextField chunkSizeField;
+
+    /**
+     * Field for ET name (file).
+     */
+    private final JTextField etNameField;
+
+    /**
+     * Field for host name.
+     */
+    private final JTextField hostField;
+
+    /**
+     * Field for TCP/IP port.
+     */
+    private final JTextField portField;
+
+    /**
+     * Field for prescale setting.
+     */
+    private final JTextField prescaleField;
+
+    /**
+     * Field for queue size.
+     */
+    private final JTextField queueSizeField;
+
+    /**
+     * Field for station name.
+     */
+    private final JTextField stationNameField;
+
+    /**
+     * Field for station position.
+     */
+    private final JTextField stationPositionField;
+
+    /**
+     * Check box for verbose flag.
+     */
+    private final JCheckBox verboseCheckBox;
+
+    /**
+     * Check box for wait mode selection.
+     */
+    private final JComboBox<?> waitModeComboBox;
+
+    /**
+     * Field for wait time.
+     */
+    private final JTextField waitTimeField;
+
+    /**
+     * Class constructor.
+     */
+    ConnectionSettingsPanel() {
+
+        super(new Insets(5, 5, 5, 5), true);
+
+        this.setLayout(new GridBagLayout());
+
+        this.etNameField = this.addField("ET Name", "", 20);
+        this.etNameField.addPropertyChangeListener("value", this);
+
+        this.hostField = this.addField("Host", 20);
+        this.hostField.addPropertyChangeListener("value", this);
+
+        this.portField = this.addField("Port", 5);
+        this.portField.addPropertyChangeListener("value", this);
+
+        this.blockingCheckBox = this.addCheckBox("Blocking", false, true);
+        this.blockingCheckBox.setActionCommand(Commands.BLOCKING_CHANGED);
+        this.blockingCheckBox.addActionListener(this);
+
+        this.verboseCheckBox = this.addCheckBox("Verbose", false, true);
+        this.verboseCheckBox.setActionCommand(Commands.VERBOSE_CHANGED);
+        this.verboseCheckBox.addActionListener(this);
+
+        this.stationNameField = this.addField("Station Name", 10);
+        this.stationNameField.addPropertyChangeListener("value", this);
+
+        this.chunkSizeField = this.addField("Chunk Size", 3);
+        this.chunkSizeField.addPropertyChangeListener("value", this);
+
+        this.queueSizeField = this.addField("Queue Size", 3);
+        this.queueSizeField.addPropertyChangeListener("value", this);
+
+        this.stationPositionField = this.addField("Station Position", 3);
+        this.stationPositionField.addPropertyChangeListener("value", this);
+
+        this.waitModeComboBox = this.addComboBox("Wait Mode", WAIT_MODES);
+        this.waitModeComboBox.setActionCommand(Commands.WAIT_MODE_CHANGED);
+        this.waitModeComboBox.addActionListener(this);
+
+        this.waitTimeField = this.addField("Wait Time [microseconds]", 8);
+        this.waitTimeField.addPropertyChangeListener(this);
+
+        this.prescaleField = this.addField("Prescale", 8);
+        this.prescaleField.addPropertyChangeListener(this);
+    }
+
+    /**
+     * Used to update the ConfigurationModel from GUI components.
+     *
+     * @param e the <code>ActionEvent</code> to handle
+     */
+    @Override
+    public void actionPerformed(final ActionEvent e) {
+        if (Commands.WAIT_MODE_CHANGED.equals(e.getActionCommand())) {
+            this.getConfigurationModel().setWaitMode(this.waitModeComboBox.getSelectedItem().toString());
+        } else if (Commands.BLOCKING_CHANGED.equals(e.getActionCommand())) {
+            this.getConfigurationModel().setBlocking(this.blockingCheckBox.isSelected());
+        } else if (Commands.VERBOSE_CHANGED.equals(e.getActionCommand())) {
+            this.getConfigurationModel().setVerbose(this.verboseCheckBox.isSelected());
+        }
+    }
+
+    /**
+     * Enable or disable the connection panel GUI elements.
+     *
+     * @param e <code>true</code> to enable the components in the panel
+     */
+    void enableConnectionPanel(final boolean e) {
+        this.etNameField.setEnabled(e);
+        this.hostField.setEnabled(e);
+        this.portField.setEnabled(e);
+        this.blockingCheckBox.setEnabled(e);
+        this.verboseCheckBox.setEnabled(e);
+        this.stationNameField.setEnabled(e);
+        this.chunkSizeField.setEnabled(e);
+        this.queueSizeField.setEnabled(e);
+        this.stationPositionField.setEnabled(e);
+        this.waitModeComboBox.setEnabled(e);
+        this.waitTimeField.setEnabled(e);
+        this.prescaleField.setEnabled(e);
+    }
+
+    /**
      * Updates ConfigurationModel from changes in the GUI components.
      */
     @Override
-    public void propertyChange(PropertyChangeEvent evt) {
-        if (!accept(evt)) {
+    public void propertyChange(final PropertyChangeEvent evt) {
+        if (!this.accept(evt)) {
             return;
-        }               
-        Object source = evt.getSource();
-        configurationModel.removePropertyChangeListener(this);
+        }
+        final Object source = evt.getSource();
+        this.getConfigurationModel().removePropertyChangeListener(this);
         try {
-            if (source.equals(etNameField)) {
-                configurationModel.setEtName(etNameField.getText());
-            } else if (source.equals(hostField)) {
-                configurationModel.setHost(hostField.getText());
-            } else if (source.equals(portField)) {
-                configurationModel.setPort(Integer.parseInt(portField.getText()));
-            } else if (source.equals(stationNameField)) {
-                configurationModel.setStationName(stationNameField.getText());
-            } else if (source.equals(chunkSizeField)) {
-                configurationModel.setChunkSize(Integer.parseInt(chunkSizeField.getText()));
-            } else if (source.equals(queueSizeField)) {
-                configurationModel.setQueueSize(Integer.parseInt(queueSizeField.getText()));
-            } else if (source.equals(stationPositionField)) {
-                configurationModel.setStationPosition(Integer.parseInt(stationPositionField.getText()));
-            } else if (source.equals(waitTimeField)) {
-                configurationModel.setWaitTime(Integer.parseInt(waitTimeField.getText()));
-            } else if (source.equals(prescaleField)) {
-                configurationModel.setPrescale(Integer.parseInt(prescaleField.getText()));
+            if (source.equals(this.etNameField)) {
+                this.getConfigurationModel().setEtName(this.etNameField.getText());
+            } else if (source.equals(this.hostField)) {
+                this.getConfigurationModel().setHost(this.hostField.getText());
+            } else if (source.equals(this.portField)) {
+                this.getConfigurationModel().setPort(Integer.parseInt(this.portField.getText()));
+            } else if (source.equals(this.stationNameField)) {
+                this.getConfigurationModel().setStationName(this.stationNameField.getText());
+            } else if (source.equals(this.chunkSizeField)) {
+                this.getConfigurationModel().setChunkSize(Integer.parseInt(this.chunkSizeField.getText()));
+            } else if (source.equals(this.queueSizeField)) {
+                this.getConfigurationModel().setQueueSize(Integer.parseInt(this.queueSizeField.getText()));
+            } else if (source.equals(this.stationPositionField)) {
+                this.getConfigurationModel().setStationPosition(Integer.parseInt(this.stationPositionField.getText()));
+            } else if (source.equals(this.waitTimeField)) {
+                this.getConfigurationModel().setWaitTime(Integer.parseInt(this.waitTimeField.getText()));
+            } else if (source.equals(this.prescaleField)) {
+                this.getConfigurationModel().setPrescale(Integer.parseInt(this.prescaleField.getText()));
             }
         } finally {
-            configurationModel.addPropertyChangeListener(this);
-        }
-    }
-
-    /**
-     * Used to update the ConfigurationModel from GUI components.
+            this.getConfigurationModel().addPropertyChangeListener(this);
+        }
+    }
+
+    /**
+     * Set configuration model (using <code>super</code> method) and add a property change listener for connection
+     * settings.
      */
     @Override
-    public void actionPerformed(ActionEvent e) {
-        if (Commands.WAIT_MODE_CHANGED.equals(e.getActionCommand())) {
-            configurationModel.setWaitMode(Mode.valueOf((String) waitModeComboBox.getSelectedItem()));
-        } else if (Commands.BLOCKING_CHANGED.equals(e.getActionCommand())) {
-            configurationModel.setBlocking(blockingCheckBox.isSelected());
-        } else if (Commands.VERBOSE_CHANGED.equals(e.getActionCommand())) {
-            configurationModel.setVerbose(verboseCheckBox.isSelected());
-        }
-    }
-    
-    public void setConfigurationModel(ConfigurationModel model) {
+    public void setConfigurationModel(final ConfigurationModel model) {
         super.setConfigurationModel(model);
-        
+
         // This listener updates the GUI from changes in the configuration.
-        this.configurationModel.addPropertyChangeListener(new ConnectionSettingsChangeListener());
-    }
-}
+        this.getConfigurationModel().addPropertyChangeListener(new ConnectionSettingsChangeListener());
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java	Tue Apr 21 14:48:39 2015
@@ -11,59 +11,82 @@
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JTextField;
+import javax.swing.SwingConstants;
 
 import org.hps.monitoring.application.model.ConnectionStatus;
 import org.hps.monitoring.application.model.ConnectionStatusModel;
 
 /**
- * This is the panel for showing the current connection status (connected, disconnected, etc.).
+ * This is the panel for showing the current connection status (connected, disconnected, etc.) in the tool bar.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class ConnectionStatusPanel extends JPanel implements PropertyChangeListener {
+@SuppressWarnings("serial")
+final class ConnectionStatusPanel extends JPanel implements PropertyChangeListener {
 
-    JTextField statusField;
-    JTextField dateField;
+    /**
+     * Date formatting.
+     */
+    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss");
 
-    // Format for date field.
-    private final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss");
-    
-    ConnectionStatusModel model;
+    /**
+     * Field for date when status changed (read only).
+     */
+    private final JTextField dateField;
+
+    /**
+     * The model for getting connection status changes.
+     */
+    private final ConnectionStatusModel model;
+
+    /**
+     * The field showing the current connection status (read only).
+     */
+    private final JTextField statusField;
 
     /**
      * Class constructor.
+     *
+     * @param model the model which notifies this component of connection status changes
      */
-    ConnectionStatusPanel(ConnectionStatusModel model) {
-        
+    ConnectionStatusPanel(final ConnectionStatusModel model) {
+
         this.model = model;
         this.model.addPropertyChangeListener(this);
-        
+
         setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0));
-                
-        statusField = new JTextField("", 10);
-        statusField.setHorizontalAlignment(JTextField.LEFT);
-        statusField.setEditable(false);
-        statusField.setBackground(Color.WHITE);
-        statusField.setFont(new Font("Arial", Font.BOLD, 16));
-        statusField.setForeground(model.getConnectionStatus().getColor());
-        statusField.setText(model.getConnectionStatus().name());
-        add(statusField);
-        
+
+        this.statusField = new JTextField("", 10);
+        this.statusField.setHorizontalAlignment(SwingConstants.LEFT);
+        this.statusField.setEditable(false);
+        this.statusField.setBackground(Color.WHITE);
+        this.statusField.setFont(new Font("Arial", Font.BOLD, 16));
+        this.statusField.setForeground(model.getConnectionStatus().getColor());
+        this.statusField.setText(model.getConnectionStatus().name());
+        add(this.statusField);
+
         add(new JLabel("@"));
-        
-        dateField = new JTextField("", 21);
-        dateField.setEditable(false);
-        dateField.setBackground(Color.WHITE);
-        dateField.setHorizontalAlignment(JTextField.LEFT);
-        dateField.setFont(new Font("Arial", Font.PLAIN, 14));
-        add(dateField);
+
+        this.dateField = new JTextField("", 21);
+        this.dateField.setEditable(false);
+        this.dateField.setBackground(Color.WHITE);
+        this.dateField.setHorizontalAlignment(SwingConstants.LEFT);
+        this.dateField.setFont(new Font("Arial", Font.PLAIN, 14));
+        add(this.dateField);
     }
 
+    /**
+     * Handle a property change event coming from the model.
+     *
+     * @param evt the property change event
+     */
     @Override
-    public void propertyChange(PropertyChangeEvent evt) {
+    public void propertyChange(final PropertyChangeEvent evt) {
         if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) {
             final ConnectionStatus status = (ConnectionStatus) evt.getNewValue();
-            statusField.setForeground(status.getColor());
-            statusField.setText(status.name());
-            dateField.setText(dateFormat.format(new Date()));
-        }        
+            this.statusField.setForeground(status.getColor());
+            this.statusField.setText(status.name());
+            this.dateField.setText(ConnectionStatusPanel.DATE_FORMAT.format(new Date()));
+        }
     }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DataSourceComboBox.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DataSourceComboBox.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DataSourceComboBox.java	Tue Apr 21 14:48:39 2015
@@ -21,28 +21,48 @@
 import org.hps.record.enums.DataSourceType;
 
 /**
- * This is a combo box that shows the current data source such as an LCIO file, EVIO file or ET ring.
- * It can also be used to select a new data source for the new session. 
+ * This is a combo box that shows the current data source such as an LCIO file, EVIO file or ET ring. It can also be
+ * used to select a data source for the next monitoring session.
  * <p>
- * The way this works is kind of odd because it is not directly connected to an event loop, so it must 
- * catch changes to the configuration and update its items accordingly.
+ * This component is not directly connected to an event loop, so it must catch changes to the configuration via property
+ * change events and then update its state accordingly.
  * <p>
- * A single ET item is kept in the list and updated as changes are made to the global configuration.
- * 
- * @author Jeremy McCormick <[log in to unmask]>
+ * Only a single "global" ET item is kept in the list, and it is updated as changes are made to the configuration model.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class DataSourceComboBox extends JComboBox<DataSourceItem> implements PropertyChangeListener, ActionListener{
-
-    ConnectionStatusModel connectionModel;
-    ConfigurationModel configurationModel;
-
+@SuppressWarnings("serial")
+final class DataSourceComboBox extends JComboBox<DataSourceItem> implements PropertyChangeListener, ActionListener {
+
+    /**
+     * This class represents a data source item in the combo box, which has a name for display, a full path to the file,
+     * and an implicit type (EVIO, LCIO or ET).
+     */
     static class DataSourceItem {
 
+        /**
+         * The name of the data source which will show in the drop down box.
+         */
         private String name;
-        private String path;
-        private DataSourceType type;
-
-        DataSourceItem(String path, String name, DataSourceType type) {
+
+        /**
+         * The full path used for the data source (for ET this is not used directly).
+         */
+        private final String path;
+
+        /**
+         * The implicit data type (EVIO, LCIO and ET).
+         */
+        private final DataSourceType type;
+
+        /**
+         * Create a data source item.
+         *
+         * @param path the data source path
+         * @param name the data source name
+         * @param type the data source type
+         */
+        DataSourceItem(final String path, final String name, final DataSourceType type) {
             if (path == null) {
                 throw new IllegalArgumentException("path is null");
             }
@@ -57,48 +77,81 @@
             this.path = path;
         }
 
-        public String toString() {
-            return name;
-        }
-        
-        public String getPath() {
-            return path;
-        }
-        
-        public String getName() {
-            return name;
-        }
-
-        public boolean equals(Object object) {
+        /**
+         * Implementation of equals operation.
+         *
+         * @param object the other object
+         */
+        @Override
+        public boolean equals(final Object object) {
             if (!(object instanceof DataSourceItem)) {
                 return false;
             }
-            DataSourceItem otherItem = (DataSourceItem) object;
-            if (this.name == otherItem.name && this.path == otherItem.path && this.type == otherItem.type) {
-                return true;
-            } else {
-                return false;
-            }
-        }
-    }
-    
-    @SuppressWarnings({ "rawtypes", "serial", "unchecked" })
-    DataSourceComboBox(ConfigurationModel configurationModel, ConnectionStatusModel connectionModel) {
+            final DataSourceItem otherItem = (DataSourceItem) object;
+            return this.name == otherItem.name && this.path == otherItem.path && this.type == otherItem.type;
+        }
+
+        /**
+         * Get the name of the source that is used as text in the drop down menu.
+         *
+         * @return the name of the data source
+         */
+        public String getName() {
+            return this.name;
+        }
+
+        /**
+         * Get the full path to the data source which is used as tool tip text (not used directly for ET sources).
+         *
+         * @return the full path to the data source
+         */
+        public String getPath() {
+            return this.path;
+        }
+
+        /**
+         * Convert this object to a string.
+         *
+         * @return this object converted to a string
+         */
+        @Override
+        public String toString() {
+            return this.name;
+        }
+    }
+
+    /**
+     * The preferred width of this component in pixels.
+     */
+    private static final int PREFERRED_WIDTH = 510;
+
+    /**
+     * The backing configuration model.
+     */
+    private ConfigurationModel configurationModel;
+
+    /**
+     * Create a new data source combo box.
+     *
+     * @param configurationModel the underlying configuration data model
+     * @param connectionModel the underlying connection status data model
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    DataSourceComboBox(final ConfigurationModel configurationModel, final ConnectionStatusModel connectionModel) {
         addActionListener(this);
         setActionCommand(Commands.DATA_SOURCE_CHANGED);
-        setPreferredSize(new Dimension(510, this.getPreferredSize().height));
+        setPreferredSize(new Dimension(PREFERRED_WIDTH, this.getPreferredSize().height));
         setEditable(false);
         this.configurationModel = configurationModel;
-        connectionModel.addPropertyChangeListener(this);                
+        connectionModel.addPropertyChangeListener(this);
         configurationModel.addPropertyChangeListener(this);
-        
-        ListCellRenderer renderer = new DefaultListCellRenderer() {
+
+        final ListCellRenderer renderer = new DefaultListCellRenderer() {
             @Override
-            public Component getListCellRendererComponent(JList<?> list,
-                    Object value, int index, boolean isSelected,
-                    boolean cellHasFocus) {
+            public Component getListCellRendererComponent(final JList<?> list, final Object value, final int index,
+                    final boolean isSelected, final boolean cellHasFocus) {
                 if (value instanceof DataSourceItem) {
-                    setToolTipText(((DataSourceItem)value).getPath());
+                    setToolTipText(((DataSourceItem) value).getPath());
                 } else {
                     setToolTipText(null);
                 }
@@ -108,48 +161,142 @@
         };
         this.setRenderer(renderer);
     }
-            
-    boolean containsItem(DataSourceItem item) {
+
+    /**
+     * Handle action events.
+     *
+     * @param evt the <code>ActionEvent</code> to handle
+     */
+    @Override
+    public void actionPerformed(final ActionEvent evt) {
+        if (evt.getActionCommand().equals(Commands.DATA_SOURCE_CHANGED)) {
+            try {
+                // Update the model with data source settings.
+                this.configurationModel.removePropertyChangeListener(this);
+                final DataSourceItem item = (DataSourceItem) getSelectedItem();
+                if (item != null) {
+                    this.configurationModel.setDataSourceType(item.type);
+                    if (item.type != DataSourceType.ET_SERVER) {
+                        this.configurationModel.setDataSourcePath(item.getPath());
+                    }
+                }
+            } finally {
+                this.configurationModel.addPropertyChangeListener(this);
+            }
+        }
+    }
+
+    /**
+     * Add a data source item with a specific type and path.
+     *
+     * @param path the data source path
+     * @param type the data source type
+     * @return the new data source item
+     */
+    DataSourceItem addDataSourceItem(final String path, final DataSourceType type) {
+        final DataSourceItem newItem = new DataSourceItem(path, new File(path).getName(), type);
+        addItem(newItem);
+        return newItem;
+    }
+
+    /**
+     * Add a data source item. Attempting to add an item that already exists will be ignored.
+     */
+    @Override
+    public void addItem(final DataSourceItem item) {
+        if (containsItem(item)) {
+            return;
+        }
+        if (findItem(item.getPath()) == null) {
+            super.addItem(item);
+        }
+    }
+
+    /**
+     * Return true if the (exact) given item exists in the combo box model.
+     *
+     * @param item the data source item
+     * @return <code>true</code> if data source item exists in the model
+     */
+    boolean containsItem(final DataSourceItem item) {
         return ((DefaultComboBoxModel<DataSourceItem>) getModel()).getIndexOf(item) != -1;
     }
 
+    /**
+     * Find the single data source item for the ET configuration in the items.
+     *
+     * @return the data source item for the ET configuration or <code>null</code> if does not exist
+     */
+    DataSourceItem findEtItem() {
+        for (int i = 0; i < this.getItemCount(); i++) {
+            final DataSourceItem item = this.getItemAt(i);
+            if (item.type == DataSourceType.ET_SERVER) {
+                return item;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Find an item by its path.
+     *
+     * @param path the path of the item
+     * @return the item or <code>null</code> if does not exist
+     */
+    DataSourceItem findItem(final String path) {
+        for (int i = 0; i < this.getItemCount(); i++) {
+            final DataSourceItem item = this.getItemAt(i);
+            if (item.getPath().equals(path)) {
+                return item;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Handle property change events which is used to update the GUI from changes to the global configuration model.
+     *
+     * @param evt the property change event
+     */
     @Override
-    public void propertyChange(PropertyChangeEvent evt) {
-        configurationModel.removePropertyChangeListener(this);
+    public void propertyChange(final PropertyChangeEvent evt) {
+        this.configurationModel.removePropertyChangeListener(this);
         try {
             if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) {
-                ConnectionStatus status = (ConnectionStatus) evt.getNewValue();
+                final ConnectionStatus status = (ConnectionStatus) evt.getNewValue();
                 if (status.equals(ConnectionStatus.DISCONNECTED)) {
                     setEnabled(true);
                 } else {
                     setEnabled(false);
                 }
             } else if (evt.getPropertyName().equals(ConfigurationModel.DATA_SOURCE_PATH_PROPERTY)) {
-                if (configurationModel.hasValidProperty(ConfigurationModel.DATA_SOURCE_TYPE_PROPERTY)) {                    
-                    String path = configurationModel.getDataSourcePath();
-                    DataSourceType type = DataSourceType.getDataSourceType(path);
+                if (this.configurationModel.hasValidProperty(ConfigurationModel.DATA_SOURCE_TYPE_PROPERTY)) {
+                    final String path = this.configurationModel.getDataSourcePath();
+                    final DataSourceType type = DataSourceType.getDataSourceType(path);
                     if (type.isFile()) {
                         DataSourceItem item = findItem(path);
                         if (item == null) {
                             item = addDataSourceItem(path, type);
                         }
-                        if (configurationModel.getDataSourceType().isFile()) {
+                        if (this.configurationModel.getDataSourceType().isFile()) {
                             setSelectedItem(item);
                         }
                     }
                 }
             } else if (evt.getPropertyName().equals(ConfigurationModel.DATA_SOURCE_TYPE_PROPERTY)) {
-                if (configurationModel.getDataSourceType() == DataSourceType.ET_SERVER) {
+                if (this.configurationModel.getDataSourceType() == DataSourceType.ET_SERVER) {
                     DataSourceItem item = findEtItem();
                     if (item == null) {
-                        item = new DataSourceItem(configurationModel.getEtPath(), configurationModel.getEtPath(), DataSourceType.ET_SERVER);
+                        item = new DataSourceItem(this.configurationModel.getEtPath(),
+                                this.configurationModel.getEtPath(), DataSourceType.ET_SERVER);
                     }
                     setSelectedItem(item);
                 } else {
-                    if (configurationModel.hasValidProperty(ConfigurationModel.DATA_SOURCE_PATH_PROPERTY)) {
-                        DataSourceItem item = findItem(configurationModel.getDataSourcePath());
+                    if (this.configurationModel.hasValidProperty(ConfigurationModel.DATA_SOURCE_PATH_PROPERTY)) {
+                        DataSourceItem item = findItem(this.configurationModel.getDataSourcePath());
                         if (item == null) {
-                            item = addDataSourceItem(configurationModel.getDataSourcePath(), configurationModel.getDataSourceType());
+                            item = addDataSourceItem(this.configurationModel.getDataSourcePath(),
+                                    this.configurationModel.getDataSourceType());
                         }
                         setSelectedItem(item);
                     }
@@ -162,76 +309,33 @@
                 updateEtItem();
             }
         } finally {
-            configurationModel.addPropertyChangeListener(this);
-        }
-    }
-    
+            this.configurationModel.addPropertyChangeListener(this);
+        }
+    }
+
+    /**
+     * Set the currently selected item.
+     *
+     * @param object the currently selected item (should be an instance of this class)
+     */
     @Override
-    public void setSelectedItem(Object object) {
+    public void setSelectedItem(final Object object) {
         super.setSelectedItem(object);
-        this.setToolTipText(((DataSourceItem)object).getPath());
-    }
-
-    public void actionPerformed(ActionEvent evt) {
-        if (evt.getActionCommand().equals(Commands.DATA_SOURCE_CHANGED)) {
-            try {
-                // Update the model with data source settings.
-                configurationModel.removePropertyChangeListener(this);
-                DataSourceItem item = (DataSourceItem) getSelectedItem();
-                if (item != null) {
-                    configurationModel.setDataSourceType(item.type);
-                    if (item.type != DataSourceType.ET_SERVER) {
-                        configurationModel.setDataSourcePath(item.getPath());
-                    }
-                }
-            } finally {
-                configurationModel.addPropertyChangeListener(this);
-            }
-        } 
-    }
-       
-    public void addItem(DataSourceItem item) {
-        if (containsItem(item)) {
-            return;
-        }
-        if (findItem(item.getPath()) == null) {
-            super.addItem(item);
-        }
-    }
-
-    DataSourceItem findItem(String path) {
-        for (int i = 0; i < this.getItemCount(); i++) {
-            DataSourceItem item = this.getItemAt(i);
-            if (item.getPath().equals(path)) {
-                return item;
-            }
-        }
-        return null;
-    }
-    
-    DataSourceItem findEtItem() {
-        for (int i = 0; i < this.getItemCount(); i++) {
-            DataSourceItem item = this.getItemAt(i);
-            if (item.type == DataSourceType.ET_SERVER) {
-                return item;
-            }
-        }
-        return null;
-    }
-
-    DataSourceItem addDataSourceItem(String path, DataSourceType type) {
-        DataSourceItem newItem = new DataSourceItem(path, new File(path).getName(), type);
-        addItem(newItem);
-        return newItem;
-    }
-    
+        this.setToolTipText(((DataSourceItem) object).getPath());
+    }
+
+    /**
+     * Update the path value of the current ET item from the current global configuration. There is only one ET item
+     * present in the list at one time so property changes to ET configuration will trigger this method.
+     */
     void updateEtItem() {
         DataSourceItem item = findEtItem();
         if (item == null) {
-            item = new DataSourceItem(configurationModel.getEtPath(), configurationModel.getEtPath(), DataSourceType.ET_SERVER);
+            item = new DataSourceItem(this.configurationModel.getEtPath(), this.configurationModel.getEtPath(),
+                    DataSourceType.ET_SERVER);
             addItem(item);
         } else {
-            item.name = configurationModel.getEtPath();
-        }
-    }
-}
+            item.name = this.configurationModel.getEtPath();
+        }
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DatePanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DatePanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/DatePanel.java	Tue Apr 21 14:48:39 2015
@@ -5,33 +5,72 @@
 import java.util.Date;
 
 /**
- * A small JPanel with a date field and a label on its border.
+ * A small <code>JPanel</code> with a date field and a label on its border.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class DatePanel extends FieldPanel {
+@SuppressWarnings("serial")
+final class DatePanel extends FieldPanel {
 
+    /**
+     * Default date formatting.
+     */
     private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
-    DatePanel(String fieldName, String defaultValue, int size, boolean editable) {
+    /**
+     * Create a date panel.
+     *
+     * @param fieldName the field name for the label
+     * @param defaultValue the default value
+     * @param format the date formatter
+     * @param size the size of the field
+     * @param editable <code>true</code> to enable editing
+     */
+    DatePanel(final String fieldName, final Date defaultValue, final SimpleDateFormat format, final int size,
+            final boolean editable) {
+        super(fieldName, format.format(defaultValue), size, editable);
+    }
+
+    /**
+     * Create a date panel with default date formatting.
+     *
+     * @param fieldName the field name for the label
+     * @param defaultValue the default value
+     * @param size the size of the field
+     * @param editable <code>true</code> to enable editing
+     */
+    DatePanel(final String fieldName, final String defaultValue, final int size, final boolean editable) {
         super(fieldName, defaultValue, size, editable);
     }
 
-    DatePanel(String fieldName, Date defaultValue, SimpleDateFormat format, int size, boolean editable) {
-        super(fieldName, format.format(defaultValue), size, editable);
+    /**
+     * Get the value of the field.
+     *
+     * @return the <code>Date</code> object
+     */
+    Date getDateValue() {
+        try {
+            return this.dateFormat.parse(getValue());
+        } catch (final ParseException e) {
+            throw new RuntimeException(e);
+        }
     }
 
-    void setDateFormat(SimpleDateFormat dateFormat) {
+    /**
+     * Set the date formatter.
+     *
+     * @param dateFormat the date formatter
+     */
+    void setDateFormat(final SimpleDateFormat dateFormat) {
         this.dateFormat = dateFormat;
     }
 
-    void setValue(Date date) {
-        setValue(dateFormat.format(date));
-    }
-
-    Date getDateValue() {
-        try {
-            return dateFormat.parse(getValue());
-        } catch (ParseException e) {
-            throw new RuntimeException(e);
-        }
+    /**
+     * Set the value of the field.
+     *
+     * @param date the <code>Date</code> object
+     */
+    void setValue(final Date date) {
+        setValue(this.dateFormat.format(date));
     }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java	Tue Apr 21 14:48:39 2015
@@ -16,32 +16,94 @@
 import org.hps.monitoring.application.model.ConnectionStatusModel;
 
 /**
- * This is the panel with buttons for connecting or disconnecting from the session
- * and controlling the application from pause mode.
+ * This is the panel with buttons for connecting or disconnecting from the session and controlling the application when
+ * event processing is paused.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class EventButtonsPanel extends JPanel implements PropertyChangeListener {
+@SuppressWarnings("serial")
+final class EventButtonsPanel extends JPanel implements PropertyChangeListener {
 
-    JButton nextButton;
-    JButton pauseButton;
-    JButton connectButton;
-    JButton resumeButton;
-    
-    static final ImageIcon connectedIcon = getImageIcon("/monitoringButtonGraphics/connected-128.png");
-    static final ImageIcon disconnectedIcon = getImageIcon("/monitoringButtonGraphics/disconnected-128.png");
-    
-    EventButtonsPanel(ConnectionStatusModel connectionModel, ActionListener listener) {
-        
+    /**
+     * Icon when application is connected to event processing session.
+     */
+    static final ImageIcon CONNECTED_ICON = getImageIcon("/monitoringButtonGraphics/connected-128.png");
+
+    /**
+     * Icon when application is disconnected from event processing.
+     */
+    static final ImageIcon DISCONNECTED_ICON = getImageIcon("/monitoringButtonGraphics/disconnected-128.png");
+
+    /**
+     * The icon size (width and height) in pixels.
+     */
+    private static final int ICON_SIZE = 24;
+
+    /**
+     * Get an image icon from a jar resource.
+     *
+     * @param resource the resource path
+     * @return the image icon
+     */
+    static ImageIcon getImageIcon(final String resource) {
+        Image image = null;
+        try {
+            image = ImageIO.read(EventButtonsPanel.class.getResource(resource));
+            image = image.getScaledInstance(ICON_SIZE, ICON_SIZE, 0);
+        } catch (final IOException e) {
+        }
+        return new ImageIcon(image);
+    }
+
+    /**
+     * Button for connect and disconnect which is toggled depending on state.
+     */
+    private final JButton connectButton;
+
+    /**
+     * Button for getting next event when paused.
+     */
+    private final JButton nextButton;
+
+    /**
+     * Button for pausing the event processing.
+     */
+    private final JButton pauseButton;
+
+    /**
+     * Button for resuming the event processing.
+     */
+    private final JButton resumeButton;
+
+    /**
+     * Class constructor.
+     *
+     * @param connectionModel the global connection model
+     * @param listener the action listener
+     */
+    EventButtonsPanel(final ConnectionStatusModel connectionModel, final ActionListener listener) {
+
         connectionModel.addPropertyChangeListener(this);
-        
+
         setLayout(new FlowLayout());
-        connectButton = addButton(disconnectedIcon, Commands.CONNECT, listener, true);
-        resumeButton = addButton("/toolbarButtonGraphics/media/Play24.gif", Commands.RESUME, listener, false);
-        pauseButton = addButton("/toolbarButtonGraphics/media/Pause24.gif", Commands.PAUSE, listener, false);
-        nextButton = addButton("/toolbarButtonGraphics/media/StepForward24.gif", Commands.NEXT, listener, false);
+        this.connectButton = addButton(DISCONNECTED_ICON, Commands.CONNECT, listener, true);
+        this.resumeButton = addButton("/toolbarButtonGraphics/media/Play24.gif", Commands.RESUME, listener, false);
+        this.pauseButton = addButton("/toolbarButtonGraphics/media/Pause24.gif", Commands.PAUSE, listener, false);
+        this.nextButton = addButton("/toolbarButtonGraphics/media/StepForward24.gif", Commands.NEXT, listener, false);
     }
-           
-    final JButton addButton(ImageIcon icon, String command, ActionListener listener, boolean enabled) {
-        JButton button = new JButton();
+
+    /**
+     * Add a button to the panel.
+     *
+     * @param icon the button's image icon
+     * @param command the command for the action event
+     * @param listener the action listener which handles action events
+     * @param enabled <code>true</code> if button should be enabled initially
+     * @return the new button object
+     */
+    private JButton addButton(final ImageIcon icon, final String command, final ActionListener listener,
+            final boolean enabled) {
+        final JButton button = new JButton();
         button.setIcon(icon);
         button.setEnabled(enabled);
         button.addActionListener(listener);
@@ -49,21 +111,26 @@
         this.add(button);
         return button;
     }
-    
-    final JButton addButton(String resource, String actionCommand, ActionListener listener, boolean enabled) {
+
+    /**
+     * Add a button to the panel.
+     *
+     * @param resource the resource for the image icon
+     * @param actionCommand the command for the action event
+     * @param listener the action listener which handles action events
+     * @param enabled <code>true</code> if button should be enabled initially
+     * @return the new button object
+     */
+    private JButton addButton(final String resource, final String actionCommand, final ActionListener listener,
+            final boolean enabled) {
         return addButton(getImageIcon(resource), actionCommand, listener, enabled);
     }
-        
-    static ImageIcon getImageIcon(String resource) {
-        Image image = null;
-        try {
-            image = ImageIO.read(EventButtonsPanel.class.getResource(resource));
-            image = image.getScaledInstance(24, 24, 0);
-        } catch (IOException e) {            
-        }
-        return new ImageIcon(image);
-    }
 
+    /**
+     * Handle property change events to set status from changes to the connection status model.
+     *
+     * @param evt the <code>PropertyChangeEvent</code> to handle
+     */
     @Override
     public void propertyChange(final PropertyChangeEvent evt) {
         if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) {
@@ -72,35 +139,45 @@
             setPaused((boolean) evt.getNewValue());
         }
     }
-    
-    void setConnectionStatus(final ConnectionStatus status) {
+
+    /**
+     * Set the connection status to update the button state.
+     *
+     * @param status the new connection status
+     */
+    private void setConnectionStatus(final ConnectionStatus status) {
         if (status.equals(ConnectionStatus.DISCONNECTED)) {
-            nextButton.setEnabled(false);
-            pauseButton.setEnabled(false);
-            resumeButton.setEnabled(false);
-            connectButton.setActionCommand(Commands.CONNECT);
-            connectButton.setIcon(disconnectedIcon);
-            connectButton.setToolTipText("Start new session");
-            connectButton.setEnabled(true);
+            this.nextButton.setEnabled(false);
+            this.pauseButton.setEnabled(false);
+            this.resumeButton.setEnabled(false);
+            this.connectButton.setActionCommand(Commands.CONNECT);
+            this.connectButton.setIcon(DISCONNECTED_ICON);
+            this.connectButton.setToolTipText("Start new session");
+            this.connectButton.setEnabled(true);
         } else if (status.equals(ConnectionStatus.DISCONNECTING)) {
-            nextButton.setEnabled(false);
-            pauseButton.setEnabled(false);
-            resumeButton.setEnabled(false);
-            connectButton.setEnabled(false);
+            this.nextButton.setEnabled(false);
+            this.pauseButton.setEnabled(false);
+            this.resumeButton.setEnabled(false);
+            this.connectButton.setEnabled(false);
         } else if (status.equals(ConnectionStatus.CONNECTED)) {
-            nextButton.setEnabled(false);            
-            pauseButton.setEnabled(true);
-            resumeButton.setEnabled(false);
-            connectButton.setActionCommand(Commands.DISCONNECT);
-            connectButton.setIcon(connectedIcon);
-            connectButton.setToolTipText("Disconnect from session");
-            connectButton.setEnabled(true);
+            this.nextButton.setEnabled(false);
+            this.pauseButton.setEnabled(true);
+            this.resumeButton.setEnabled(false);
+            this.connectButton.setActionCommand(Commands.DISCONNECT);
+            this.connectButton.setIcon(CONNECTED_ICON);
+            this.connectButton.setToolTipText("Disconnect from session");
+            this.connectButton.setEnabled(true);
         }
-    }       
-    
-    void setPaused(final boolean paused) {
-        resumeButton.setEnabled(paused);
-        pauseButton.setEnabled(!paused);
-        nextButton.setEnabled(paused);
     }
-}
+
+    /**
+     * Set pause mode.
+     *
+     * @param paused <code>true</code> to set paused state
+     */
+    private void setPaused(final boolean paused) {
+        this.resumeButton.setEnabled(paused);
+        this.pauseButton.setEnabled(!paused);
+        this.nextButton.setEnabled(paused);
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventDashboard.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventDashboard.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventDashboard.java	Tue Apr 21 14:48:39 2015
@@ -20,248 +20,387 @@
 import org.lcsim.event.EventHeader;
 
 /**
- * Dashboard for displaying information about the current run.
- * @author Jeremy McCormick <[log in to unmask]>
+ * This class implements a dashboard for displaying information about the current run.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class EventDashboard extends JPanel implements PropertyChangeListener {
-
-    FieldPanel runNumberField = new FieldPanel("Run Number", "", 10, false);
-    DatePanel startDateField = new DatePanel("Run Start", "", 14, false);
-    DatePanel endDateField = new DatePanel("Run End", "", 14, false);
-    FieldPanel lengthField = new FieldPanel("Run Length [sec]", "", 12, false);
-    FieldPanel totalEventsField = new FieldPanel("Total Events in Run", "", 14, false);
-    FieldPanel elapsedTimeField = new FieldPanel("Elapsed Time [sec]", "", 14, false);
-    FieldPanel eventsReceivedField = new FieldPanel("Events Received", "", 14, false);
-    FieldPanel dataReceivedField = new FieldPanel("Data Received [MB]", "", 14, false);
-    FieldPanel eventNumberField = new FieldPanel("Event Number", "", 14, false);
-    FieldPanel dataRateField = new FieldPanel("Data Rate [MB/s]", "", 12, false);
-    FieldPanel eventRateField = new FieldPanel("Event Rate [Hz]", "", 14, false);
-
-    RunModel runModel;
-    
-    static final NumberFormat formatter = new DecimalFormat("#0.0000"); 
-
-    public EventDashboard() {
-        build();
-    }
-    
-    public EventDashboard(RunModel runModel) {
-        this.runModel = runModel;
-        this.runModel.addPropertyChangeListener(this);
-        build();
-    }
-    
-    private void build() {
-        
-        setLayout(new FlowLayout(FlowLayout.LEADING));
-
-        add(runNumberField);
-        add(startDateField);
-        add(endDateField);
-        add(lengthField);
-        add(totalEventsField);
-        
-        add(elapsedTimeField);
-        add(eventsReceivedField);
-        add(dataReceivedField);
-        add(eventNumberField);
-        add(dataRateField);
-        add(eventRateField);
-    }
-    
-    public void setModel(RunModel runModel) {
-        this.runModel = runModel;
-    }
-
+@SuppressWarnings("serial")
+final class EventDashboard extends JPanel implements PropertyChangeListener {
+
+    /**
+     * Updates the fields as events are processed.
+     */
     class EventDashboardUpdater extends CompositeRecordProcessor {
 
-        Timer timer;
-        
-        int eventsReceived;
-        double bytesReceived;
-        int totalEvents;
-        int eventNumber;
-        int runNumber = -1;
-        long jobStartMillis;
-        long lastTickMillis = 0;
-        static final long millis = 1000;
-        
+        /**
+         * Task to periodically update the fields as events are processed.
+         */
         class RunTimerTask extends TimerTask {
-            
-            public void run() {                     
-                                
-                double tickLengthSeconds = (System.currentTimeMillis() - lastTickMillis) / (double)millis;
-                int elapsedTime = (int) ((System.currentTimeMillis() - jobStartMillis) / (double)millis);
-                double megaBytesReceived = bytesReceived / 1000000;
-                totalEvents += eventsReceived;
-
-                /*
-                System.out.println("tickLengthSeconds = " + tickLengthSeconds);
-                System.out.println("elapsedTime = " + elapsedTime);
-                System.out.println("eventsReceived = " + eventsReceived);
-                System.out.println("dataRate = " + (megaBytesReceived / tickLengthSeconds));
-                System.out.println("eventNumber = " + eventNumber);
-                System.out.println("eventRate = " + (eventsReceived / tickLengthSeconds));
-                System.out.println("totalEvents = " + totalEvents);
-                System.out.println("megaBytesReceived = " + megaBytesReceived);
-                */
-                
-                runModel.setElapsedTime(elapsedTime);
-                runModel.setEventsReceived(totalEvents);
-                runModel.setDataRate(megaBytesReceived / tickLengthSeconds);
-                runModel.addDataReceived(megaBytesReceived);
-                runModel.setEventNumber(eventNumber);
-                runModel.setEventRate(eventsReceived / tickLengthSeconds);
-                
-                eventsReceived = 0;
-                bytesReceived = 0;
-                eventNumber = 0;  
-                
-                lastTickMillis = System.currentTimeMillis();
-                
+
+            /**
+             * Run the timer task to update the GUI from the current values in the model.
+             */
+            @Override
+            public void run() {
+
+                final double tickLengthSeconds = (System.currentTimeMillis() - EventDashboardUpdater.this.lastTickMillis)
+                        / (double) MILLIS;
+                final int elapsedTime = (int) ((System.currentTimeMillis() - EventDashboardUpdater.this.jobStartMillis) / (double) MILLIS);
+                final double megaBytesReceived = EventDashboardUpdater.this.bytesReceived / 1000000;
+                EventDashboardUpdater.this.totalEvents += EventDashboardUpdater.this.eventsReceived;
+
+                // Print to System.out if debugging the processor (by default this is off).
+                if (DEBUG) {
+                    System.out.println("tickLengthSeconds = " + tickLengthSeconds);
+                    System.out.println("elapsedTime = " + elapsedTime);
+                    System.out.println("eventsReceived = " + EventDashboardUpdater.this.eventsReceived);
+                    System.out.println("dataRate = " + megaBytesReceived / tickLengthSeconds);
+                    System.out.println("eventNumber = " + EventDashboardUpdater.this.eventNumber);
+                    System.out.println("eventRate = " + EventDashboardUpdater.this.eventsReceived / tickLengthSeconds);
+                    System.out.println("totalEvents = " + EventDashboardUpdater.this.totalEvents);
+                    System.out.println("megaBytesReceived = " + megaBytesReceived);
+
+                }
+
+                EventDashboard.this.runModel.setElapsedTime(elapsedTime);
+                EventDashboard.this.runModel.setEventsReceived(EventDashboardUpdater.this.totalEvents);
+                EventDashboard.this.runModel.setDataRate(megaBytesReceived / tickLengthSeconds);
+                EventDashboard.this.runModel.addDataReceived(megaBytesReceived);
+                EventDashboard.this.runModel.setEventNumber(EventDashboardUpdater.this.eventNumber);
+                EventDashboard.this.runModel
+                        .setEventRate(EventDashboardUpdater.this.eventsReceived / tickLengthSeconds);
+
+                EventDashboardUpdater.this.eventsReceived = 0;
+                EventDashboardUpdater.this.bytesReceived = 0;
+                EventDashboardUpdater.this.eventNumber = 0;
+
+                EventDashboardUpdater.this.lastTickMillis = System.currentTimeMillis();
+
                 // System.out.println();
-            }        
-        }
-        
+            }
+        }
+
+        /**
+         * Set to <code>true</code> to enable debugging.
+         */
+        private static final boolean DEBUG = false;
+
+        /**
+         * Helper for second to milliseconds conversion.
+         */
+        private static final long MILLIS = 1000;
+
+        /**
+         * Helper for second to nanoseconds conversion.
+         */
+        private static final int NANOS = 1000000000;
+
+        /**
+         * The number of bytes received.
+         */
+        private double bytesReceived;
+
+        /**
+         * The current event number.
+         */
+        private int eventNumber;
+
+        /**
+         * The number of events received.
+         */
+        private int eventsReceived;
+
+        /**
+         * The system time in milliseconds when the job started.
+         */
+        private long jobStartMillis;
+
+        /**
+         * The system time in milliseconds when the last timer tick occurred.
+         */
+        private long lastTickMillis = 0;
+
+        /**
+         * The current run number.
+         */
+        private int runNumber = -1;
+
+        /**
+         * The timer for running the update task.
+         */
+        private Timer timer;
+
+        /**
+         * The total number of events received.
+         */
+        private int totalEvents;
+
+        /**
+         * Check for head bank and update the run info if necessary.
+         *
+         * @param evioEvent the EVIO event
+         */
+        private void checkHeadBank(final EvioEvent evioEvent) {
+            final BaseStructure headBank = EvioEventUtilities.getHeadBank(evioEvent);
+            if (headBank != null) {
+                final int headBankRun = headBank.getIntData()[1];
+                if (headBankRun != this.runNumber) {
+                    this.runNumber = headBankRun;
+                    EventDashboard.this.runModel.setRunNumber(headBankRun);
+                    EventDashboard.this.runModel.setStartDate(new Date(headBank.getIntData()[3] * MILLIS));
+                }
+            }
+        }
+
+        /**
+         * Perform end of job hook, which will cancel the update timer.
+         */
         @Override
-        public void startJob() {
-            runModel.reset();
-            jobStartMillis = System.currentTimeMillis();
-            
-            // Start the timer to update GUI components about once per second.
-            timer = new Timer("RunModelUpdaterTimer");
-            lastTickMillis = System.currentTimeMillis();
-            timer.scheduleAtFixedRate(new RunTimerTask(), 0, 1000);
-        }
-
+        public void endJob() {
+            this.timer.cancel();
+
+            // Push final values into GUI.
+            this.timer = new Timer("RunModelUpdaterEndJobTimer");
+            this.timer.schedule(new RunTimerTask(), 0);
+        }
+
+        /**
+         * Handle an EVIO END event.
+         *
+         * @param evioEvent the EVIO END event
+         */
+        private void endRun(final EvioEvent evioEvent) {
+            // Get end run data.
+            final int[] data = EvioEventUtilities.getControlEventData(evioEvent);
+            if (data != null) {
+                final int seconds = data[0];
+                final int eventCount = data[2];
+                final long endMillis = (long) seconds * 1000;
+
+                // Update the GUI.
+                EventDashboard.this.runModel.setEndDate(new Date(endMillis));
+                EventDashboard.this.runModel.computeRunLength();
+                EventDashboard.this.runModel.setTotalEvents(eventCount);
+            }
+        }
+
+        /**
+         * Process a {@link org.hps.record.composite.CompositeRecord} to extract information from available event
+         * sources and update the running values.
+         */
         @Override
-        public void process(CompositeRecord event) {          
+        public void process(final CompositeRecord event) {
             // FIXME: CompositeRecord number is always -1 here.
             if (event.getEvioEvent() != null) {
-                EvioEvent evioEvent = event.getEvioEvent();
-                bytesReceived += evioEvent.getTotalBytes();
+                final EvioEvent evioEvent = event.getEvioEvent();
+                this.bytesReceived += evioEvent.getTotalBytes();
                 if (EvioEventUtilities.isPreStartEvent(evioEvent)) {
                     // Get run start info from pre start event.
                     startRun(evioEvent);
                 } else if (EvioEventUtilities.isEndEvent(evioEvent)) {
                     // Get end run info from end event.
                     endRun(evioEvent);
-                } else if (EvioEventUtilities.isPhysicsEvent(evioEvent)) {                    
+                } else if (EvioEventUtilities.isPhysicsEvent(evioEvent)) {
                     // Check for run info in head bank.
                     checkHeadBank(evioEvent);
-                    eventNumber = evioEvent.getEventNumber();
-                    eventsReceived += 1;
+                    this.eventNumber = evioEvent.getEventNumber();
+                    this.eventsReceived += 1;
                 }
             } else if (event.getEtEvent() != null) {
-                bytesReceived += event.getEtEvent().getData().length;
-                eventNumber = event.getEtEvent().getId();
-                eventsReceived += 1;
+                this.bytesReceived += event.getEtEvent().getData().length;
+                this.eventNumber = event.getEtEvent().getId();
+                this.eventsReceived += 1;
             } else if (event.getLcioEvent() != null) {
-                EventHeader lcioEvent = event.getLcioEvent();
-                eventNumber = lcioEvent.getEventNumber();
-                if (lcioEvent.getRunNumber() != runNumber) {
-                    runNumber = lcioEvent.getRunNumber();
+                final EventHeader lcioEvent = event.getLcioEvent();
+                this.eventNumber = lcioEvent.getEventNumber();
+                if (lcioEvent.getRunNumber() != this.runNumber) {
+                    this.runNumber = lcioEvent.getRunNumber();
                     startRun(lcioEvent);
                 }
-                eventsReceived += 1;
-            }                    
-        }
-
-        /**
-         * Check for head bank and update the run info if necessary.
-         * @param evioEvent The EVIO event.
-         */
-        private void checkHeadBank(EvioEvent evioEvent) {
-            BaseStructure headBank = EvioEventUtilities.getHeadBank(evioEvent);
-            if (headBank != null) {
-                int headBankRun = headBank.getIntData()[1];
-                if (headBankRun != runNumber) {
-                    runNumber = headBankRun;
-                    runModel.setRunNumber(headBankRun);
-                    runModel.setStartDate(new Date(headBank.getIntData()[3] * 1000));
-                }
-            }
-        }
-
-        private void endRun(EvioEvent evioEvent) {
-            // Get end run data.
-            int[] data = EvioEventUtilities.getControlEventData(evioEvent);
+                this.eventsReceived += 1;
+            }
+        }
+
+        /**
+         * Perform start of job hook which initializes this processor.
+         */
+        @Override
+        public void startJob() {
+            EventDashboard.this.runModel.reset();
+            this.jobStartMillis = System.currentTimeMillis();
+
+            // Start the timer to update GUI components about once per second.
+            this.timer = new Timer("RunModelUpdaterTimer");
+            this.lastTickMillis = System.currentTimeMillis();
+            this.timer.scheduleAtFixedRate(new RunTimerTask(), 0, MILLIS);
+        }
+
+        /**
+         * Handle start of run using an LCIO event.
+         *
+         * @param lcioEvent the LCIO event
+         */
+        private void startRun(final EventHeader lcioEvent) {
+            EventDashboard.this.runModel.setRunNumber(lcioEvent.getRunNumber());
+            final long seconds = lcioEvent.getTimeStamp() / NANOS;
+            EventDashboard.this.runModel.setStartDate(new Date((int) seconds));
+        }
+
+        /**
+         * Handle start of run using an EVIO START event.
+         *
+         * @param evioEvent the EVIO START event
+         */
+        private void startRun(final EvioEvent evioEvent) {
+            // Get start of run data.
+            final int[] data = EvioEventUtilities.getControlEventData(evioEvent);
             if (data != null) {
-                int seconds = data[0];
-                int eventCount = data[2];
-                long endMillis = ((long) seconds) * 1000;
+                final int seconds = data[0];
+                this.runNumber = data[1];
 
                 // Update the GUI.
-                runModel.setEndDate(new Date(endMillis));
-                runModel.computeRunLength();
-                runModel.setTotalEvents(eventCount);
-            }
-        }
-
-        private void startRun(EvioEvent evioEvent) {
-            // Get start of run data.
-            int[] data = EvioEventUtilities.getControlEventData(evioEvent);
-            if (data != null) {
-                int seconds = data[0];
-                runNumber = data[1];
-                
-                // Update the GUI.
-                runModel.setRunNumber(runNumber);
-                runModel.setStartDate(new Date(seconds * 1000));
-            }
-        }
-        
-        private void startRun(EventHeader lcioEvent) {
-            runModel.setRunNumber(lcioEvent.getRunNumber());
-            long seconds = lcioEvent.getTimeStamp() / 1000000000;
-            runModel.setStartDate(new Date((int)seconds));
-        }
-        
-        @Override
-        public void endJob() {
-            timer.cancel();
-            
-            // Push final values into GUI.
-            timer = new Timer("RunModelUpdaterEndJobTimer");
-            timer.schedule(new RunTimerTask(), 0);
+                EventDashboard.this.runModel.setRunNumber(this.runNumber);
+                EventDashboard.this.runModel.setStartDate(new Date(seconds * MILLIS));
+            }
         }
     }
-    
-    /**
-     * Update the GUI from changes to the backing RunModel object.
+
+    /**
+     * The decimal format (shows decimal numbers to 4 places).
+     */
+    static final NumberFormat DECIMAL_FORMAT = new DecimalFormat("#0.0000");
+
+    /**
+     * Field for showing the data rate in MB per second.
+     */
+    private final FieldPanel dataRateField = new FieldPanel("Data Rate [MB/s]", "", 12, false);
+
+    /**
+     * Field for showing the total data received in MB.
+     */
+    private final FieldPanel dataReceivedField = new FieldPanel("Data Received [MB]", "", 14, false);
+
+    /**
+     * Field for showing the elapsed job time in seconds.
+     */
+    private final FieldPanel elapsedTimeField = new FieldPanel("Elapsed Time [sec]", "", 14, false);
+
+    /**
+     * Field for showing the end date.
+     */
+    private final DatePanel endDateField = new DatePanel("Run End", "", 14, false);
+
+    /**
+     * Field for showing the current event number.
+     */
+    private final FieldPanel eventNumberField = new FieldPanel("Event Number", "", 14, false);
+
+    /**
+     * Field showing the event rate in Hertz.
+     */
+    private final FieldPanel eventRateField = new FieldPanel("Event Rate [Hz]", "", 14, false);
+
+    /**
+     * Field for showing the total number of events received.
+     */
+    private final FieldPanel eventsReceivedField = new FieldPanel("Events Received", "", 14, false);
+
+    /**
+     * Field for showing the length of the run in seconds.
+     */
+    private final FieldPanel lengthField = new FieldPanel("Run Length [sec]", "", 12, false);
+
+    /**
+     * The backing model with run and event information.
+     */
+    private final RunModel runModel;
+
+    /**
+     * Field for showing the run number.
+     */
+    private final FieldPanel runNumberField = new FieldPanel("Run Number", "", 10, false);
+
+    /**
+     * Field for showing the start date.
+     */
+    private final DatePanel startDateField = new DatePanel("Run Start", "", 14, false);
+
+    /**
+     * Field for showing the total events in the run.
+     */
+    private final FieldPanel totalEventsField = new FieldPanel("Total Events in Run", "", 14, false);
+
+    /**
+     * Class constructor which takes reference to backing model.
+     *
+     * @param runModel the backing {@link org.hps.monitoring.application.model.RunModel} with event and run information
+     */
+    public EventDashboard(final RunModel runModel) {
+        this.runModel = runModel;
+        this.runModel.addPropertyChangeListener(this);
+        build();
+    }
+
+    /**
+     * Build the GUI components.
+     */
+    private void build() {
+
+        setLayout(new FlowLayout(FlowLayout.LEADING));
+
+        add(this.runNumberField);
+        add(this.startDateField);
+        add(this.endDateField);
+        add(this.lengthField);
+        add(this.totalEventsField);
+
+        add(this.elapsedTimeField);
+        add(this.eventsReceivedField);
+        add(this.dataReceivedField);
+        add(this.eventNumberField);
+        add(this.dataRateField);
+        add(this.eventRateField);
+    }
+
+    /**
+     * Update the GUI from changes to the backing {@link org.hps.monitoring.application.model.RunModel} object.
+     *
+     * @param evt the {@link java.beans.PropertyChangeEvent} to handle
      */
     @Override
-    public void propertyChange(PropertyChangeEvent evt) {
-        //System.out.println("RunPanel.propertyChange - " + evt.getPropertyName());
-        Object value = evt.getNewValue();
+    public void propertyChange(final PropertyChangeEvent evt) {
+        // System.out.println("RunPanel.propertyChange - " + evt.getPropertyName());
+        final Object value = evt.getNewValue();
         if (RunModel.RUN_NUMBER_PROPERTY.equals(evt.getPropertyName())) {
-            runNumberField.setValue((Integer) value);
+            this.runNumberField.setValue((Integer) value);
         } else if (RunModel.START_DATE_PROPERTY.equals(evt.getPropertyName())) {
-            if (value != null)
-                startDateField.setValue((Date) value);
-            else
-                startDateField.setValue("");
+            if (value != null) {
+                this.startDateField.setValue((Date) value);
+            } else {
+                this.startDateField.setValue("");
+            }
         } else if (RunModel.END_DATE_PROPERTY.equals(evt.getPropertyName())) {
-            if (value != null)
-                endDateField.setValue((Date) value);
-            else
-                endDateField.setValue("");
+            if (value != null) {
+                this.endDateField.setValue((Date) value);
+            } else {
+                this.endDateField.setValue("");
+            }
         } else if (RunModel.RUN_LENGTH_PROPERTY.equals(evt.getPropertyName())) {
-            lengthField.setValue((Integer) value);
+            this.lengthField.setValue((Integer) value);
         } else if (RunModel.TOTAL_EVENTS_PROPERTY.equals(evt.getPropertyName())) {
-            totalEventsField.setValue((Integer) value);
+            this.totalEventsField.setValue((Integer) value);
         } else if (RunModel.EVENTS_RECEIVED_PROPERTY.equals(evt.getPropertyName())) {
-            eventsReceivedField.setValue((Integer) value);
+            this.eventsReceivedField.setValue((Integer) value);
         } else if (RunModel.ELAPSED_TIME_PROPERTY.equals(evt.getPropertyName())) {
-            elapsedTimeField.setValue((Integer) value);
+            this.elapsedTimeField.setValue((Integer) value);
         } else if (RunModel.DATA_RECEIVED_PROPERTY.equals(evt.getPropertyName())) {
-            dataReceivedField.setValue(formatter.format((Double) value));
+            this.dataReceivedField.setValue(DECIMAL_FORMAT.format(value));
         } else if (RunModel.EVENT_NUMBER_PROPERTY.equals(evt.getPropertyName())) {
-            eventNumberField.setValue((Integer) value);
+            this.eventNumberField.setValue((Integer) value);
         } else if (RunModel.DATA_RATE_PROPERTY.equals(evt.getPropertyName())) {
-            dataRateField.setValue(formatter.format((Double) value));
+            this.dataRateField.setValue(DECIMAL_FORMAT.format(value));
         } else if (RunModel.EVENT_RATE_PROPERTY.equals(evt.getPropertyName())) {
-            eventRateField.setValue(formatter.format((Double) value));
+            this.eventRateField.setValue(DECIMAL_FORMAT.format(value));
         }
     }
-}
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventProcessing.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventProcessing.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventProcessing.java	Tue Apr 21 14:48:39 2015
@@ -18,7 +18,6 @@
 import org.hps.monitoring.application.model.SteeringType;
 import org.hps.monitoring.application.util.ErrorHandler;
 import org.hps.monitoring.application.util.EtSystemUtil;
-import org.hps.monitoring.application.util.SyncEventProcessor;
 import org.hps.monitoring.subsys.et.EtSystemMonitor;
 import org.hps.monitoring.subsys.et.EtSystemStripCharts;
 import org.hps.record.LCSimEventBuilder;
@@ -27,13 +26,9 @@
 import org.hps.record.composite.CompositeRecordProcessor;
 import org.hps.record.composite.EventProcessingThread;
 import org.hps.record.enums.DataSourceType;
-import org.hps.record.epics.EpicsEtProcessor;
 import org.hps.record.et.EtConnection;
-import org.hps.record.et.EtEventProcessor;
 import org.hps.record.et.EtStationThread;
-import org.hps.record.et.PreStartProcessor;
 import org.hps.record.evio.EvioDetectorConditionsProcessor;
-import org.hps.record.evio.EvioEventConstants;
 import org.jlab.coda.et.EtConstants;
 import org.jlab.coda.et.exception.EtClosedException;
 import org.jlab.coda.et.exception.EtException;
@@ -43,665 +38,722 @@
 import org.lcsim.util.Driver;
 
 /**
- * This class encapsulates all of the logic involved with processing events and managing the related
- * state and objects within the monitoring application.
- * 
- * @author Jeremy McCormick <[log in to unmask]>
+ * This class encapsulates all of the logic involved with processing events and managing the related state and objects
+ * within the monitoring application.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class EventProcessing {
-
-    SessionState sessionState;
-    MonitoringApplication application;
-    ConfigurationModel configurationModel;
-    ConnectionStatusModel connectionModel;
-    ErrorHandler errorHandler;
-    Logger logger;
-    
-    /**
-     * This class is used to organize the objects for an event processing session.
-     */
-    class SessionState {
-        
-        List<CompositeRecordProcessor> processors;
-        List<Driver> drivers;
-        List<ConditionsListener> conditionsListeners;
-        
-        JobManager jobManager;
-        LCSimEventBuilder eventBuilder;
-        CompositeLoop loop;
-        
-        boolean usingEtServer;
-        
-        EventProcessingThread processingThread;
-        Thread sessionWatchdogThread;
-        ThreadGroup stationThreadGroup = new ThreadGroup("Station Threads");
-        List<EtStationThread> stations = new ArrayList<EtStationThread>();
-        EtConnection connection;                                      
-    }
-
-    /**
-     * Initialize with reference to the current monitoring application and a list of extra
-     * processors to add to the loop after configuration.
-     * @param application The current monitoring application.
-     * @param processors A list of processors to add after configuration is performed.
-     */
-    EventProcessing(
-            MonitoringApplication application, 
-            List<CompositeRecordProcessor> processors, 
-            List<Driver> drivers, 
-            List<ConditionsListener> conditionsListeners) {
-        
+final class EventProcessing {
+
+    /**
+     * This class organizes and encapsulates most of the objects used by an event processing session.
+     */
+    private final class SessionState {
+
+        /**
+         * A list of extra {@link org.lcsim.conditions.ConditionsListener} objects to add to the loop.
+         */
+        private List<ConditionsListener> conditionsListeners;
+
+        /**
+         * An {@link org.hps.record.et.EtConnection} with ET configuration (can be null if using a file source).
+         */
+        private EtConnection connection;
+
+        /**
+         * A list of extra {@link org.lcsim.util.Driver} objects to add to the loop.
+         */
+        private List<Driver> drivers;
+
+        /**
+         * The class for building the LCSim events from EVIO data.
+         */
+        private LCSimEventBuilder eventBuilder;
+
+        /**
+         * The LCSim {@link org.hps.job.JobManager} which handles the <code>Driver</code> setup from XML steering files.
+         */
+        private JobManager jobManager;
+
+        /**
+         * The loop which manages the ET to EVIO to LCIO event building and processing.
+         */
+        private CompositeLoop loop;
+
+        /**
+         * The {@link org.hps.record.composite.EventProcessingThread} on which event processing executes.
+         */
+        private EventProcessingThread processingThread;
+
+        /**
+         * The list of extra {@link org.hps.record.composite.CompositeRecordProcessor} objects to add to the loop.
+         */
+        private List<CompositeRecordProcessor> processors;
+
+        /**
+         * A {@link java.lang.Thread} which is used to monitor the event processing.
+         */
+        private Thread sessionWatchdogThread;
+
+        /**
+         * A list of ET stations on separate threads (currently unused).
+         */
+        private List<EtStationThread> stations = new ArrayList<EtStationThread>();
+
+        /**
+         * The ET station thread group (currently unused).
+         */
+        private ThreadGroup stationThreadGroup = new ThreadGroup("Station Threads");
+
+        /**
+         * This is <code>true</code> if the session will connect to a network ET event server.
+         */
+        private boolean usingEtServer;
+    }
+
+    /**
+     * This class will cause the application to disconnect from the current event processing session if the event
+     * processing thread completes.
+     */
+    private final class SessionWatchdogThread extends Thread {
+
+        /**
+         * A reference to the current {{@link #EventProcessing(Thread)}.
+         */
+        private final Thread processingThread;
+
+        /**
+         * Class constructor.
+         *
+         * @param processingThread the current {{@link #EventProcessing(Thread)}
+         */
+        private SessionWatchdogThread(final Thread processingThread) {
+            this.processingThread = processingThread;
+        }
+
+        /**
+         * Run this thread, which will disconnect from the current session if the event processing ends for any reason.
+         */
+        @Override
+        public void run() {
+            try {
+                // This thread waits on the event processing thread to die.
+                this.processingThread.join();
+
+                // Activate a disconnect using the ActionEvent which is used by the disconnect button.
+                EventProcessing.this.logger.finest("processing thread ended so automatic disconnect is happening");
+                EventProcessing.this.application.actionPerformed(new ActionEvent(Thread.currentThread(), 0,
+                        Commands.DISCONNECT));
+
+            } catch (final InterruptedException e) {
+                EventProcessing.this.logger.finest("SessionWatchdogThread got interrupted");
+                // This happens when the thread is interrupted by the user pressing the disconnect button.
+            }
+        }
+    }
+
+    /**
+     * Create the select array from event selection in ET stations (not currently used).
+     *
+     * @return The select array.
+     */
+    static int[] createSelectArray() {
+        final int[] select = new int[EtConstants.stationSelectInts];
+        Arrays.fill(select, -1);
+        return select;
+    }
+
+    /**
+     * Reference to the current application.
+     */
+    private MonitoringApplication application;
+
+    /**
+     * Reference to the global configuration model.
+     */
+    private ConfigurationModel configurationModel;
+
+    /**
+     * Reference to the global connection model.
+     */
+    private ConnectionStatusModel connectionModel;
+
+    /**
+     * The error handler, which is just a reference to the application's error handler.
+     */
+    private ErrorHandler errorHandler;
+
+    /**
+     * The logger to use for message which is the application's logger.
+     */
+    private Logger logger;
+
+    /**
+     * The current {@link EventProcessing.SessionState} object which has all of the session state for event processing.
+     */
+    private SessionState sessionState;
+
+    /**
+     * Class constructor, which will initialize with reference to the current monitoring application and lists of extra
+     * processors to add to the loop, as well as supplemental conditions listeners that activate when the conditions
+     * change.
+     *
+     * @param application the current monitoring application object
+     * @param processors a list of processors to add after configuration is performed
+     * @param drivers a list of extra {@link org.lcsim.util.Driver} objects to add to the loop
+     * @param conditionsListeners a list of extra {@link org.lcsim.conditions.ConditionsListener} to add to the loop
+     */
+    EventProcessing(final MonitoringApplication application, final List<CompositeRecordProcessor> processors,
+            final List<Driver> drivers, final List<ConditionsListener> conditionsListeners) {
+
         this.application = application;
-        logger = MonitoringApplication.logger;        
-        configurationModel = application.configurationModel;
-        connectionModel = application.connectionModel;
-        errorHandler = application.errorHandler;
-        
-        sessionState = new SessionState();                        
-        sessionState.processors = processors;
-        sessionState.drivers = drivers;
-        sessionState.conditionsListeners = conditionsListeners;
-        sessionState.usingEtServer = application.configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER);
-    }
-    
-    /**
-     * Setup this class from the global configuration.
-     * @param configurationModel The global configuration.
-     */
-    void setup(ConfigurationModel configurationModel) {
-        
+        this.logger = application.getLogger();
+        this.configurationModel = application.getConfigurationModel();
+        this.connectionModel = application.getConnectionModel();
+        this.errorHandler = application.getErrorHandler();
+
+        this.sessionState = new SessionState();
+        this.sessionState.processors = processors;
+        this.sessionState.drivers = drivers;
+        this.sessionState.conditionsListeners = conditionsListeners;
+        this.sessionState.usingEtServer = application.getConfigurationModel().getDataSourceType()
+                .equals(DataSourceType.ET_SERVER);
+    }
+
+    /**
+     * Close the current ET connection.
+     * <p>
+     * This method does not need to be <code>synchronized</code>, because it is only called from the
+     * {@link #disconnect()} method which is itself <code>synchronized</code>.
+     */
+    private void closeEtConnection() {
+        if (this.sessionState.connection != null) {
+            this.logger.fine("closing ET connection");
+            if (this.sessionState.connection.getEtSystem().alive()) {
+                this.logger.finest("cleaning up the connection ...");
+                this.sessionState.connection.cleanup();
+                this.logger.finest("connection cleanup successful");
+            }
+            this.sessionState.connection = null;
+            this.logger.fine("ET connection closed");
+        }
+    }
+
+    /**
+     * Connect to the ET system using the current connection settings.
+     *
+     * @throws IOException if any error occurs while creating the ET connection
+     */
+    synchronized void connect() throws IOException {
+        // Setup the network connection if using an ET server.
+        if (this.usingEtServer()) {
+            // Create a connection to the ET server.
+            try {
+                this.logger.fine("connecting to ET system ...");
+
+                // Create the main ET system connection.
+                this.createEtConnection();
+
+                // FIXME: Separate event processing ET stations not currently used due to synchronization and ET issues.
+
+                // Add an attachment that listens for DAQ configuration changes via physics SYNC events.
+                // createSyncStation();
+
+                // Add an attachment which listens for EPICs events with scalar data.
+                // createEpicsStation();
+
+                // Add an attachment that listens for PRESTART events.
+                // createPreStartStation();
+
+            } catch (final Exception e) {
+                throw new IOException(e);
+            }
+
+            this.logger.fine("ET system is connected");
+        } else {
+            // This is when a direct file source is used and ET is not needed.
+            this.connectionModel.setConnectionStatus(ConnectionStatus.CONNECTED);
+        }
+
+    }
+
+    /**
+     * Create a connection to an ET system using current parameters from the GUI.
+     * <p>
+     * This method does not need to be <code>synchronized</code>, because it is only called from the {@link #connect()}
+     * method which is itself <code>synchronized</code>.
+     */
+    private void createEtConnection() {
+        // Setup connection to ET system.
+        this.sessionState.connection = EtSystemUtil.createEtConnection(this.configurationModel);
+
+        if (this.sessionState.connection != null) {
+            // Set status to connected as there is now a live ET connection.
+            this.connectionModel.setConnectionStatus(ConnectionStatus.CONNECTED);
+        } else {
+            this.errorHandler.setError(new RuntimeException("Failed to create ET connection.")).log().printStackTrace()
+                    .raiseException();
+        }
+    }
+
+    /**
+     * Create the event builder for converting EVIO events to LCSim.
+     *
+     * @param configurationModel the current global {@link org.hps.monitoring.application.ConfigurationModel} object
+     */
+    private void createEventBuilder(final ConfigurationModel configurationModel) {
+
+        // Get the class for the event builder.
+        final String eventBuilderClassName = configurationModel.getEventBuilderClassName();
+
+        try {
+            // Create a new instance of the builder class.
+            this.sessionState.eventBuilder = (LCSimEventBuilder) Class.forName(eventBuilderClassName, true,
+                    Thread.currentThread().getContextClassLoader()).newInstance();
+        } catch (final Exception e) {
+            throw new RuntimeException("Failed to create LCSimEventBuilder.", e);
+        }
+
+        // Add the builder as a listener so it is notified when conditions change.
+        ConditionsManager.defaultInstance().addConditionsListener(this.sessionState.eventBuilder);
+    }
+
+    /**
+     * Disconnect from the current session, closing the ET connection if necessary.
+     */
+    synchronized void disconnect() {
+
+        // Cleanup the ET connection.
+        if (this.usingEtServer()) {
+            this.closeEtConnection();
+        }
+
+        // Change application state to disconnected.
+        this.connectionModel.setConnectionStatus(ConnectionStatus.DISCONNECTED);
+    }
+
+    /**
+     * Invalidate all of the local variables and session state so that this object is not usable after a disconnect.
+     */
+    void invalidate() {
+
+        this.application = null;
+        this.logger = null;
+        this.configurationModel = null;
+        this.connectionModel = null;
+        this.errorHandler = null;
+
+        this.sessionState.conditionsListeners = null;
+        this.sessionState.drivers = null;
+        this.sessionState.processors = null;
+        this.sessionState.jobManager = null;
+        this.sessionState.eventBuilder = null;
+        this.sessionState.loop = null;
+        this.sessionState.processingThread = null;
+        this.sessionState.sessionWatchdogThread = null;
+        this.sessionState.stationThreadGroup = null;
+        this.sessionState.stations = null;
+        this.sessionState.connection = null;
+
+        this.sessionState = null;
+    }
+
+    /**
+     * Return <code>true</code> if the event processing thread is valid (non-null) and active.
+     *
+     * @return <code>true</code> if event processing thread is active
+     */
+    boolean isActive() {
+        return this.sessionState.processingThread != null && this.sessionState.processingThread.isAlive();
+    }
+
+    /**
+     * Interrupt and join the processing watchdog thread.
+     * <p>
+     * This will happen if there is a user requested disconnect from pushing the button in the GUI.
+     */
+    synchronized void killWatchdogThread() {
+        // Is the session watchdog thread not null?
+        if (this.sessionState.sessionWatchdogThread != null) {
+            this.logger.finest("killing watchdog thread ...");
+            // Is the thread still alive?
+            if (this.sessionState.sessionWatchdogThread.isAlive()) {
+                // Interrupt the thread which should cause it to stop.
+                this.sessionState.sessionWatchdogThread.interrupt();
+                try {
+                    // This should always work once the thread is interrupted.
+                    this.sessionState.sessionWatchdogThread.join();
+                } catch (final InterruptedException e) {
+                }
+            }
+            // Set the thread object to null.
+            this.sessionState.sessionWatchdogThread = null;
+            this.logger.finest("watchdog thread killed");
+        }
+    }
+
+    /**
+     * Get the next event from the loop if in pause mode.
+     */
+    synchronized void next() {
+        this.logger.finest("getting next event");
+        if (this.connectionModel.getPaused()) {
+            this.connectionModel.setPaused(false);
+            this.sessionState.loop.execute(Command.GO_N, 1L, true);
+            this.connectionModel.setPaused(true);
+        }
+        this.logger.finest("got next event");
+    }
+
+    /**
+     * Notify the loop to pause the event processing.
+     */
+    synchronized void pause() {
+        this.logger.finest("pausing");
+        if (!this.connectionModel.getPaused()) {
+            this.sessionState.loop.pause();
+            this.connectionModel.setPaused(true);
+        }
+        this.logger.finest("paused");
+    }
+
+    /**
+     * Resume processing events from pause mode by resuming loop event processing.
+     */
+    synchronized void resume() {
+        this.logger.finest("resuming");
+        if (this.connectionModel.getPaused()) {
+            // Notify event processor to continue.
+            this.sessionState.loop.resume();
+            this.connectionModel.setPaused(false);
+        }
+        this.logger.finest("resumed");
+    }
+
+    /**
+     * Setup this class from the global {@link org.hps.monitoring.model.ConfigurationModel} object.
+     *
+     * @param configurationModel the global @link org.hps.monitoring.model.ConfigurationModel} object
+     */
+    void setup(final ConfigurationModel configurationModel) {
+
         // Setup LCSim from the configuration.
-        setupLcsim(configurationModel);
+        this.setupLcsim(configurationModel);
 
         // Now setup the CompositeLoop.
-        setupLoop(configurationModel);
-    }
-
-    /**
-     * @param configurationModel
-     */
-    void setupLcsim(ConfigurationModel configurationModel) {
-        MonitoringApplication.logger.info("setting up lcsim");
+        this.setupLoop(configurationModel);
+    }
+
+    /**
+     * Setup LCSim event processing from the global {@link org.hps.monitoring.model.ConfigurationModel} object.
+     *
+     * @param configurationModel the global @link org.hps.monitoring.model.ConfigurationModel} object
+     */
+    private void setupLcsim(final ConfigurationModel configurationModel) {
+        this.logger.info("setting up lcsim");
 
         // Get steering resource or file as a String parameter.
         String steering = null;
-        SteeringType steeringType = configurationModel.getSteeringType();
+        final SteeringType steeringType = configurationModel.getSteeringType();
         if (steeringType.equals(SteeringType.FILE)) {
             steering = configurationModel.getSteeringFile();
         } else {
             steering = configurationModel.getSteeringResource();
         }
 
-        MonitoringApplication.logger.config("set steering " + steering + " with type " + (steeringType == SteeringType.RESOURCE ? "RESOURCE" : "FILE"));
+        this.logger.config("set steering " + steering + " with type "
+                + (steeringType == SteeringType.RESOURCE ? "RESOURCE" : "FILE"));
 
         try {
             // Create the job manager. A new conditions manager is instantiated from this call but not configured.
-            sessionState.jobManager = new JobManager();
+            this.sessionState.jobManager = new JobManager();
 
             // Add conditions listeners after new database conditions manager is initialized from the job manager.
-            DatabaseConditionsManager conditionsManager = DatabaseConditionsManager.getInstance();
-            for (ConditionsListener conditionsListener : sessionState.conditionsListeners) {
-                logger.config("adding conditions listener " + conditionsListener.getClass().getName());
+            final DatabaseConditionsManager conditionsManager = DatabaseConditionsManager.getInstance();
+            for (final ConditionsListener conditionsListener : this.sessionState.conditionsListeners) {
+                this.logger.config("adding conditions listener " + conditionsListener.getClass().getName());
                 conditionsManager.addConditionsListener(conditionsListener);
             }
 
             if (configurationModel.hasValidProperty(ConfigurationModel.DETECTOR_ALIAS_PROPERTY)) {
                 // Set a detector alias.
-                ConditionsReader.addAlias(configurationModel.getDetectorName(), "file://" + configurationModel.getDetectorAlias());
-                logger.config("using detector alias " + configurationModel.getDetectorAlias());
+                ConditionsReader.addAlias(configurationModel.getDetectorName(),
+                        "file://" + configurationModel.getDetectorAlias());
+                this.logger.config("using detector alias " + configurationModel.getDetectorAlias());
             }
 
             // Setup the event builder to translate from EVIO to LCIO.
             // This must happen before Driver setup so the builder's listeners are activated first!
-            createEventBuilder(configurationModel);
+            this.createEventBuilder(configurationModel);
 
             // Configure the job manager for the XML steering.
-            sessionState.jobManager.setPerformDryRun(true);
+            this.sessionState.jobManager.setPerformDryRun(true);
             if (steeringType == SteeringType.RESOURCE) {
-                setupSteeringResource(steering);
+                this.setupSteeringResource(steering);
             } else if (steeringType.equals(SteeringType.FILE)) {
-                setupSteeringFile(steering);
-            }
-
-            // Set conditions tag.
-            if (configurationModel.hasValidProperty(ConfigurationModel.CONDITIONS_TAG_PROPERTY) && !configurationModel.getConditionsTag().equals("")) {
-                logger.config("conditions tag is set to " + configurationModel.getConditionsTag());
+                this.setupSteeringFile(steering);
+            }
+
+            // Set conditions tag if applicable.
+            if (configurationModel.hasValidProperty(ConfigurationModel.CONDITIONS_TAG_PROPERTY)
+                    && !configurationModel.getConditionsTag().equals("")) {
+                this.logger.config("conditions tag is set to " + configurationModel.getConditionsTag());
             } else {
-                logger.config("conditions NOT using a tag");
+                this.logger.config("conditions NOT using a tag");
             }
 
             // Is there a user specified run number from the JobPanel?
             if (configurationModel.hasValidProperty(ConfigurationModel.USER_RUN_NUMBER_PROPERTY)) {
-                int userRunNumber = configurationModel.getUserRunNumber();
-                String detectorName = configurationModel.getDetectorName();
-                logger.config("setting user run number " + userRunNumber + " with detector " + detectorName);
+                final int userRunNumber = configurationModel.getUserRunNumber();
+                final String detectorName = configurationModel.getDetectorName();
+                this.logger.config("setting user run number " + userRunNumber + " with detector " + detectorName);
                 conditionsManager.setDetector(configurationModel.getDetectorName(), userRunNumber);
                 if (configurationModel.hasPropertyKey(ConfigurationModel.FREEZE_CONDITIONS_PROPERTY)) {
                     // Freeze the conditions system to ignore run numbers from the events.
-                    logger.config("user configured to freeze conditions system");
+                    this.logger.config("user configured to freeze conditions system");
                     conditionsManager.freeze();
                 } else {
                     // Allow run numbers to be picked up from the events.
-                    logger.config("user run number provided but conditions system is NOT frozen");
+                    this.logger.config("user run number provided but conditions system is NOT frozen");
                     conditionsManager.unfreeze();
                 }
             }
 
-            logger.info("lcsim setup was successful");
-
-        } catch (Throwable t) {
+            this.logger.info("lcsim setup was successful");
+
+        } catch (final Throwable t) {
             throw new RuntimeException("Error setting up LCSim.", t);
         }
     }
 
     /**
-     * Create the event builder for converting EVIO events to LCSim.
-     */
-    void createEventBuilder(ConfigurationModel configurationModel) {
-
-        // Get the class for the event builder.
-        String eventBuilderClassName = configurationModel.getEventBuilderClassName();
-
-        try {
-            // Create a new instance of the builder class.
-            sessionState.eventBuilder = (LCSimEventBuilder) Class.forName(eventBuilderClassName, true, Thread.currentThread().getContextClassLoader()).newInstance();
-        } catch (Exception e) {
-            throw new RuntimeException("Failed to create LCSimEventBuilder.", e);
-        }
-
-        // Add the builder as a listener so it is notified when conditions change.
-        ConditionsManager.defaultInstance().addConditionsListener(sessionState.eventBuilder);
-    }
-
-    /**
-     * Setup the loop from the global configuration.
-     * @param configurationModel The global configuration.
-     */
-    void setupLoop(ConfigurationModel configurationModel) {
-
-        logger.config("setting up record loop ...");
-        
-        CompositeLoopConfiguration loopConfig = new CompositeLoopConfiguration()
-            .setStopOnEndRun(configurationModel.getDisconnectOnEndRun())
-            .setStopOnErrors(configurationModel.getDisconnectOnError())
-            .setDataSourceType(configurationModel.getDataSourceType())
-            .setProcessingStage(configurationModel.getProcessingStage())
-            .setEtConnection(sessionState.connection)
-            .setFilePath(configurationModel.getDataSourcePath())
-            .setLCSimEventBuilder(sessionState.eventBuilder);
-        
-        logger.config("data source path is " + configurationModel.getDataSourcePath());
-        logger.config("data source type is " + configurationModel.getDataSourceType());
-
+     * Setup the {@link org.hps.record.composite.CompositeLoop} from the global
+     * {@link org.hps.monitoring.model.ConfigurationModel} object.
+     *
+     * @param configurationModel the global {@link org.hps.monitoring.model.ConfigurationModel} object
+     */
+    private void setupLoop(final ConfigurationModel configurationModel) {
+
+        this.logger.config("setting up record loop ...");
+
+        // Initialize the loop from the ConfigurationModel.
+        final CompositeLoopConfiguration loopConfig = new CompositeLoopConfiguration()
+                .setStopOnEndRun(configurationModel.getDisconnectOnEndRun())
+                .setStopOnErrors(configurationModel.getDisconnectOnError())
+                .setDataSourceType(configurationModel.getDataSourceType())
+                .setProcessingStage(configurationModel.getProcessingStage())
+                .setEtConnection(this.sessionState.connection).setFilePath(configurationModel.getDataSourcePath())
+                .setLCSimEventBuilder(this.sessionState.eventBuilder);
+
+        this.logger.config("data source path is " + configurationModel.getDataSourcePath());
+        this.logger.config("data source type is " + configurationModel.getDataSourceType());
+
+        // Set the max events.
         if (configurationModel.hasValidProperty(ConfigurationModel.MAX_EVENTS_PROPERTY)) {
-            long maxEvents = configurationModel.getMaxEvents();
+            final long maxEvents = configurationModel.getMaxEvents();
             if (maxEvents > 0L) {
                 loopConfig.setMaxRecords(maxEvents);
             }
         }
 
         // Add all Drivers from the JobManager.
-        for (Driver driver : sessionState.jobManager.getDriverExecList()) {
+        for (final Driver driver : this.sessionState.jobManager.getDriverExecList()) {
             loopConfig.add(driver);
-            logger.config("added Driver " + driver.getName());
+            this.logger.config("added Driver " + driver.getName());
         }
 
         // Using ET server?
         if (configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER)) {
 
             // ET system monitor.
-            logger.config("added EtSystemMonitor");
+            this.logger.config("added EtSystemMonitor");
             loopConfig.add(new EtSystemMonitor());
 
             // ET system strip charts.
-            logger.config("added EtSystemStripCharts");
+            this.logger.config("added EtSystemStripCharts");
             loopConfig.add(new EtSystemStripCharts());
         }
 
         // Add extra CompositeRecordProcessors to the loop config.
-        for (CompositeRecordProcessor processor : sessionState.processors) {
+        for (final CompositeRecordProcessor processor : this.sessionState.processors) {
             loopConfig.add(processor);
-            logger.config("added extra processor " + processor.getClass().getSimpleName());
+            this.logger.config("added extra processor " + processor.getClass().getSimpleName());
         }
 
         // Add extra Drivers to the loop config.
-        for (Driver driver : sessionState.drivers) {
+        for (final Driver driver : this.sessionState.drivers) {
             loopConfig.add(driver);
-            logger.config("added extra Driver " + driver.getName());
+            this.logger.config("added extra Driver " + driver.getName());
         }
 
         // Enable conditions system activation from EVIO event data in case the PRESTART is missed.
         loopConfig.add(new EvioDetectorConditionsProcessor(configurationModel.getDetectorName()));
-        logger.config("added EvioDetectorConditionsProcessor to job with detector " + configurationModel.getDetectorName());
+        this.logger.config("added EvioDetectorConditionsProcessor to job with detector "
+                + configurationModel.getDetectorName());
 
         // Create the CompositeLoop with the configuration.
-        sessionState.loop = new CompositeLoop(loopConfig);
-        
-        logger.config("record loop is setup");
-    }
-
-    /**
-     * Setup a steering file on disk.
-     * @param steering The steering file.
-     */
-    void setupSteeringFile(String steering) {
-        sessionState.jobManager.setup(new File(steering));
-    }
-
-    /**
-     * Setup a steering resource.
-     * @param steering The steering resource.
-     * @throws IOException if there is a problem setting up or accessing the resource.
-     */
-    void setupSteeringResource(String steering) throws IOException {
-        InputStream is = this.getClass().getClassLoader().getResourceAsStream(steering);
-        if (is == null)
+        this.sessionState.loop = new CompositeLoop(loopConfig);
+
+        this.logger.config("record loop is setup");
+    }
+
+    /**
+     * Setup XML steering from a file from disk.
+     *
+     * @param steering the steering file path
+     */
+    private void setupSteeringFile(final String steering) {
+        this.sessionState.jobManager.setup(new File(steering));
+    }
+
+    /**
+     * Setup XML steering from a jar resource.
+     *
+     * @param steering the steering resource
+     * @throws IOException if there is a problem accessing or setting up the resource
+     */
+    private void setupSteeringResource(final String steering) throws IOException {
+        final InputStream is = this.getClass().getClassLoader().getResourceAsStream(steering);
+        if (is == null) {
             throw new IOException("Steering resource is not accessible or does not exist.");
-        sessionState.jobManager.setup(is);
+        }
+        this.sessionState.jobManager.setup(is);
         is.close();
     }
 
+    /**
+     * Start event processing on a separate thread and also start the watchdog thread.
+     * <p>
+     * This method is called externally by the app to activate event processing after it is initialized and configured.
+     */
+    synchronized void start() {
+
+        this.logger.fine("event processing threads are starting");
+
+        // Start the event processing thread.
+        this.sessionState.processingThread = new EventProcessingThread(this.sessionState.loop);
+        this.sessionState.processingThread.start();
+
+        // Start the watch dog thread which will auto-disconnect when event processing is done.
+        this.sessionState.sessionWatchdogThread = new SessionWatchdogThread(this.sessionState.processingThread);
+        this.sessionState.sessionWatchdogThread.start();
+
+        this.logger.fine("started event processing threads");
+    }
+
+    /**
+     * Stop the current session, which will bring down the current ET client connection and activate end-of-job and
+     * end-of-run hooks on all registered event processors.
+     * <p>
+     * This method is called externally by the app to stop an event processing session e.g. from action event handling.
+     */
     synchronized void stop() {
 
         // Kill session watchdog thread.
-        killWatchdogThread();
-
-        // Wake up all ET stations to unblock the system and make sure secondary stations are detached.
-        if (usingEtServer()) {
-            wakeUpEtStations();   
-        }
-        
-        // Stop the event processing now that ET system is unblocked.
-        logger.fine("sending STOP command to loop ...");
-        sessionState.loop.execute(Command.STOP);
-        logger.fine("loop got command STOP");
-
-        // Cleanup the event processing thread since it was told to stop now.
+        this.killWatchdogThread();
+
+        // Wake up all ET stations to unblock the system and make sure stations are detached properly.
+        if (this.usingEtServer()) {
+            this.wakeUpEtStations();
+        }
+
+        // Stop the event processing now that ET system should be unblocked.
+        this.logger.finer("sending STOP command to loop ...");
+        this.sessionState.loop.execute(Command.STOP);
+        this.logger.finer("loop got STOP command");
+
+        this.logger.finer("processing thread is alive: " + this.sessionState.processingThread.isAlive());
+
         try {
-            logger.fine("waiting for event processing thread to end ...");
-            sessionState.processingThread.join();
-            logger.fine("event processing thread ended");   
-        } catch (InterruptedException e) {
+            // Give the event processing thread a chance to end cleanly.
+            this.logger.finer("waiting for event processing thread to end ...");
+            this.sessionState.processingThread.join(5000);
+            this.logger.finer("processing thread is alive: " + this.sessionState.processingThread.isAlive());
+            // this.logger.finer("event processing thread ended cleanly");
+        } catch (final InterruptedException e) {
             e.printStackTrace();
         }
 
+        try {
+            this.logger.finer("processing thread is alive: " + this.sessionState.processingThread.isAlive());
+            // In this case the thread needs to be interrupted and then joined.
+            this.logger.finer("interrupting event processing thread");
+            this.sessionState.processingThread.interrupt();
+            this.sessionState.processingThread.join();
+            this.logger.finer("event processing thread ended after interrupt");
+        } catch (final InterruptedException e) {
+            e.printStackTrace();
+        }
+
         // Notify of last error that occurred in event processing.
-        if (sessionState.loop.getLastError() != null) {
+        if (this.sessionState.loop.getLastError() != null) {
             // Log the error.
-            errorHandler.setError(sessionState.loop.getLastError()).log();
+            this.errorHandler.setError(this.sessionState.loop.getLastError()).log();
         }
 
         // Invalidate the loop.
-        sessionState.loop = null;
+        this.sessionState.loop = null;
 
         // Disconnect from the ET system.
-        disconnect();
-        
+        this.disconnect();
+
         // Invalidate the event processing object so it is unusable now.
-        invalidate();
-    }
-
-    /**
-     * Wake up all ET stations associated with event processing.
-     */
-    void wakeUpEtStations() {
-        if (sessionState.connection != null) {
-            logger.fine("waking up ET stations ...");
+        this.invalidate();
+    }
+
+    /**
+     * Return <code>true</code> if using an ET server.
+     *
+     * @return <code>true</code> if using an ET server in the current session
+     */
+    private boolean usingEtServer() {
+        return this.sessionState.usingEtServer;
+    }
+
+    /**
+     * Wake up all ET stations associated with the event processing.
+     */
+    private void wakeUpEtStations() {
+        if (this.sessionState.connection != null) {
+            this.logger.fine("waking up ET stations ...");
 
             // Wake up secondary ET stations.
-            for (EtStationThread station : sessionState.stations) {
-                
+            for (final EtStationThread station : this.sessionState.stations) {
+
                 // First unblock if in ET call.
                 station.wakeUp();
-                
+
                 // Next interrupt so that it will definitely stop.
                 station.interrupt();
             }
 
             // Wait for station threads to die after being woken up.
-            while (sessionState.stationThreadGroup.activeCount() != 0) {
-                logger.finest("waiting for station threads to die ...");
-                Object lock = new Object();
+            while (this.sessionState.stationThreadGroup.activeCount() != 0) {
+                this.logger.finest("waiting for station threads to die ...");
+                final Object lock = new Object();
                 synchronized (lock) {
                     try {
                         lock.wait(500);
-                    } catch (InterruptedException e) {
+                    } catch (final InterruptedException e) {
                         e.printStackTrace();
                     }
                 }
             }
-            
-            sessionState.stationThreadGroup.destroy();
-            
-            logger.finest("station threads destroyed");
+
+            this.sessionState.stationThreadGroup.destroy();
+
+            this.logger.finest("station threads destroyed");
 
             // Wake up the primary ET station doing the event processing.
-            logger.finest("waking up event processing station ...");
+            this.logger.finest("waking up event processing station ...");
             try {
-                sessionState.connection.getEtSystem().wakeUpAll(sessionState.connection.getEtStation());
-                logger.finest("event processing station was woken up");
+                this.sessionState.connection.getEtSystem().wakeUpAll(this.sessionState.connection.getEtStation());
+                this.logger.finest("event processing station was woken up");
             } catch (IOException | EtException | EtClosedException e) {
                 e.printStackTrace();
             }
 
-            logger.finest("ET stations all woken up");
-        }
-    }    
-
-    /**
-     * Start event processing on the event processing thread and start the watchdog thread.
-     */
-    synchronized void start() {
-
-        logger.fine("event processing threads are starting");
-
-        // Start the event processing thread.
-        sessionState.processingThread = new EventProcessingThread(sessionState.loop);
-        sessionState.processingThread.start();
-
-        // Start the watch dog thread which will auto-disconnect when event processing is done.
-        sessionState.sessionWatchdogThread = new SessionWatchdogThread(sessionState.processingThread);
-        sessionState.sessionWatchdogThread.start();
-
-        logger.fine("started event processing threads");
-    }
-
-    /**
-     * Notify the event processor to pause processing.
-     */
-    synchronized void pause() {
-        logger.finest("pausing");
-        if (!connectionModel.getPaused()) {
-            sessionState.loop.pause();
-            connectionModel.setPaused(true);
-        }
-        logger.finest("paused");
-    }
-
-    /**
-     * Get next event if in pause mode.
-     */
-    synchronized void next() {
-        logger.finest("getting next event");
-        if (connectionModel.getPaused()) {
-            connectionModel.setPaused(false);
-            sessionState.loop.execute(Command.GO_N, 1L, true);
-            connectionModel.setPaused(true);
-        }
-        logger.finest("got next event");
-    }
-
-    /**
-     * Resume processing events from pause mode.
-     */
-    synchronized void resume() {
-        logger.finest("resuming");
-        if (connectionModel.getPaused()) {
-            // Notify event processor to continue.
-            sessionState.loop.resume();
-            connectionModel.setPaused(false);
-        }
-        logger.finest("resumed");
-    }
-
-    /**
-     * Interrupt and join to the processing watchdog thread.
-     */
-    synchronized void killWatchdogThread() {
-        // Is the session watchdog thread not null?
-        if (sessionState.sessionWatchdogThread != null) {
-            logger.finest("killing watchdog thread ...");
-            // Is the thread still alive?
-            if (sessionState.sessionWatchdogThread.isAlive()) {
-                // Interrupt the thread which should cause it to stop.
-                sessionState.sessionWatchdogThread.interrupt();
-                try {
-                    // This should always work once the thread is interrupted.
-                    sessionState.sessionWatchdogThread.join();
-                } catch (InterruptedException e) {
-                    // This should never happen.
-                    e.printStackTrace();
-                }
-            }
-            // Set the thread object to null.
-            sessionState.sessionWatchdogThread = null;
-            logger.finest("watchdog thread killed");
-        }
-    }
-
-    /**
-     * Cleanup the ET connection.
-     */
-    synchronized void closeEtConnection() {
-        if (sessionState.connection != null) {
-            logger.fine("closing ET connection");
-            if (sessionState.connection.getEtSystem().alive()) {
-                logger.finest("cleaning up the connection ...");
-                sessionState.connection.cleanup();
-                logger.finest("connection cleanup successful");
-            }
-            sessionState.connection = null;
-            logger.fine("ET connection closed");
-        }
-    }
-
-    /**
-     * True if the processing thread is valid and active.
-     * @return True if processing thread is active.
-     */
-    boolean isActive() {
-        return sessionState.processingThread != null && sessionState.processingThread.isAlive();
-    }
-
-    /**
-     * Connect to the ET system using the current connection settings.
-     */
-    synchronized void connect() throws IOException {        
-        // Setup the network connection if using an ET server.
-        if (usingEtServer()) {
-            // Create a connection to the ET server.
-            try {
-                logger.fine("connecting to ET system ...");
-                
-                // Create the main ET system connection.
-                createEtConnection();
-
-                // Add an attachment that listens for DAQ configuration changes via physics SYNC events.
-                //createSyncStation();
-                
-                // Add an attachment which listens for EPICs events with scalar data.
-                //createEpicsStation();
-                
-                // Add an attachment that listens for PRESTART events.
-                //createPreStartStation();
-                
-            } catch (Exception e) {
-                throw new IOException(e);
-            }
-            
-            logger.fine("ET system is connected");
-        } else {
-            // This is when a direct file source is used and ET is not needed.
-            connectionModel.setConnectionStatus(ConnectionStatus.CONNECTED);
-        }
-        
-    }
-
-    /**
-     * True if using an ET server.
-     * @return True if using an ET server.
-     */
-    boolean usingEtServer() {
-        return sessionState.usingEtServer;
-    }
-
-    /**
-     * Create a connection to an ET system using current parameters from the GUI. 
-     */
-    synchronized void createEtConnection() {
-        // Setup connection to ET system.
-        sessionState.connection = EtSystemUtil.createEtConnection(configurationModel);
-
-        if (sessionState.connection != null) {
-            // Set status to connected as there is now a live ET connection.
-            connectionModel.setConnectionStatus(ConnectionStatus.CONNECTED);
-        } else {
-            errorHandler.setError(new RuntimeException("Failed to create ET connection.")).log().printStackTrace().raiseException();
-        }
-    }       
-    
-    /**
-     * Create the select array from event selection in ET stations.
-     * @return The select array.
-     */
-    static int[] createSelectArray() {
-        int select[] = new int[EtConstants.stationSelectInts];
-        Arrays.fill(select, -1);
-        return select;   
-    }    
-     
-    /**
-     * Create a station that listens for physics sync events
-     * containing DAQ configuration.
-     */
-    void createSyncStation() {
-        
-        // Sync events have bits 6 and 7 set.
-        int syncEventType = 0;
-        syncEventType = syncEventType ^ (1 << 6); 
-        syncEventType = syncEventType ^ (1 << 7);
-        int select[] = createSelectArray();
-        select[1] = syncEventType;
-        
-        createStationThread(
-                new SyncEventProcessor(),
-                "SYNC", 
-                1,
-                select);
-    }                                                                                                                                                                                                                                                                               
-    
-    /**
-     * Create a station that listens for PRESTART events
-     * to initialize the conditions system.
-     */
-    void createPreStartStation() {
-                
-        // Select only PRESTART events.
-        int[] select = createSelectArray();
-        select[0] = EvioEventConstants.PRESTART_EVENT_TAG;
-        
-        createStationThread(
-                new PreStartProcessor(configurationModel.getDetectorName()),
-                "PRESTART",
-                1,
-                select);
-    }
-    
-    /**
-     * Create a station that listens for EPICS control events (currently not activated).     
-     */
-    void createEpicsStation() {
-        
-        // Select only EPICS events.
-        int[] select = createSelectArray();
-        select[0] = EvioEventConstants.EPICS_EVENT_TAG;
-        
-        createStationThread(
-                new EpicsEtProcessor(),
-                "EPICS",
-                1,
-                select);
-    }
-    
-    /**
-     * Create an ET station thread.
-     * @param processor The event processor to run on the thread.
-     * @param nameAppend The string to append for naming this station.
-     * @param stationPosition The position of the station.
-     * @param select The event selection data array.
-     */
-    void createStationThread(EtEventProcessor processor, String nameAppend, int stationPosition, int[] select) {
-        EtStationThread stationThread = new EtStationThread(
-                processor,
-                sessionState.connection.getEtSystem(),
-                sessionState.connection.getEtStation().getName() + "_" + nameAppend,
-                stationPosition,
-                select);
-        new Thread(sessionState.stationThreadGroup, stationThread).start();
-        sessionState.stations.add(stationThread);
-        logger.config("started ET station " + nameAppend);
-        StringBuffer sb = new StringBuffer();
-        for (int word : select) {
-            sb.append(word + " ");
-        }
-        logger.config("station has select array: " + sb.toString());
-    }
-
-    /**
-     * Disconnect from the current ET session.
-     * @param status The connection status.
-     */
-    synchronized void disconnect() {
-                
-        // Cleanup the ET connection.
-        if (usingEtServer()) {
-            closeEtConnection();
-        }
-
-        // Change application state to disconnected.
-        connectionModel.setConnectionStatus(ConnectionStatus.DISCONNECTED);
-    }
-
-    /**
-     * This class notifies the application to disconnect if the event processing thread completes.
-     */
-    class SessionWatchdogThread extends Thread {
-
-        Thread processingThread;
-
-        SessionWatchdogThread(Thread processingThread) {
-            this.processingThread = processingThread;
-        }
-
-        public void run() {
-            try {
-                // This thread waits on the event processing thread to die.
-                processingThread.join();
-
-                // Activate a disconnect using the ActionEvent which is used by the disconnect button.
-                logger.finest("processing thread ended so automatic disconnect is happening");
-                application.actionPerformed(new ActionEvent(Thread.currentThread(), 0, Commands.DISCONNECT));
-
-            } catch (InterruptedException e) {
-                logger.finest("SessionWatchdogThread got interrupted");
-                // This happens when the thread is interrupted by the user pressing the disconnect button.
-            }
-        }
-    }
-    
-    /**
-     * Invalidate all 
-     */
-    void invalidate() {
-
-        application = null;
-        logger = null;
-        configurationModel = null;
-        connectionModel = null;
-        errorHandler = null;
-        
-        sessionState.conditionsListeners = null;
-        sessionState.drivers = null;        
-        sessionState.processors = null;        
-        sessionState.jobManager = null;
-        sessionState.eventBuilder = null;
-        sessionState.loop = null;
-        sessionState.processingThread = null;
-        sessionState.sessionWatchdogThread = null;
-        sessionState.stationThreadGroup = null;
-        sessionState.stations = null;
-        sessionState.connection = null;
-        
-        sessionState = null;
+            this.logger.finest("ET stations all woken up");
+        }
     }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/FieldPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/FieldPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/FieldPanel.java	Tue Apr 21 14:48:39 2015
@@ -3,81 +3,138 @@
 import javax.swing.BorderFactory;
 import javax.swing.JPanel;
 import javax.swing.JTextField;
+import javax.swing.SwingConstants;
 import javax.swing.SwingUtilities;
 import javax.swing.border.Border;
 import javax.swing.border.TitledBorder;
 
 /**
  * A panel with a label and a text field.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
+@SuppressWarnings("serial")
 class FieldPanel extends JPanel {
 
-    String fieldName;
-    String defaultValue;
-    JTextField field;
+    /**
+     * The default component border.
+     */
+    private static final Border DEFAULT_BORDER = BorderFactory.createLoweredBevelBorder();
 
-    static Border border = BorderFactory.createLoweredBevelBorder();
+    /**
+     * The component with the field value.
+     */
+    private final JTextField field;
 
-    FieldPanel(String fieldName, String defaultValue, int size, boolean editable) {
+    /**
+     * Class constructor.
+     *
+     * @param fieldName the name of the field for the label
+     * @param defaultValue the default value
+     * @param size the size of the field
+     * @param editable <code>true</code> if field is editable
+     */
+    protected FieldPanel(final String fieldName, final String defaultValue, final int size, final boolean editable) {
 
-        this.fieldName = fieldName;
-        this.defaultValue = defaultValue;
-
-        TitledBorder title = BorderFactory.createTitledBorder(border, fieldName);
+        final TitledBorder title = BorderFactory.createTitledBorder(DEFAULT_BORDER, fieldName);
         title.setTitleJustification(TitledBorder.LEFT);
 
-        field = new JTextField(defaultValue, size);
-        field.setHorizontalAlignment(JTextField.RIGHT);
-        field.setEditable(editable);
-        field.setBorder(title);
-        add(field);
+        this.field = new JTextField(defaultValue, size);
+        this.field.setHorizontalAlignment(SwingConstants.RIGHT);
+        this.field.setEditable(editable);
+        this.field.setBorder(title);
+        add(this.field);
     }
 
-    void setValue(final String value) {
+    /**
+     * Get a <code>Double</code> value from the field.
+     *
+     * @return the <code>Double</code> value
+     */
+    final Double getDoubleValue() {
+        return Double.parseDouble(getValue());
+    }
+
+    /**
+     * Get an <code>Integer</code> value from the field.
+     *
+     * @return the <code>Integer</code> value
+     */
+    final Integer getIntegerValue() {
+        return Integer.parseInt(getValue());
+    }
+
+    /**
+     * Get a <code>Long</code> value from the field.
+     *
+     * @return the <code>Long</code> value
+     */
+    final Long getLongValue() {
+        return Long.parseLong(getValue());
+    }
+
+    /**
+     * Get the <code>String</code> value from the field.
+     *
+     * @return the <code>String</code> value from the field
+     */
+    final String getValue() {
+        return this.field.getText();
+    }
+
+    /**
+     * Set the field value from a <code>double</code>.
+     *
+     * @param value the <code>double</code> value
+     */
+    final void setValue(final double value) {
         SwingUtilities.invokeLater(new Runnable() {
+            @Override
             public void run() {
-                field.setText(value);
+                FieldPanel.this.field.setText(new Double(value).toString());
             }
         });
     }
 
-    void setValue(final int value) {
+    /**
+     * Set the field value from an <code>int</code>.
+     *
+     * @param value the <code>int</code> value
+     */
+    final void setValue(final int value) {
         SwingUtilities.invokeLater(new Runnable() {
+            @Override
             public void run() {
-                field.setText(new Integer(value).toString());
+                FieldPanel.this.field.setText(new Integer(value).toString());
             }
         });
     }
 
-    void setValue(final double value) {
+    /**
+     * Set the field value from a <code>long</code>.
+     *
+     * @param value the <code>long</code> value
+     */
+    final void setValue(final long value) {
         SwingUtilities.invokeLater(new Runnable() {
+            @Override
             public void run() {
-                field.setText(new Double(value).toString());
+                FieldPanel.this.field.setText(new Long(value).toString());
             }
         });
     }
 
-    void setValue(final long value) {
+    /**
+     * Set the field value from a <code>String</code>.
+     *
+     * @param value the <code>String</code> value
+     */
+    void setValue(final String value) {
         SwingUtilities.invokeLater(new Runnable() {
+            @Override
             public void run() {
-                field.setText(new Long(value).toString());
+                FieldPanel.this.field.setText(value);
             }
         });
     }
-
-    String getValue() {
-        return field.getText();
-    }
-
-    Integer getIntegerValue() {
-        return Integer.parseInt(getValue());
-    }
-
-    Double getDoubleValue() {
-        return Double.parseDouble(getValue());
-    }
-
-    Long getLongValue() {
-        return Long.parseLong(getValue());
-    }
-}
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/JobSettingsPanel.java	Tue Apr 21 14:48:39 2015
@@ -28,400 +28,502 @@
 import org.jdom.input.SAXBuilder;
 
 /**
- * This is the GUI panel for setting job parameters. It is connected to the global configuration via
- * a {@link org.hps.monitoring.model.ConfigurationModel} object.
+ * This is the GUI panel for setting job parameters. It is connected to the global configuration settings via a
+ * {@link org.hps.monitoring.model.ConfigurationModel} object.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-// FIXME: Combo boxes should use explicit types.
-class JobSettingsPanel extends AbstractFieldsPanel {
-
-    private JComboBox<?> steeringResourcesComboBox;
-    private JTextField steeringFileField;
-    private JComboBox<?> steeringTypeComboBox;
-    private JComboBox<ProcessingStage> processingStageComboBox;
-    private JComboBox<String> detectorNameComboBox;
-    private JTextField detectorAliasField;
-    private JComboBox<String> conditionsTagComboBox;
-    private JComboBox<String> eventBuilderComboBox;
-    private JTextField userRunNumberField;
-    private JCheckBox freezeConditionsCheckBox;    
-    private JTextField maxEventsField;
-    private JCheckBox disconnectOnErrorCheckBox;
-    private JCheckBox disconnectOnEndRunCheckBox;    
-    private JComboBox<?> logLevelComboBox;
-    private JCheckBox logToFileCheckbox;
-    private JTextField logFileNameField;
-    private JTextField aidaServerNameField;
-           
-    // The package where steering resources must be located.
-    static final String STEERING_PACKAGE = "org/hps/steering/monitoring/";
-
-    // The available LogLevel settings as an array of strings.
-    static final String[] LOG_LEVELS = new String[] { 
-        Level.ALL.toString(), 
-        Level.FINEST.toString(), 
-        Level.FINER.toString(), 
-        Level.FINE.toString(), 
-        Level.CONFIG.toString(), 
-        Level.INFO.toString(), 
-        Level.WARNING.toString(), 
-        Level.SEVERE.toString(), 
-        Level.OFF.toString() 
-    };
+@SuppressWarnings("serial")
+final class JobSettingsPanel extends AbstractFieldsPanel {
+
+    /**
+     * This filter will accept only files called compact.xml which should be an LCSim detector description file.
+     */
+    static class CompactFileFilter extends FileFilter {
+
+        /**
+         * Class constructor.
+         */
+        public CompactFileFilter() {
+        }
+
+        /**
+         * Returns <code>true</code> if the path passes the filter.
+         *
+         * @return <code>true</code> if the path passes the filter
+         */
+        @Override
+        public boolean accept(final File pathname) {
+            return "compact.xml".equals(pathname.getName());
+        }
+
+        /**
+         * Get the description of the filter.
+         *
+         * @return the description of the filter
+         */
+        @Override
+        public String getDescription() {
+            return "Compact XML files";
+        }
+    }
+
+    /**
+     * Update the GUI from changes in the underlying model. The changes are distinguishable by their property name.
+     */
+    private class JobSettingsChangeListener implements PropertyChangeListener {
+
+        /**
+         * Handle {@link java.beans.PropertyChangeEvent} by updating the GUI from changes to the model.
+         *
+         * @param evt the {@link java.beans.PropertyChangeEvent} to handle
+         */
+        @Override
+        public void propertyChange(final PropertyChangeEvent evt) {
+            if (evt.getSource() instanceof ConfigurationModel) {
+                final Object value = evt.getNewValue();
+                final String property = evt.getPropertyName();
+                JobSettingsPanel.this.getConfigurationModel().removePropertyChangeListener(this);
+                try {
+                    if (property.equals(ConfigurationModel.DETECTOR_NAME_PROPERTY)) {
+                        JobSettingsPanel.this.detectorNameComboBox.setSelectedItem(value);
+                    } else if (property.equals(ConfigurationModel.DETECTOR_ALIAS_PROPERTY)) {
+                        JobSettingsPanel.this.detectorAliasField.setText((String) value);
+                    } else if (property.equals(ConfigurationModel.DISCONNECT_ON_ERROR_PROPERTY)) {
+                        JobSettingsPanel.this.disconnectOnErrorCheckBox.setSelected((Boolean) value);
+                    } else if (property.equals(ConfigurationModel.DISCONNECT_ON_END_RUN_PROPERTY)) {
+                        JobSettingsPanel.this.disconnectOnEndRunCheckBox.setSelected((Boolean) value);
+                    } else if (property.equals(ConfigurationModel.EVENT_BUILDER_PROPERTY)) {
+                        JobSettingsPanel.this.eventBuilderComboBox.setSelectedItem(value);
+                    } else if (property.equals(ConfigurationModel.LOG_FILE_NAME_PROPERTY)) {
+                        JobSettingsPanel.this.logFileNameField.setText((String) value);
+                    } else if (property.equals(ConfigurationModel.LOG_LEVEL_PROPERTY)) {
+                        JobSettingsPanel.this.logLevelComboBox.setSelectedItem(value.toString());
+                    } else if (property.equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) {
+                        JobSettingsPanel.this.logToFileCheckbox.setSelected((Boolean) value);
+                    } else if (property.equals(ConfigurationModel.STEERING_TYPE_PROPERTY)) {
+                        JobSettingsPanel.this.steeringTypeComboBox.setSelectedItem(value);
+                    } else if (property.equals(ConfigurationModel.STEERING_FILE_PROPERTY)) {
+                        if (value != null) {
+                            JobSettingsPanel.this.steeringFileField.setText((String) evt.getNewValue());
+                        } else {
+                            // A null value here is actually okay and means this field should be reset to have no value.
+                            JobSettingsPanel.this.steeringFileField.setText(null);
+                        }
+                    } else if (property.equals(ConfigurationModel.STEERING_RESOURCE_PROPERTY)) {
+                        JobSettingsPanel.this.steeringResourcesComboBox.setSelectedItem(value);
+                    } else if (property.equals(ConfigurationModel.USER_RUN_NUMBER_PROPERTY)) {
+                        if (value != null) {
+                            JobSettingsPanel.this.userRunNumberField.setText(Integer.toString((int) value));
+                        } else {
+                            JobSettingsPanel.this.userRunNumberField.setText(null);
+                        }
+                    } else if (property.equals(ConfigurationModel.FREEZE_CONDITIONS_PROPERTY)) {
+                        if (value != null) {
+                            JobSettingsPanel.this.freezeConditionsCheckBox.setSelected((Boolean) value);
+                        }
+                    } else if (property.equals(ConfigurationModel.MAX_EVENTS_PROPERTY)) {
+                        if (value != null) {
+                            JobSettingsPanel.this.maxEventsField.setText(value.toString());
+                        }
+                    } else if (property.equals(ConfigurationModel.PROCESSING_STAGE_PROPERTY)) {
+                        JobSettingsPanel.this.processingStageComboBox.setSelectedItem(evt.getNewValue());
+                    } else if (property.equals(ConfigurationModel.AIDA_SERVER_NAME_PROPERTY)) {
+                        JobSettingsPanel.this.aidaServerNameField.setText((String) evt.getNewValue());
+                    }
+                } finally {
+                    JobSettingsPanel.this.getConfigurationModel().addPropertyChangeListener(this);
+                }
+            }
+        }
+    }
+
+    /**
+     * The available LogLevel settings as an array of strings.
+     */
+    static final String[] LOG_LEVELS = new String[] {Level.ALL.toString(), Level.FINEST.toString(),
+            Level.FINER.toString(), Level.FINE.toString(), Level.CONFIG.toString(), Level.INFO.toString(),
+            Level.WARNING.toString(), Level.SEVERE.toString(), Level.OFF.toString()};
+
+    /**
+     * The package where steering resources must be located.
+     */
+    private static final String STEERING_PACKAGE = "org/hps/steering/monitoring/";
+
+    /**
+     * Field for name of remote AIDA server.
+     */
+    private final JTextField aidaServerNameField;
+
+    /**
+     * Combo box for selecting a conditions system tag.
+     */
+    private final JComboBox<String> conditionsTagComboBox;
+
+    /**
+     * Field setting a detector alias to a local file.
+     */
+    private final JTextField detectorAliasField;
+
+    /**
+     * Combo box for selecting a detector model.
+     */
+    private final JComboBox<String> detectorNameComboBox;
+
+    /**
+     * Check box for enabling disconnect on end run.
+     */
+    private final JCheckBox disconnectOnEndRunCheckBox;
+
+    /**
+     * Check box for enabling disconnect on event processing errors.
+     */
+    private final JCheckBox disconnectOnErrorCheckBox;
+
+    /**
+     * Combo box for selecting the event builder class.
+     */
+    private final JComboBox<String> eventBuilderComboBox;
+
+    /**
+     * Check box for freezing conditions system provided there is a user selected run number and detector.
+     */
+    private final JCheckBox freezeConditionsCheckBox;
+
+    /**
+     * Field for specifying an output log file.
+     */
+    private final JTextField logFileNameField;
+
+    /**
+     * Field for setting the log level.
+     */
+    private final JComboBox<?> logLevelComboBox;
+
+    /**
+     * Check box for enabling logging to a file.
+     */
+    private final JCheckBox logToFileCheckbox;
+
+    /**
+     * Field for setting the maximum number of events to process in the session.
+     */
+    private final JTextField maxEventsField;
+
+    /**
+     * Combo box for selecting the processing stage(s) to execute (ET, EVIO or LCIO).
+     */
+    private final JComboBox<ProcessingStage> processingStageComboBox;
+
+    /**
+     * Field for setting an XML steering file.
+     */
+    private final JTextField steeringFileField;
+
+    /**
+     * Combo box for selecting a steering file resource.
+     */
+    private final JComboBox<?> steeringResourcesComboBox;
+
+    /**
+     * Combo box for selecting between current file or resource for XML steering.
+     */
+    private final JComboBox<SteeringType> steeringTypeComboBox;
+
+    /**
+     * Field for setting a user run number for conditions system activation.
+     */
+    private final JTextField userRunNumberField;
 
     /**
      * Class constructor.
-     */
-    JobSettingsPanel(ConfigurationModel model) {
+     *
+     * @param model the current {@link org.hps.monitoring.application.model.ConfigurationModel} with global
+     *            configuration
+     */
+    @SuppressWarnings("unchecked")
+    JobSettingsPanel(final ConfigurationModel model) {
 
         super(new Insets(5, 3, 3, 5), true);
-        
-        setBorder(new EmptyBorder(10, 10, 10, 10));
-                
-        setLayout(new GridBagLayout());
-        
+
+        this.setBorder(new EmptyBorder(10, 10, 10, 10));
+
+        this.setLayout(new GridBagLayout());
+
         // Listen on changes to the configuration which will then be automatically pushed to the GUI.
         model.addPropertyChangeListener(this);
 
-        steeringResourcesComboBox = addComboBoxMultiline("Steering File Resource", ResourceUtil.findSteeringResources(STEERING_PACKAGE));
-        steeringResourcesComboBox.setActionCommand(Commands.STEERING_RESOURCE_CHANGED);
-        steeringResourcesComboBox.addActionListener(this);
-        
-        steeringFileField = addField("Steering File", 50);
-        steeringFileField.addPropertyChangeListener("value", this);
-        
-        JButton steeringFileButton = addButton("Select Steering File");
+        this.steeringResourcesComboBox = this.addComboBoxMultiline("Steering File Resource",
+                ResourceUtil.findSteeringResources(STEERING_PACKAGE));
+        this.steeringResourcesComboBox.setActionCommand(Commands.STEERING_RESOURCE_CHANGED);
+        this.steeringResourcesComboBox.addActionListener(this);
+
+        this.steeringFileField = this.addField("Steering File", 50);
+        this.steeringFileField.addPropertyChangeListener("value", this);
+
+        final JButton steeringFileButton = this.addButton("Select Steering File");
         steeringFileButton.setActionCommand(Commands.CHOOSE_STEERING_FILE);
         steeringFileButton.addActionListener(this);
-        
-        steeringTypeComboBox = addComboBox("Steering Type", new String[] { SteeringType.RESOURCE.name(), SteeringType.FILE.name() });
-        steeringTypeComboBox.setActionCommand(Commands.STEERING_TYPE_CHANGED);
-        steeringTypeComboBox.addActionListener(this);
-        
-        processingStageComboBox = new JComboBox<ProcessingStage>(ProcessingStage.values());
-        addComponent("Processing Stage", processingStageComboBox);
-        processingStageComboBox.setActionCommand(Commands.PROCESSING_STAGE_CHANGED);
-        processingStageComboBox.addActionListener(this);
-        
-        detectorNameComboBox = addComboBox("Detector Name", ResourceUtil.findDetectorNames());
-        detectorNameComboBox.setActionCommand(Commands.DETECTOR_NAME_CHANGED);
-        detectorNameComboBox.addActionListener(this);
-        
-        detectorAliasField = addField("Detector Resources Directory", "", 35, true);
-        detectorAliasField.setActionCommand(Commands.DETECTOR_ALIAS_CHANGED);
-        detectorAliasField.addPropertyChangeListener("value", this);
-        detectorAliasField.addActionListener(this);
-        
-        JButton compactXmlButton = addButton("Select Compact Xml File");
+
+        this.steeringTypeComboBox = this.addComboBox("Steering Type", SteeringType.values());
+        this.steeringTypeComboBox.setActionCommand(Commands.STEERING_TYPE_CHANGED);
+        this.steeringTypeComboBox.addActionListener(this);
+
+        this.processingStageComboBox = new JComboBox<ProcessingStage>(ProcessingStage.values());
+        this.addComponent("Processing Stage", this.processingStageComboBox);
+        this.processingStageComboBox.setActionCommand(Commands.PROCESSING_STAGE_CHANGED);
+        this.processingStageComboBox.addActionListener(this);
+
+        this.detectorNameComboBox = this.addComboBox("Detector Name", ResourceUtil.findDetectorNames());
+        this.detectorNameComboBox.setActionCommand(Commands.DETECTOR_NAME_CHANGED);
+        this.detectorNameComboBox.addActionListener(this);
+
+        this.detectorAliasField = this.addField("Detector Resources Directory", "", 35, true);
+        this.detectorAliasField.setActionCommand(Commands.DETECTOR_ALIAS_CHANGED);
+        this.detectorAliasField.addPropertyChangeListener("value", this);
+        this.detectorAliasField.addActionListener(this);
+
+        final JButton compactXmlButton = this.addButton("Select Compact Xml File");
         compactXmlButton.setActionCommand(Commands.CHOOSE_COMPACT_FILE);
         compactXmlButton.addActionListener(this);
 
-        userRunNumberField = addField("User Run Number", "", 10, true);
-        userRunNumberField.addPropertyChangeListener("value", this);
-        userRunNumberField.setActionCommand(Commands.USER_RUN_NUMBER_CHANGED);
-        userRunNumberField.setEnabled(true);
-        userRunNumberField.setEditable(true);
-                
-        conditionsTagComboBox = addComboBox("Conditions Tag", ResourceUtil.getConditionsTags());
-        conditionsTagComboBox.addItem("");
-        conditionsTagComboBox.setSelectedItem("");
-        conditionsTagComboBox.setActionCommand(Commands.CONDITIONS_TAG_CHANGED);
-        conditionsTagComboBox.addActionListener(this);
-        conditionsTagComboBox.setEditable(false);
-        conditionsTagComboBox.setEnabled(true);
-                
-        freezeConditionsCheckBox = addCheckBox("Freeze detector conditions", false, true);
-        freezeConditionsCheckBox.addActionListener(this);
-        freezeConditionsCheckBox.setActionCommand(Commands.FREEZE_CONDITIONS_CHANGED);
-        
-        maxEventsField = addField("Max Events", "-1", 10, false);
-        maxEventsField.addPropertyChangeListener("value", this);
-        maxEventsField.setEnabled(true);
-        maxEventsField.setEditable(true);
-        
-        eventBuilderComboBox = addComboBox("LCSim Event Builder", ResourceUtil.findEventBuilderClassNames());
-        eventBuilderComboBox.setSize(24, eventBuilderComboBox.getPreferredSize().height);
-        eventBuilderComboBox.setActionCommand(Commands.EVENT_BUILDER_CHANGED);
-        eventBuilderComboBox.addActionListener(this);
-        
-        disconnectOnErrorCheckBox = addCheckBox("Disconnect on error", false, true);
-        disconnectOnErrorCheckBox.setActionCommand(Commands.DISCONNECT_ON_ERROR_CHANGED);
-        disconnectOnErrorCheckBox.addActionListener(this);
-
-        disconnectOnEndRunCheckBox = addCheckBox("Disconnect on end run", false, true);
-        disconnectOnEndRunCheckBox.setActionCommand(Commands.DISCONNECT_ON_END_RUN_CHANGED);
-        disconnectOnEndRunCheckBox.addActionListener(this);
-
-        logLevelComboBox = addComboBox("Log Level", LOG_LEVELS);
-        logLevelComboBox.setActionCommand(Commands.LOG_LEVEL_CHANGED);
-        logLevelComboBox.addActionListener(this);
-                                            
-        logToFileCheckbox = addCheckBox("Log to File", false, false);
-        logToFileCheckbox.setEnabled(false);
-
-        logFileNameField = addField("Log File Name", "", "Full path to log file", 50, false);
-        logFileNameField.setEditable(false);
-        
-        aidaServerNameField = addField("AIDA Server Name", "", "Name of AIDA server", 30, true);
-        aidaServerNameField.addPropertyChangeListener("value", this);
-    }
-
+        this.userRunNumberField = this.addField("User Run Number", "", 10, true);
+        this.userRunNumberField.addPropertyChangeListener("value", this);
+        this.userRunNumberField.setActionCommand(Commands.USER_RUN_NUMBER_CHANGED);
+        this.userRunNumberField.setEnabled(true);
+        this.userRunNumberField.setEditable(true);
+
+        this.conditionsTagComboBox = this.addComboBox("Conditions Tag", ResourceUtil.getConditionsTags());
+        this.conditionsTagComboBox.addItem("");
+        this.conditionsTagComboBox.setSelectedItem("");
+        this.conditionsTagComboBox.setActionCommand(Commands.CONDITIONS_TAG_CHANGED);
+        this.conditionsTagComboBox.addActionListener(this);
+        this.conditionsTagComboBox.setEditable(false);
+        this.conditionsTagComboBox.setEnabled(true);
+
+        this.freezeConditionsCheckBox = this.addCheckBox("Freeze detector conditions", false, true);
+        this.freezeConditionsCheckBox.addActionListener(this);
+        this.freezeConditionsCheckBox.setActionCommand(Commands.FREEZE_CONDITIONS_CHANGED);
+
+        this.maxEventsField = this.addField("Max Events", "-1", 10, false);
+        this.maxEventsField.addPropertyChangeListener("value", this);
+        this.maxEventsField.setEnabled(true);
+        this.maxEventsField.setEditable(true);
+
+        this.eventBuilderComboBox = this.addComboBox("LCSim Event Builder", ResourceUtil.findEventBuilderClassNames());
+        this.eventBuilderComboBox.setSize(24, this.eventBuilderComboBox.getPreferredSize().height);
+        this.eventBuilderComboBox.setActionCommand(Commands.EVENT_BUILDER_CHANGED);
+        this.eventBuilderComboBox.addActionListener(this);
+
+        this.disconnectOnErrorCheckBox = this.addCheckBox("Disconnect on error", false, true);
+        this.disconnectOnErrorCheckBox.setActionCommand(Commands.DISCONNECT_ON_ERROR_CHANGED);
+        this.disconnectOnErrorCheckBox.addActionListener(this);
+
+        this.disconnectOnEndRunCheckBox = this.addCheckBox("Disconnect on end run", false, true);
+        this.disconnectOnEndRunCheckBox.setActionCommand(Commands.DISCONNECT_ON_END_RUN_CHANGED);
+        this.disconnectOnEndRunCheckBox.addActionListener(this);
+
+        this.logLevelComboBox = this.addComboBox("Log Level", LOG_LEVELS);
+        this.logLevelComboBox.setActionCommand(Commands.LOG_LEVEL_CHANGED);
+        this.logLevelComboBox.addActionListener(this);
+
+        this.logToFileCheckbox = this.addCheckBox("Log to File", false, false);
+        this.logToFileCheckbox.setEnabled(false);
+
+        this.logFileNameField = this.addField("Log File Name", "", "Full path to log file", 50, false);
+        this.logFileNameField.setEditable(false);
+
+        this.aidaServerNameField = this.addField("AIDA Server Name", "", "Name of AIDA server", 30, true);
+        this.aidaServerNameField.addPropertyChangeListener("value", this);
+    }
+
+    /**
+     * Handle {@link java.awt.event.ActionEvent} objects by pushing changes from the GUI into the model.
+     *
+     * @param event the {@link java.awt.event.ActionEvent} to handle
+     */
     @Override
-    public ConfigurationModel getConfigurationModel() {
-        return configurationModel;
-    }
-
-    /**
-     * Attaches the ActionListener from the main app to specific GUI components in this class.
-     */
-    public void addActionListener(ActionListener listener) {
-        steeringResourcesComboBox.addActionListener(listener);
-        freezeConditionsCheckBox.addActionListener(listener);
-    }
-
-    /**
-     * Choose an lcsim steering file.
-     */
-    void chooseSteeringFile() {
-        JFileChooser fc = new JFileChooser();
+    public void actionPerformed(final ActionEvent event) {
+        try {
+            this.getConfigurationModel().removePropertyChangeListener(this);
+            final String command = event.getActionCommand();
+            if (event.getActionCommand().equals(Commands.CHOOSE_STEERING_FILE)) {
+                this.chooseSteeringFile();
+            } else if (event.getActionCommand().equals(Commands.CHOOSE_COMPACT_FILE)) {
+                this.chooseCompactFile();
+            } else if (Commands.DISCONNECT_ON_ERROR_CHANGED.equals(command)) {
+                this.getConfigurationModel().setDisconnectOnError(this.disconnectOnErrorCheckBox.isSelected());
+            } else if (Commands.DISCONNECT_ON_END_RUN_CHANGED.equals(command)) {
+                this.getConfigurationModel().setDisconnectOnEndRun(this.disconnectOnEndRunCheckBox.isSelected());
+            } else if (Commands.STEERING_TYPE_CHANGED.equals(command)) {
+                this.getConfigurationModel().setSteeringType(this.steeringTypeComboBox.getSelectedItem().toString());
+            } else if (Commands.STEERING_RESOURCE_CHANGED.equals(command)) {
+                this.getConfigurationModel().setSteeringResource(
+                        this.steeringResourcesComboBox.getSelectedItem().toString());
+            } else if (Commands.LOG_LEVEL_CHANGED.equals(command)) {
+                this.getConfigurationModel().setLogLevel(Level.parse((String) this.logLevelComboBox.getSelectedItem()));
+            } else if (Commands.EVENT_BUILDER_CHANGED.equals(command)) {
+                this.getConfigurationModel().setEventBuilderClassName(
+                        (String) this.eventBuilderComboBox.getSelectedItem());
+            } else if (Commands.DETECTOR_NAME_CHANGED.equals(command)) {
+                try {
+                    this.getConfigurationModel().setDetectorName((String) this.detectorNameComboBox.getSelectedItem());
+                } catch (final Exception exception) {
+                    exception.printStackTrace();
+                }
+            } else if (Commands.FREEZE_CONDITIONS_CHANGED.equals(command)) {
+                if (this.getConfigurationModel().hasPropertyKey(ConfigurationModel.USER_RUN_NUMBER_PROPERTY)
+                        && this.getConfigurationModel().getUserRunNumber() != null) {
+                    this.getConfigurationModel().setFreezeConditions(this.freezeConditionsCheckBox.isSelected());
+                } else {
+                    throw new IllegalArgumentException(
+                            "Conditions system may only be frozen if there is a valid user run number.");
+                }
+            } else if (Commands.DETECTOR_ALIAS_CHANGED.equals(command)) {
+                this.getConfigurationModel().setDetectorName(this.detectorAliasField.getText());
+            } else if (Commands.CONDITIONS_TAG_CHANGED.equals(command)) {
+                this.getConfigurationModel().setConditionsTag((String) this.conditionsTagComboBox.getSelectedItem());
+            } else if (Commands.PROCESSING_STAGE_CHANGED.equals(command)) {
+                this.getConfigurationModel().setProcessingStage(
+                        this.processingStageComboBox.getSelectedItem().toString());
+            }
+        } finally {
+            this.getConfigurationModel().addPropertyChangeListener(this);
+        }
+    }
+
+    /**
+     * Attaches the ActionListener from the main application to specific GUI components in this class.
+     *
+     * @param the {@link java.awt.event.ActionListener} to register with the relevant components
+     */
+    @Override
+    public void addActionListener(final ActionListener listener) {
+        this.steeringResourcesComboBox.addActionListener(listener);
+        this.freezeConditionsCheckBox.addActionListener(listener);
+    }
+
+    /**
+     * Parse the LCSim XML steering file to see if it looks valid.
+     *
+     * @param file the input steering file
+     * @throws IOException if there is a basic IO problem like reading the file
+     * @throws JDOMException if the XML is not valid
+     */
+    private void checkSteeringFile(final File file) throws IOException, JDOMException {
+        final SAXBuilder builder = new SAXBuilder();
+        final Document document = builder.build(file);
+        final Element rootNode = document.getRootElement();
+        if (!"lcsim".equals(rootNode.getName())) {
+            throw new IOException("not an LCSim XML file: " + file.getPath());
+        }
+    }
+
+    /**
+     * Choose a compact XML file to override the one embedded in the jar as a resource.
+     */
+    private void chooseCompactFile() {
+        final JFileChooser fc = new JFileChooser();
+        fc.setDialogTitle("Choose a Compact XML File");
+        fc.setCurrentDirectory(new File("."));
+        fc.setFileFilter(new CompactFileFilter());
+        final int r = fc.showDialog(this, "Select ...");
+        if (r == JFileChooser.APPROVE_OPTION) {
+            final File file = fc.getSelectedFile();
+            this.getConfigurationModel().setDetectorAlias(file.getParent());
+        }
+    }
+
+    /**
+     * Choose an LCSim steering file.
+     */
+    private void chooseSteeringFile() {
+        final JFileChooser fc = new JFileChooser();
         fc.setDialogTitle("Choose an LCSim Steering File");
         fc.setCurrentDirectory(new File("."));
-        int r = fc.showDialog(this, "Select ...");
+        final int r = fc.showDialog(this, "Select ...");
         if (r == JFileChooser.APPROVE_OPTION) {
-            File file = fc.getSelectedFile();
+            final File file = fc.getSelectedFile();
             try {
-                checkSteeringFile(file);
-                configurationModel.setSteeringFile(file.getCanonicalPath());
-                configurationModel.setSteeringType(SteeringType.FILE);
+                this.checkSteeringFile(file);
+                this.getConfigurationModel().setSteeringFile(file.getCanonicalPath());
+                this.getConfigurationModel().setSteeringType(SteeringType.FILE.toString());
             } catch (IOException | JDOMException e) {
                 throw new RuntimeException("Error parsing the selected steering file.", e);
             }
         }
     }
-    
-    /**
-     * This filter will accept only files called compact.xml which
-     * should be an LCSim detector description file. 
-     */
-    static class CompactFileFilter extends FileFilter {
-
-        public CompactFileFilter() {            
-        }
-        
-        @Override
-        public boolean accept(File pathname) {
-            if (pathname.getName().equals("compact.xml")) {
-                return true;
-            } else {
-                return false;
-            }
-        }
-        
-        @Override
-        public String getDescription() {
-            return "Compact XML files";
-        }        
-    }
-    
-    
-    /**
-     * Choose a compact XML file to override the one embedded in the jar as a resource.
-     */
-    void chooseCompactFile() {
-        JFileChooser fc = new JFileChooser();
-        fc.setDialogTitle("Choose a Compact XML File");
-        fc.setCurrentDirectory(new File("."));
-        fc.setFileFilter(new CompactFileFilter());
-        int r = fc.showDialog(this, "Select ...");
-        if (r == JFileChooser.APPROVE_OPTION) {
-            File file = fc.getSelectedFile();
-            configurationModel.setDetectorAlias(file.getParent());
-        }
-    }    
-
-    /**
-     * Parse the lcsim steering file to see if it appears to be valid.
-     * @param file The input steering file.
-     * @throws IOException if there is a basic IO problem.
-     * @throws JDOMException if the XML is not valid.
-     */
-    private void checkSteeringFile(File file) throws IOException, JDOMException {
-        SAXBuilder builder = new SAXBuilder();
-        Document document = builder.build(file);
-        Element rootNode = document.getRootElement();
-        if (!rootNode.getName().equals("lcsim")) {
-            throw new IOException("Not an LCSim XML file: " + file.getPath());
-        }
-    }
-
+
+    /**
+     * Updates the configuration with changes from the GUI component values. The changes from the GUI are
+     * distinguishable by their component object.
+     */
     @Override
-    public void actionPerformed(ActionEvent event) {
+    public void propertyChange(final PropertyChangeEvent evt) {
+        this.getConfigurationModel().removePropertyChangeListener(this);
         try {
-            configurationModel.removePropertyChangeListener(this);
-            String command = event.getActionCommand();
-            if (event.getActionCommand().equals(Commands.CHOOSE_STEERING_FILE)) {
-                chooseSteeringFile();
-            } else if (event.getActionCommand().equals(Commands.CHOOSE_COMPACT_FILE)) {
-                chooseCompactFile();
-            } else if (Commands.DISCONNECT_ON_ERROR_CHANGED.equals(command)) {
-                configurationModel.setDisconnectOnError(disconnectOnErrorCheckBox.isSelected());
-            } else if (Commands.DISCONNECT_ON_END_RUN_CHANGED.equals(command)) {
-                configurationModel.setDisconnectOnEndRun(disconnectOnEndRunCheckBox.isSelected());
-            } else if (Commands.STEERING_TYPE_CHANGED.equals(command)) {
-                configurationModel.setSteeringType(SteeringType.valueOf((String) steeringTypeComboBox.getSelectedItem()));
-            } else if (Commands.STEERING_RESOURCE_CHANGED.equals(command)) {
-                configurationModel.setSteeringResource((String) steeringResourcesComboBox.getSelectedItem());
-            } else if (Commands.LOG_LEVEL_CHANGED.equals(command)) {
-                configurationModel.setLogLevel(Level.parse((String) logLevelComboBox.getSelectedItem()));
-            } else if (Commands.EVENT_BUILDER_CHANGED.equals(command)) {
-                configurationModel.setEventBuilderClassName((String) eventBuilderComboBox.getSelectedItem());
-            } else if (Commands.DETECTOR_NAME_CHANGED.equals(command)) {
-                try {
-                    configurationModel.setDetectorName((String) detectorNameComboBox.getSelectedItem());
-                } catch (Exception exception) {
-                    exception.printStackTrace();
-                }
-            } else if (Commands.FREEZE_CONDITIONS_CHANGED.equals(command)) {
-                if (configurationModel.hasPropertyKey(ConfigurationModel.USER_RUN_NUMBER_PROPERTY) && configurationModel.getUserRunNumber() != null) {
-                    configurationModel.setFreezeConditions(freezeConditionsCheckBox.isSelected());
-                } else {
-                    throw new IllegalArgumentException("Conditions system may only be frozen if there is a valid user run number.");
-                }
-            } else if (Commands.DETECTOR_ALIAS_CHANGED.equals(command)) {
-                configurationModel.setDetectorName(detectorAliasField.getText());
-            } else if (Commands.CONDITIONS_TAG_CHANGED.equals(command)) {
-                configurationModel.setConditionsTag((String) conditionsTagComboBox.getSelectedItem());
-            } else if (Commands.PROCESSING_STAGE_CHANGED.equals(command)) {
-                configurationModel.setProcessingStage((ProcessingStage) processingStageComboBox.getSelectedItem());
-            } 
-        } finally {
-            configurationModel.addPropertyChangeListener(this);
-        }
-    }
-
-    /**
-     * Updates the configuration with changes from the GUI component values. 
-     * The changes from the GUI are distinguishable by their component object.
-     */
-    @Override
-    public void propertyChange(PropertyChangeEvent evt) {                            
-        configurationModel.removePropertyChangeListener(this);
-        try {
-            Object source = evt.getSource();            
-            if (source == steeringFileField) {
-                configurationModel.setSteeringFile(steeringFileField.getText());
-            } else if (source == userRunNumberField) {
+            final Object source = evt.getSource();
+            if (source == this.steeringFileField) {
+                this.getConfigurationModel().setSteeringFile(this.steeringFileField.getText());
+            } else if (source == this.userRunNumberField) {
                 // Is run number being reset to null or empty?
-                if (userRunNumberField.getText() == null || userRunNumberField.getText().isEmpty()) {
+                if (this.userRunNumberField.getText() == null || this.userRunNumberField.getText().isEmpty()) {
                     // Update the model to null user run number and do not freeze the conditions system.
-                    configurationModel.setUserRunNumber(null);
-                    configurationModel.setFreezeConditions(false);
+                    this.getConfigurationModel().setUserRunNumber(null);
+                    this.getConfigurationModel().setFreezeConditions(false);
                 } else {
                     try {
                         // Parse the run number. Need to catch errors because it might be an invalid string.
-                        int userRunNumber = Integer.parseInt(userRunNumberField.getText());
-                        configurationModel.setUserRunNumber(userRunNumber);
-                        configurationModel.setFreezeConditions(true);
-                    } catch (NumberFormatException e) {
+                        final int userRunNumber = Integer.parseInt(this.userRunNumberField.getText());
+                        this.getConfigurationModel().setUserRunNumber(userRunNumber);
+                        this.getConfigurationModel().setFreezeConditions(true);
+                    } catch (final NumberFormatException e) {
                         System.out.println("bad number format so ignoring user run number " + evt.getNewValue());
-                        userRunNumberField.setText((String) evt.getOldValue());
-                        // throw new IllegalArgumentException("The value " + evt.getNewValue() + " is not a valid run number.");
+                        this.userRunNumberField.setText((String) evt.getOldValue());
+                        // throw new IllegalArgumentException("The value " + evt.getNewValue() +
+                        // " is not a valid run number.");
                     }
                 }
-            } else if (source == maxEventsField) {
-                configurationModel.setMaxEvents(Long.parseLong(maxEventsField.getText()));
-                //System.out.println("setMaxEvents - " + configurationModel.getMaxEvents());
-            } else if (source == aidaServerNameField) {
-                configurationModel.setAIDAServerName(aidaServerNameField.getText());
+            } else if (source == this.maxEventsField) {
+                this.getConfigurationModel().setMaxEvents(Long.parseLong(this.maxEventsField.getText()));
+                // System.out.println("setMaxEvents - " + configurationModel.getMaxEvents());
+            } else if (source == this.aidaServerNameField) {
+                this.getConfigurationModel().setAIDAServerName(this.aidaServerNameField.getText());
             } else if (evt.getPropertyName().equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) {
-                // This is getting the log to file prop change from the ConfigurationModel to update a read only component.
-                Boolean logToFile = (Boolean) evt.getNewValue();
+                // This is getting the log to file prop change from the ConfigurationModel to update a read only
+                // component.
+                final Boolean logToFile = (Boolean) evt.getNewValue();
                 if (logToFile != null) {
-                    logToFileCheckbox.setSelected(logToFile);
+                    this.logToFileCheckbox.setSelected(logToFile);
                 }
             } else if (evt.getPropertyName().equals(ConfigurationModel.LOG_FILE_NAME_PROPERTY)) {
-                // This is getting the log file name prop change from the ConfigurationModel to update a read only component.
-                String logFileName = (String) evt.getNewValue();
+                // This is getting the log file name prop change from the ConfigurationModel to update a read only
+                // component.
+                final String logFileName = (String) evt.getNewValue();
                 if (logFileName != null && logFileName.length() > 0) {
-                    logFileNameField.setText(logFileName);
+                    this.logFileNameField.setText(logFileName);
                 } else {
-                    logFileNameField.setText("");
+                    this.logFileNameField.setText("");
                 }
             } else if (evt.getPropertyName().equals(ConfigurationModel.CONDITIONS_TAG_PROPERTY)) {
-                conditionsTagComboBox.setSelectedItem(evt.getNewValue()); 
-            } 
+                this.conditionsTagComboBox.setSelectedItem(evt.getNewValue());
+            }
         } finally {
-            configurationModel.addPropertyChangeListener(this);
-        }
-    }
-
-    /**
-     * Update the GUI from changes in the underlying model. 
-     * The changes are distinguishable by their property name.
-     */
-    private class JobSettingsChangeListener implements PropertyChangeListener {
-        @Override
-        public void propertyChange(PropertyChangeEvent evt) {
-            if (evt.getSource() instanceof ConfigurationModel) {
-                Object value = evt.getNewValue();
-                String property = evt.getPropertyName();
-                configurationModel.removePropertyChangeListener(this);
-                try {
-                    if (property.equals(ConfigurationModel.DETECTOR_NAME_PROPERTY)) {
-                        detectorNameComboBox.setSelectedItem((String) value);
-                    } else if (property.equals(ConfigurationModel.DETECTOR_ALIAS_PROPERTY)) {
-                        detectorAliasField.setText((String) value);
-                    } else if (property.equals(ConfigurationModel.DISCONNECT_ON_ERROR_PROPERTY)) {
-                        disconnectOnErrorCheckBox.setSelected((Boolean) value);
-                    } else if (property.equals(ConfigurationModel.DISCONNECT_ON_END_RUN_PROPERTY)) {
-                        disconnectOnEndRunCheckBox.setSelected((Boolean) value);
-                    } else if (property.equals(ConfigurationModel.EVENT_BUILDER_PROPERTY)) {
-                        eventBuilderComboBox.setSelectedItem((String) value);
-                    } else if (property.equals(ConfigurationModel.LOG_FILE_NAME_PROPERTY)) {
-                        logFileNameField.setText((String) value);
-                    } else if (property.equals(ConfigurationModel.LOG_LEVEL_PROPERTY)) {
-                        logLevelComboBox.setSelectedItem(value.toString());
-                    } else if (property.equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) {
-                        logToFileCheckbox.setSelected((Boolean) value);
-                    } else if (property.equals(ConfigurationModel.STEERING_TYPE_PROPERTY)) {
-                        steeringTypeComboBox.setSelectedIndex(((SteeringType) value).ordinal());
-                    } else if (property.equals(ConfigurationModel.STEERING_FILE_PROPERTY)) {
-                        if (value != null) {
-                            steeringFileField.setText((String) evt.getNewValue());
-                        } else {
-                            // A null value here is actually okay and means this field should be reset to have no value.
-                            steeringFileField.setText(null);
-                        }
-                    } else if (property.equals(ConfigurationModel.STEERING_RESOURCE_PROPERTY)) {
-                        steeringResourcesComboBox.setSelectedItem(value);
-                    } else if (property.equals(ConfigurationModel.USER_RUN_NUMBER_PROPERTY)) {
-                        if (value != null) {
-                            userRunNumberField.setText(Integer.toString((int) value));
-                        } else {
-                            userRunNumberField.setText(null);
-                        }
-                    } else if (property.equals(ConfigurationModel.FREEZE_CONDITIONS_PROPERTY)) {
-                        if (value != null) {
-                            freezeConditionsCheckBox.setSelected((Boolean) value);
-                        }
-                    } else if (property.equals(ConfigurationModel.MAX_EVENTS_PROPERTY)) {
-                        if (value != null) {
-                            maxEventsField.setText(value.toString());
-                        }
-                    } else if (property.equals(ConfigurationModel.PROCESSING_STAGE_PROPERTY)) {
-                        processingStageComboBox.setSelectedItem(evt.getNewValue());
-                    } else if (property.equals(ConfigurationModel.AIDA_SERVER_NAME_PROPERTY)) {
-                        aidaServerNameField.setText((String) evt.getNewValue());
-                    }
-                } finally {
-                    configurationModel.addPropertyChangeListener(this);
-                }
-            }
-        }
-    }
-    
+            this.getConfigurationModel().addPropertyChangeListener(this);
+        }
+    }
+
+    /**
+     * Sets the {@link org.hps.monitoring.application.model.ConfigurationModel} for the component containing global
+     * configuration.
+     * <p>
+     * The job settings will be updated automatically if the model changes.
+     *
+     * @param the {@link org.hps.monitoring.application.model.ConfigurationModel} for the component
+     */
     @Override
-    public void setConfigurationModel(ConfigurationModel model) {
+    public void setConfigurationModel(final ConfigurationModel model) {
         super.setConfigurationModel(model);
         model.addPropertyChangeListener(new JobSettingsChangeListener());
     }
-}
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java	Tue Apr 21 14:48:39 2015
@@ -14,62 +14,74 @@
 
 /**
  * This is a combo box used to filter the log table messages by level.
- * @author Jeremy McCormick <[log in to unmask]>
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-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) {
-        
+@SuppressWarnings("serial")
+final class LogLevelFilterComboBox extends JComboBox<Level> implements ActionListener, PropertyChangeListener {
+
+    /**
+     * Available log levels.
+     */
+    private static final Level[] LOG_LEVELS = new Level[] { Level.ALL, Level.FINEST, Level.FINER, Level.FINE,
+            Level.CONFIG, Level.INFO, Level.WARNING, Level.SEVERE };
+
+    /**
+     * The {@link org.hps.monitoring.application.model.ConfigurationModel} providing the backing model.
+     */
+    private final ConfigurationModel configurationModel;
+
+    /**
+     * Class constructor.
+     *
+     * @param configurationModel the {@link org.hps.monitoring.application.model.ConfigurationModel} providing the
+     *            backing model
+     */
+    LogLevelFilterComboBox(final ConfigurationModel configurationModel) {
+
         configurationModel.addPropertyChangeListener(this);
-        this.configurationModel = configurationModel;       
-        
+        this.configurationModel = configurationModel;
+
         setModel(new DefaultComboBoxModel<Level>(LOG_LEVELS));
         setPrototypeDisplayValue(Level.WARNING);
-        setSelectedItem(Level.ALL);                       
+        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.
+     * The {@link java.awt.event.ActionEvent} handling, which is used to push changes to the global data model.
+     *
+     * @param event the {@link java.awt.event.ActionEvent} object
      */
-    public void actionPerformed(ActionEvent event) {
+    @Override
+    public void actionPerformed(final ActionEvent event) {
         if (event.getActionCommand().equals(Commands.LOG_LEVEL_FILTER_CHANGED)) {
-            configurationModel.removePropertyChangeListener(this);
-            try {                
-                configurationModel.setLogLevelFilter((Level) getSelectedItem());
+            this.configurationModel.removePropertyChangeListener(this);
+            try {
+                this.configurationModel.setLogLevelFilter((Level) getSelectedItem());
             } finally {
-                configurationModel.addPropertyChangeListener(this);
+                this.configurationModel.addPropertyChangeListener(this);
             }
         }
     }
-    
+
     /**
-     * Get change in log level filtering from the configuration model.     
+     * The {@link java.beans.PropertyChangeEvent} handling, which is used to get changes from the model into the GUI.
+     *
+     * @param event the {@link java.beans.PropertyChangeEvent} object to handle
      */
-    public void propertyChange(PropertyChangeEvent event) {
+    @Override
+    public void propertyChange(final PropertyChangeEvent event) {
         if (event.getPropertyName().equals(ConfigurationModel.LOG_LEVEL_FILTER_PROPERTY)) {
-            Level newLevel = (Level) event.getNewValue();
-            configurationModel.removePropertyChangeListener(this);
+            final Level newLevel = (Level) event.getNewValue();
+            this.configurationModel.removePropertyChangeListener(this);
             try {
                 setSelectedItem(newLevel);
             } finally {
-                configurationModel.addPropertyChangeListener(this);
+                this.configurationModel.addPropertyChangeListener(this);
             }
         }
     }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogPanel.java	Tue Apr 21 14:48:39 2015
@@ -15,46 +15,67 @@
 
 /**
  * This is a simple GUI component for the log table and its controls.
- * @author Jeremy McCormick <[log in to unmask]>
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class LogPanel extends JPanel{ 
+@SuppressWarnings("serial")
+final class LogPanel extends JPanel {
 
-    LogTable logTable;
-    LogLevelFilterComboBox logFilterComboBox;
-    
-    ConfigurationModel configurationModel;
-        
-    LogPanel(ConfigurationModel configurationModel, ActionListener listener) {
-        
-        this.configurationModel = configurationModel;
-        
+    /**
+     * The combo box for filtering which messages are currently showing in the table.
+     */
+    private final LogLevelFilterComboBox logFilterComboBox;
+
+    /**
+     * The table containing the log messages.
+     */
+    private final LogTable logTable;
+
+    /**
+     * Class constructor.
+     *
+     * @param configurationModel the {@link org.hps.monitoring.application.model.ConfigurationModel} providing the data
+     *            model
+     * @param listener an {@link java.awt.event.ActionListener} to register on certain components
+     */
+    LogPanel(final ConfigurationModel configurationModel, final ActionListener listener) {
+
         setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
-        
-        logTable = new LogTable(configurationModel);
-                        
-        JPanel controlsPanel = new JPanel();
+
+        this.logTable = new LogTable(configurationModel);
+
+        final JPanel controlsPanel = new JPanel();
         controlsPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5));
-        
-        JLabel label = new JLabel("Log Level Filter");
-        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 ...");
+
+        final JLabel label = new JLabel("Log Level Filter");
+        this.logFilterComboBox = new LogLevelFilterComboBox(configurationModel);
+        this.logFilterComboBox.setToolTipText("Messages below this level will be filtered out.");
+        controlsPanel.add(label);
+        controlsPanel.add(this.logFilterComboBox);
+
+        final JButton exportButton = new JButton("Export ...");
         exportButton.setActionCommand(Commands.SAVE_LOG_TABLE);
         exportButton.addActionListener(listener);
         controlsPanel.add(exportButton);
-        
-        JButton clearButton = new JButton("Clear");
+
+        final JButton clearButton = new JButton("Clear");
         clearButton.setActionCommand(Commands.CLEAR_LOG_TABLE);
         clearButton.addActionListener(listener);
         controlsPanel.add(clearButton);
-                              
-        JScrollPane tablePane = new JScrollPane(logTable);        
+
+        final JScrollPane tablePane = new JScrollPane(this.logTable);
         controlsPanel.setMaximumSize(new Dimension(tablePane.getPreferredSize().width, 200));
-                
+
         add(controlsPanel, BorderLayout.PAGE_START);
         add(tablePane, BorderLayout.PAGE_END);
-    }          
+    }
+
+    /**
+     * Get the log table.
+     *
+     * @return the log table
+     */
+    LogTable getLogTable() {
+        return this.logTable;
+    }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogTable.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogTable.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/LogTable.java	Tue Apr 21 14:48:39 2015
@@ -18,79 +18,144 @@
 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]>
+ * This is a simple {@link avax.swing.JTable} component for displaying log messages.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class LogTable extends JTable implements PropertyChangeListener {
-    
-    static final String[] COLUMN_NAMES = { "Date", "Level", "Message" };
-    
-    LogRecordModel model;
-    TableRowSorter<LogRecordModel> sorter;
-
-    Level filterLevel = Level.ALL;
-    
-    final static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-            
-    LogTable(ConfigurationModel configurationModel) {
-        configurationModel.addPropertyChangeListener(this);
-        model = new LogRecordModel();
-        setModel(model);
-        sorter = new TableRowSorter<LogRecordModel>(model);
-        sorter.setRowFilter(new LevelFilter());
-        getColumnModel().getColumn(0).setCellRenderer(new DateRenderer());        
-        setRowSorter(sorter);
-        getColumnModel().getColumn(0).setPreferredWidth(142);
-        getColumnModel().getColumn(0).setMaxWidth(142);
-        getColumnModel().getColumn(1).setPreferredWidth(60);
-        getColumnModel().getColumn(1).setMaxWidth(60);
-        setEnabled(false);
-    }
-        
+@SuppressWarnings("serial")
+final class LogTable extends JTable implements PropertyChangeListener {
+
+    /**
+     * The table cell renderer for displaying dates.
+     */
     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()) {
+        @Override
+        public void setValue(final Object value) {
+            setText(value == null ? "" : DATE_FORMAT.format(value));
+        }
+    }
+
+    /**
+     * A filter which determines what level of messages to display in the table.
+     */
+    private class LevelFilter extends RowFilter<LogRecordModel, Integer> {
+
+        /**
+         * Return <code>true</code> to display the entry.
+         *
+         * @param entry the table entry (model with a row ID)
+         */
+        @Override
+        public boolean include(final Entry<? extends LogRecordModel, ? extends Integer> entry) {
+            final LogRecordModel model = entry.getModel();
+            final LogRecord record = model.get(entry.getIdentifier());
+            if (record.getLevel().intValue() >= LogTable.this.filterLevel.intValue()) {
                 return true;
             }
             return false;
         }
     }
-   
-    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);
+
+    /**
+     * The table model implementation.
+     */
+    static class LogRecordModel extends AbstractTableModel {
+
+        /**
+         * The list of {@link java.util.logging.LogRecord} objects to display in the table.
+         */
+        private final List<LogRecord> records = new ArrayList<LogRecord>();
+
+        /**
+         * Add a new {@link java.util.logging.LogRecord} object to the table.
+         *
+         * @param record the new {@link java.util.logging.LogRecord} object
+         */
+        void add(final LogRecord record) {
+            this.records.add(record);
             fireTableDataChanged();
         }
 
-        @Override
-        public int getRowCount() {
-            return records.size();
-        }
-
+        /**
+         * Clear all the records from the table.
+         */
+        void clear() {
+            this.records.clear();
+            fireTableDataChanged();
+        }
+
+        /**
+         * Get a record by its index.
+         *
+         * @param rowIndex the row index
+         * @return the {@link java.util.logging.LogRecord} object
+         * @throws IndexOutOfBoundsException if rowIndex is invalid
+         */
+        private LogRecord get(final Integer rowIndex) {
+            return this.records.get(rowIndex);
+        }
+
+        /**
+         * Get the class of a column.
+         *
+         * @param columnIndex the column's index
+         * @return the column's class
+         */
+        @Override
+        public Class<?> getColumnClass(final int columnIndex) {
+            switch (columnIndex) {
+            case 0:
+                return Date.class;
+            case 1:
+                return Level.class;
+            case 2:
+                return String.class;
+            default:
+                return Object.class;
+            }
+        }
+
+        /**
+         * Get the number of columns.
+         *
+         * @return the number of columns
+         */
         @Override
         public int getColumnCount() {
             return COLUMN_NAMES.length;
         }
 
-        @Override
-        public Object getValueAt(int rowIndex, int columnIndex) {
-            LogRecord record = records.get(rowIndex);
+        /**
+         * Get the column name.
+         *
+         * @param columnIndex the column index
+         * @return the name of the column
+         */
+        @Override
+        public String getColumnName(final int columnIndex) {
+            return COLUMN_NAMES[columnIndex];
+        }
+
+        /**
+         * Get the number of rows.
+         *
+         * @return the number of rows
+         */
+        @Override
+        public int getRowCount() {
+            return this.records.size();
+        }
+
+        /**
+         * Get a cell value from the table.
+         *
+         * @param rowIndex the row index
+         * @param column the column index
+         * @return the cell value or <code>null</code> if does not exist (e.g. invalid column number)
+         */
+        @Override
+        public Object getValueAt(final int rowIndex, final int columnIndex) {
+            final LogRecord record = this.get(rowIndex);
             switch (columnIndex) {
             case 0:
                 return new Date(record.getMillis());
@@ -102,39 +167,70 @@
                 return null;
             }
         }
-
-        @Override
-        public Class<?> getColumnClass(int columnIndex) {
-            switch (columnIndex) {
-            case 0:
-                return Date.class;
-            case 1:
-                return Level.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();
-        }
+    }
+
+    /**
+     * The column names.
+     */
+    static final String[] COLUMN_NAMES = { "Date", "Level", "Message" };
+
+    /**
+     * Date formatting.
+     */
+    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+    /**
+     * The current filtering level.
+     */
+    private Level filterLevel = Level.ALL;
+
+    /**
+     * The backing table model.
+     */
+    private final LogRecordModel model;
+
+    /**
+     * The table sorer.
+     */
+    private final TableRowSorter<LogRecordModel> sorter;
+
+    /**
+     * Class constructor.
+     *
+     * @param configurationModel the {@link org.hps.monitoring.application.model.ConfigurationModel} for the application
+     */
+    LogTable(final ConfigurationModel configurationModel) {
+        configurationModel.addPropertyChangeListener(this);
+        this.model = new LogRecordModel();
+        setModel(this.model);
+        this.sorter = new TableRowSorter<LogRecordModel>(this.model);
+        this.sorter.setRowFilter(new LevelFilter());
+        getColumnModel().getColumn(0).setCellRenderer(new DateRenderer());
+        setRowSorter(this.sorter);
+        getColumnModel().getColumn(0).setPreferredWidth(142);
+        getColumnModel().getColumn(0).setMaxWidth(142);
+        getColumnModel().getColumn(1).setPreferredWidth(60);
+        getColumnModel().getColumn(1).setMaxWidth(60);
+        setEnabled(false);
+    }
+
+    /**
+     * Get the table model.
+     *
+     * @return the table model
+     */
+    LogRecordModel getLogRecordModel() {
+        return this.model;
     }
 
     /**
      * Get change in log level filtering from the configuration model.
      */
-    public void propertyChange(PropertyChangeEvent event) {
+    @Override
+    public void propertyChange(final PropertyChangeEvent event) {
         if (event.getPropertyName().equals(ConfigurationModel.LOG_LEVEL_FILTER_PROPERTY)) {
-            filterLevel = (Level) event.getNewValue();
-            model.fireTableDataChanged();
-        }
-    }    
+            this.filterLevel = (Level) event.getNewValue();
+            this.model.fireTableDataChanged();
+        }
+    }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Main.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Main.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/Main.java	Tue Apr 21 14:48:39 2015
@@ -12,42 +12,55 @@
 import org.hps.monitoring.application.model.Configuration;
 
 /**
- * This is the front-end for running the monitoring app via a {@link #main(String[])} method.
+ * This is the front-end for running the monitoring application via a {@link #main(String[])} method.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 public final class Main {
 
-    private Main() {
-    }
-    
-    public static void main(String[] args) {
-        
+    /**
+     * The main method which starts the monitoring application, which is how users should start the application.
+     *
+     * @param args the command line arguments
+     */
+    public static void main(final String[] args) {
+
         // Set up command line parsing.
-        Options options = new Options();
+        final Options options = new Options();
         options.addOption(new Option("h", false, "Print help."));
         options.addOption(new Option("c", true, "Load a properties file with configuration parameters."));
-        CommandLineParser parser = new PosixParser();
-        
+        final CommandLineParser parser = new PosixParser();
+
         // Parse command line arguments.
         final CommandLine cl;
         try {
             cl = parser.parse(options, args);
-        } catch (ParseException e) {
+        } catch (final ParseException e) {
             throw new RuntimeException("Problem parsing command line options.", e);
         }
 
         // Print help and exit.
         if (cl.hasOption("h")) {
-            HelpFormatter help = new HelpFormatter();
+            final HelpFormatter help = new HelpFormatter();
             help.printHelp(" ", options);
             System.exit(1);
         }
-        
+
         // Load the connection settings.
         Configuration configuration = null;
         if (cl.hasOption("c")) {
             configuration = new Configuration(new File(cl.getOptionValue("c")));
-        }        
-        
+        }
+
         MonitoringApplication.create(configuration);
-    }    
-}
+    }
+
+    /**
+     * Class constructor, which should not be used.
+     * <p>
+     * Call the {@link #main(String[])} method instead.
+     */
+    private Main() {
+        throw new UnsupportedOperationException("Do not instantiate this class.");
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MenuBar.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MenuBar.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MenuBar.java	Tue Apr 21 14:48:39 2015
@@ -18,116 +18,173 @@
 
 /**
  * This is the primary menu bar for the monitoring application.
- * 
- * @author Jeremy McCormick <[log in to unmask]>
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 @SuppressWarnings("serial")
-class MenuBar extends JMenuBar implements PropertyChangeListener, ActionListener {
-    
-    ConfigurationModel configurationModel;
-    
-    JMenuItem closeFileItem;
-    JMenuItem openFileItem;    
-    JMenu settingsMenu;
-    JMenuItem logItem;
-    JMenuItem serverItem;
-    JMenu recentFilesMenu;    
-    
-    class RecentFileItem extends JMenuItem {
-        
-        String path;        
-        
-        RecentFileItem(String path, int mnemonic) {
-            setText((mnemonic - KeyEvent.VK_0) + " " + path);
+final class MenuBar extends JMenuBar implements PropertyChangeListener, ActionListener {
+
+    /**
+     * The implementation of {@link javax.swing.JMenuItem} for recent file items.
+     */
+    private class RecentFileItem extends JMenuItem {
+
+        /**
+         * The recent file's path.
+         */
+        private final String path;
+
+        /**
+         * Class constructor with file's path and its numerical mnemonic (0-9).
+         *
+         * @param path the path
+         * @param mnemonic the item's mnemonic shortcut (0-9)
+         */
+        RecentFileItem(final String path, final int mnemonic) {
+            setText(mnemonic - KeyEvent.VK_0 + " " + path);
             setMnemonic(mnemonic);
             this.path = path;
         }
-        
-        String getPath() {
-            return path;
-        }        
-    }
-                   
-    MenuBar(ConfigurationModel configurationModel, ConnectionStatusModel connectionModel, ActionListener listener) {
-         
-        this.configurationModel = configurationModel;        
+
+        /**
+         * Get the file path of the item.
+         *
+         * @return the file path
+         */
+        private String getPath() {
+            return this.path;
+        }
+    }
+
+    /**
+     * Starting mnemonic for recent files (this is equivalent to '0').
+     */
+    private static final int RECENT_FILES_START_INDEX = 48;
+
+    /**
+     * Menu item for closing a file source.
+     */
+    private final JMenuItem closeFileItem;
+
+    /**
+     * The application backing model.
+     */
+    private final ConfigurationModel configurationModel;
+
+    /**
+     * Menu item for logging to a file.
+     */
+    private final JMenuItem logItem;
+
+    /**
+     * Menu item for opening a file data source.
+     */
+    private final JMenuItem openFileItem;
+
+    /**
+     * Menu with list of recent files (10 max).
+     */
+    private final JMenu recentFilesMenu;
+
+    /**
+     * Menu item for activating the remote AIDA server.
+     */
+    private final JMenuItem serverItem;
+
+    /**
+     * Menu item for opening the settings dialog window.
+     */
+    private final JMenu settingsMenu;
+
+    /**
+     * Class constructor.
+     *
+     * @param configurationModel the {@link org.hps.monitoring.application.model.ConfigurationModel} providing the model
+     * @param connectionModel the {@link org.hps.monitoring.application.model.ConnectionStatusModel} providing
+     *            connection status
+     * @param listener an {@link ava.awt.event.ActionListener} which is assigned to certain components
+     */
+    MenuBar(final ConfigurationModel configurationModel, final ConnectionStatusModel connectionModel,
+            final ActionListener listener) {
+
+        this.configurationModel = configurationModel;
         this.configurationModel.addPropertyChangeListener(this);
-        
+
         // Need to listen for connection status changes.
-        connectionModel.addPropertyChangeListener(this);  
-        
-        JMenu fileMenu = new JMenu("File");
+        connectionModel.addPropertyChangeListener(this);
+
+        final JMenu fileMenu = new JMenu("File");
         fileMenu.setMnemonic(KeyEvent.VK_F);
         add(fileMenu);
-        
-        openFileItem = new JMenuItem("Open File ...");
-        openFileItem.setMnemonic(KeyEvent.VK_P);
-        openFileItem.setActionCommand(Commands.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(Commands.CLOSE_FILE);
-        closeFileItem.addActionListener(listener);
-        closeFileItem.setToolTipText("Close the current file data source");
-        fileMenu.add(closeFileItem);
-                                      
-        recentFilesMenu = new JMenu("RecentFiles");
-        recentFilesMenu.setMnemonic(KeyEvent.VK_R);
-        recentFilesMenu.setToolTipText("List of recent data files");
-        JMenuItem noRecentFilesItem = new JMenuItem("No recent files");
+
+        this.openFileItem = new JMenuItem("Open File ...");
+        this.openFileItem.setMnemonic(KeyEvent.VK_P);
+        this.openFileItem.setActionCommand(Commands.OPEN_FILE);
+        this.openFileItem.addActionListener(listener);
+        this.openFileItem.setToolTipText("Open an EVIO or LCIO data file");
+        fileMenu.add(this.openFileItem);
+
+        this.closeFileItem = new JMenuItem("Close File");
+        this.closeFileItem.setMnemonic(KeyEvent.VK_C);
+        this.closeFileItem.setActionCommand(Commands.CLOSE_FILE);
+        this.closeFileItem.addActionListener(listener);
+        this.closeFileItem.setToolTipText("Close the current file data source");
+        fileMenu.add(this.closeFileItem);
+
+        this.recentFilesMenu = new JMenu("Recent Files");
+        this.recentFilesMenu.setMnemonic(KeyEvent.VK_R);
+        this.recentFilesMenu.setToolTipText("List of recent data files");
+        final JMenuItem noRecentFilesItem = new JMenuItem("No recent files");
         noRecentFilesItem.setEnabled(false);
-        recentFilesMenu.add(noRecentFilesItem);
-        fileMenu.add(recentFilesMenu);
-        
+        this.recentFilesMenu.add(noRecentFilesItem);
+        fileMenu.add(this.recentFilesMenu);
+
         fileMenu.addSeparator();
-        
-        JMenuItem exitItem = new JMenuItem("Exit");
+
+        final JMenuItem exitItem = new JMenuItem("Exit");
         exitItem.setMnemonic(KeyEvent.VK_X);
         exitItem.setActionCommand(Commands.EXIT);
         exitItem.addActionListener(listener);
         exitItem.setToolTipText("Exit from the application");
         fileMenu.add(exitItem);
-                
-        settingsMenu = new JMenu("Settings");
-        settingsMenu.setMnemonic(KeyEvent.VK_S);
-        add(settingsMenu);
-        
-        JMenuItem settingsItem = new JMenuItem("Open Settings Window ...");
+
+        this.settingsMenu = new JMenu("Settings");
+        this.settingsMenu.setMnemonic(KeyEvent.VK_S);
+        add(this.settingsMenu);
+
+        final JMenuItem settingsItem = new JMenuItem("Open Settings Window ...");
         settingsItem.setMnemonic(KeyEvent.VK_O);
         settingsItem.setActionCommand(Commands.SHOW_SETTINGS);
         settingsItem.addActionListener(listener);
         settingsItem.setToolTipText("Show settings dialog");
-        settingsMenu.add(settingsItem);
-        
-        JMenuItem loadConfigItem = new JMenuItem("Load Settings ...");
+        this.settingsMenu.add(settingsItem);
+
+        final JMenuItem loadConfigItem = new JMenuItem("Load Settings ...");
         loadConfigItem.addActionListener(listener);
         loadConfigItem.setMnemonic(KeyEvent.VK_L);
         loadConfigItem.setActionCommand(Commands.LOAD_SETTINGS);
         loadConfigItem.setToolTipText("Load settings from a properties file");
-        settingsMenu.add(loadConfigItem);
-
-        JMenuItem saveConfigItem = new JMenuItem("Save Settings ...");
+        this.settingsMenu.add(loadConfigItem);
+
+        final JMenuItem saveConfigItem = new JMenuItem("Save Settings ...");
         saveConfigItem.addActionListener(listener);
         saveConfigItem.setMnemonic(KeyEvent.VK_S);
         saveConfigItem.setActionCommand(Commands.SAVE_SETTINGS);
         saveConfigItem.setToolTipText("Save configuration to a properties file");
-        settingsMenu.add(saveConfigItem);
-        
-        JMenuItem defaultSettingsItem = new JMenuItem("Load Default Settings");
+        this.settingsMenu.add(saveConfigItem);
+
+        final JMenuItem defaultSettingsItem = new JMenuItem("Load Default Settings");
         defaultSettingsItem.addActionListener(listener);
         defaultSettingsItem.setMnemonic(KeyEvent.VK_D);
         defaultSettingsItem.setActionCommand(Commands.LOAD_DEFAULT_SETTINGS);
         defaultSettingsItem.setToolTipText("Load the default settings");
-        settingsMenu.add(defaultSettingsItem);
-        
-        JMenu plotsMenu = new JMenu("Plots");
+        this.settingsMenu.add(defaultSettingsItem);
+
+        final JMenu plotsMenu = new JMenu("Plots");
         plotsMenu.setMnemonic(KeyEvent.VK_P);
         add(plotsMenu);
-        
-        JMenuItem savePlotsItem = new JMenuItem("Save plots ...");
+
+        final JMenuItem savePlotsItem = new JMenuItem("Save plots ...");
         savePlotsItem.setMnemonic(KeyEvent.VK_S);
         savePlotsItem.setActionCommand(Commands.SAVE_PLOTS);
         savePlotsItem.addActionListener(listener);
@@ -135,140 +192,162 @@
         savePlotsItem.setToolTipText("Save all plots to a file");
         plotsMenu.add(savePlotsItem);
 
-        JMenuItem clearPlotsItem = new JMenuItem("Clear plots");
+        final JMenuItem clearPlotsItem = new JMenuItem("Clear plots");
         clearPlotsItem.setMnemonic(KeyEvent.VK_C);
         clearPlotsItem.setActionCommand(Commands.CLEAR_PLOTS);
         clearPlotsItem.addActionListener(listener);
         clearPlotsItem.setEnabled(true);
         clearPlotsItem.setToolTipText("Clear the AIDA plots");
         plotsMenu.add(clearPlotsItem);
-        
-        JMenu toolsMenu = new JMenu("Tools");
+
+        final JMenu toolsMenu = new JMenu("Tools");
         toolsMenu.setMnemonic(KeyEvent.VK_T);
         add(toolsMenu);
-        
-        JMenuItem screenshotItem = new JMenuItem("Save Screenshot ...");
+
+        final JMenuItem screenshotItem = new JMenuItem("Save Screenshot ...");
         screenshotItem.setMnemonic(KeyEvent.VK_S);
         screenshotItem.setActionCommand(Commands.SAVE_SCREENSHOT);
         screenshotItem.addActionListener(listener);
         screenshotItem.setEnabled(true);
         screenshotItem.setToolTipText("Save a screenshot to a graphics file");
         toolsMenu.add(screenshotItem);
-        
-        logItem = new JMenuItem("Log to File ...");
-        logItem.setMnemonic(KeyEvent.VK_L);
-        logItem.setActionCommand(Commands.LOG_TO_FILE);
-        logItem.addActionListener(listener);
-        logItem.setEnabled(true);
-        logItem.setToolTipText("Redirect System.out to a file instead of terminal");
-        toolsMenu.add(logItem);
-        
-        serverItem = new JMenuItem("Start AIDA Server ...");
-        serverItem.setMnemonic(KeyEvent.VK_A);
-        serverItem.setActionCommand(Commands.START_AIDA_SERVER);
-        serverItem.setEnabled(true);
-        serverItem.setToolTipText("Start AIDA RMI Server");
-        serverItem.addActionListener(listener);
-        toolsMenu.add(serverItem);
-        
-        JMenu windowMenu = new JMenu("Window");
+
+        this.logItem = new JMenuItem("Log to File ...");
+        this.logItem.setMnemonic(KeyEvent.VK_L);
+        this.logItem.setActionCommand(Commands.LOG_TO_FILE);
+        this.logItem.addActionListener(listener);
+        this.logItem.setEnabled(true);
+        this.logItem.setToolTipText("Redirect System.out to a file instead of terminal");
+        toolsMenu.add(this.logItem);
+
+        this.serverItem = new JMenuItem("Start AIDA Server ...");
+        this.serverItem.setMnemonic(KeyEvent.VK_A);
+        this.serverItem.setActionCommand(Commands.START_AIDA_SERVER);
+        this.serverItem.setEnabled(true);
+        this.serverItem.setToolTipText("Start AIDA RMI Server");
+        this.serverItem.addActionListener(listener);
+        toolsMenu.add(this.serverItem);
+
+        final JMenu windowMenu = new JMenu("Window");
         windowMenu.setMnemonic(KeyEvent.VK_W);
         add(windowMenu);
-        
-        JMenuItem maximizeItem = new JMenuItem("Maximize");
+
+        final JMenuItem maximizeItem = new JMenuItem("Maximize");
         maximizeItem.setMnemonic(KeyEvent.VK_M);
         maximizeItem.setActionCommand(Commands.MAXIMIZE_WINDOW);
         maximizeItem.addActionListener(listener);
         maximizeItem.setEnabled(true);
         maximizeItem.setToolTipText("Maximize the application window");
         windowMenu.add(maximizeItem);
-        
-        JMenuItem minimizeItem = new JMenuItem("Minimize");
+
+        final JMenuItem minimizeItem = new JMenuItem("Minimize");
         minimizeItem.setMnemonic(KeyEvent.VK_I);
         minimizeItem.setActionCommand(Commands.MINIMIZE_WINDOW);
         minimizeItem.addActionListener(listener);
         minimizeItem.setEnabled(true);
         minimizeItem.setToolTipText("Minimize the application window");
         windowMenu.add(minimizeItem);
-        
-        JMenuItem defaultsItem = new JMenuItem("Restore Defaults");
+
+        final JMenuItem defaultsItem = new JMenuItem("Restore Defaults");
         defaultsItem.setMnemonic(KeyEvent.VK_D);
         defaultsItem.setActionCommand(Commands.DEFAULT_WINDOW);
         defaultsItem.addActionListener(listener);
         defaultsItem.setEnabled(true);
         defaultsItem.setToolTipText("Restore the window defaults");
-        windowMenu.add(defaultsItem);               
-    }
-
+        windowMenu.add(defaultsItem);
+    }
+
+    /**
+     * The {@link java.awt.event.ActionEvent} handling which sets GUI values from the model.
+     *
+     * @param the {@link java.awt.event.ActionEvent} to handle
+     */
     @Override
-    public void propertyChange(PropertyChangeEvent evt) {
-        configurationModel.removePropertyChangeListener(this);        
-        try {            
+    public void actionPerformed(final ActionEvent e) {
+        if (e.getActionCommand().equals(Commands.DATA_SOURCE_CHANGED)) {
+            if (!this.configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER)) {
+                this.closeFileItem.setEnabled(true);
+            } else {
+                this.closeFileItem.setEnabled(false);
+            }
+        }
+    }
+
+    /**
+     * The {@link java.beans.PropertyChangeEvent} handling which sets GUI values from the model.
+     *
+     * @param the {@link java.beans.PropertyChangeEvent} to handle
+     */
+    @Override
+    public void propertyChange(final PropertyChangeEvent evt) {
+        this.configurationModel.removePropertyChangeListener(this);
+        try {
             if (evt.getPropertyName().equals(ConnectionStatusModel.CONNECTION_STATUS_PROPERTY)) {
-                ConnectionStatus status = (ConnectionStatus) evt.getNewValue();
-                boolean connected = status.equals(ConnectionStatus.CONNECTED);
-                closeFileItem.setEnabled(!connected);
-                openFileItem.setEnabled(!connected);
+                final ConnectionStatus status = (ConnectionStatus) evt.getNewValue();
+                final boolean connected = status.equals(ConnectionStatus.CONNECTED);
+                this.closeFileItem.setEnabled(!connected);
+                this.openFileItem.setEnabled(!connected);
             } else if (evt.getPropertyName().equals(ConfigurationModel.LOG_TO_FILE_PROPERTY)) {
-                Boolean logToFile = (Boolean) evt.getNewValue();
-                if (logToFile == true) {
+                final Boolean logToFile = (Boolean) evt.getNewValue();
+                if (logToFile) {
                     // Toggle log item state to send to terminal.
-                    logItem.setText("Log to Terminal ...");
-                    logItem.setActionCommand(Commands.LOG_TO_TERMINAL);
-                    logItem.setToolTipText("Log messages to the terminal");
+                    this.logItem.setText("Log to Terminal ...");
+                    this.logItem.setActionCommand(Commands.LOG_TO_TERMINAL);
+                    this.logItem.setToolTipText("Log messages to the terminal");
                 } else {
                     // Toggle log item state to send to file.
-                    logItem.setText("Log to File ...");
-                    logItem.setActionCommand(Commands.LOG_TO_FILE);
-                    logItem.setToolTipText("Log messages to a file");
+                    this.logItem.setText("Log to File ...");
+                    this.logItem.setActionCommand(Commands.LOG_TO_FILE);
+                    this.logItem.setToolTipText("Log messages to a file");
                 }
             } else if (evt.getPropertyName().equals(ConfigurationModel.RECENT_FILES_PROPERTY)) {
-                setRecentFiles(configurationModel.getRecentFilesList());
-            } 
-            
+                setRecentFiles(this.configurationModel.getRecentFilesList());
+            }
+
         } finally {
-            configurationModel.addPropertyChangeListener(this);
-        }
-    }
-
-    @Override
-    public void actionPerformed(ActionEvent e) {
-        if (e.getActionCommand().equals(Commands.DATA_SOURCE_CHANGED)) {
-            if (!configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER)) {
-                closeFileItem.setEnabled(true);
-            } else {
-                closeFileItem.setEnabled(false);
-            }
-        } 
-    }    
-    
-    void setRecentFiles(List<String> recentFiles) {
-        recentFilesMenu.removeAll();
-        int fileMnemonic = 48; /* starts at KeyEvent.VK_0 */
-        for (String recentFile : recentFiles) {
-            RecentFileItem recentFileItem = new RecentFileItem(recentFile, fileMnemonic);
+            this.configurationModel.addPropertyChangeListener(this);
+        }
+    }
+
+    /**
+     * Set the recent file menu items.
+     *
+     * @param recentFiles the list of recent files from the model
+     */
+    private void setRecentFiles(final List<String> recentFiles) {
+        this.recentFilesMenu.removeAll();
+        int fileMnemonic = RECENT_FILES_START_INDEX; /* starts at KeyEvent.VK_0 */
+        for (final String recentFile : recentFiles) {
+            final RecentFileItem recentFileItem = new RecentFileItem(recentFile, fileMnemonic);
             recentFileItem.addActionListener(new ActionListener() {
-                public void actionPerformed(ActionEvent e) {            
-                    String recentFile = ((RecentFileItem) e.getSource()).getPath();
-                    DataSourceType dst = DataSourceType.getDataSourceType(recentFile);
-                    configurationModel.setDataSourcePath(recentFile); 
-                    configurationModel.setDataSourceType(dst);
+                @Override
+                public void actionPerformed(final ActionEvent e) {
+                    final String recentFile = ((RecentFileItem) e.getSource()).getPath();
+                    final DataSourceType dst = DataSourceType.getDataSourceType(recentFile);
+                    MenuBar.this.configurationModel.setDataSourcePath(recentFile);
+                    MenuBar.this.configurationModel.setDataSourceType(dst);
                 }
-            });                
-            recentFilesMenu.add(recentFileItem);
+            });
+            this.recentFilesMenu.add(recentFileItem);
             ++fileMnemonic;
-        }        
-    }
-    
+        }
+    }
+
+    /**
+     * Set state for AIDA server started.
+     */
     void startAIDAServer() {
-        serverItem.setActionCommand(Commands.STOP_AIDA_SERVER);
-        serverItem.setText("Stop AIDA Server");
-        serverItem.setToolTipText("Stop the remote AIDA server");
-    }
-    
+        this.serverItem.setActionCommand(Commands.STOP_AIDA_SERVER);
+        this.serverItem.setText("Stop AIDA Server");
+        this.serverItem.setToolTipText("Stop the remote AIDA server");
+    }
+
+    /**
+     * Set state for AIDA server stopped.
+     */
     void stopAIDAServer() {
-        serverItem.setActionCommand(Commands.START_AIDA_SERVER);
-        serverItem.setText("Start AIDA Server");
-        serverItem.setToolTipText("Start the remote AIDA server");
+        this.serverItem.setActionCommand(Commands.START_AIDA_SERVER);
+        this.serverItem.setText("Start AIDA Server");
+        this.serverItem.setToolTipText("Start the remote AIDA server");
     }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplication.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplication.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplication.java	Tue Apr 21 14:48:39 2015
@@ -3,8 +3,8 @@
 import hep.aida.jfree.AnalysisFactory;
 import hep.aida.jfree.plotter.PlotterRegion;
 import hep.aida.jfree.plotter.PlotterRegionListener;
-import hep.aida.ref.remote.rmi.client.RmiStoreFactory;
-
+
+import java.awt.Frame;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.WindowEvent;
@@ -19,6 +19,7 @@
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.logging.Handler;
 import java.util.logging.Level;
@@ -28,7 +29,6 @@
 
 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;
@@ -59,217 +59,278 @@
 import org.lcsim.util.log.DefaultLogFormatter;
 
 /**
- * This is the primary class that implements the monitoring GUI application.
- * It should not be used directly.  Instead the {@link Main} class should be
- * used from the command line.
- * 
- * @author Jeremy McCormick <[log in to unmask]>
+ * This is the primary class that implements the data monitoring GUI application.
+ * <p>
+ * It should not be used directly. Instead the {@link Main} class should be used from the command line.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 final class MonitoringApplication implements ActionListener, PropertyChangeListener {
 
-    // Statically initialize logging, which will be fully setup later.
-    static final Logger logger;
-    static {
-        logger = Logger.getLogger(MonitoringApplication.class.getSimpleName());
-    }
-    static final Level DEFAULT_LEVEL = Level.ALL;
-
-    // Default log stream.
-    MonitoringApplicationStreamHandler streamHandler;
-    LogHandler logHandler;
-    PrintStream sysOut = System.out;
-    PrintStream sysErr = System.err;
-    
-    // Application error handling.
-    ErrorHandler errorHandler;
-   
-    // The main GUI components inside a JFrame.
-    MonitoringApplicationFrame frame;    
-    
-    // The primary data models.
-    final RunModel runModel = new RunModel();
-    final ConfigurationModel configurationModel = new ConfigurationModel();
-    final ConnectionStatusModel connectionModel = new ConnectionStatusModel();
-        
-    // The default configuration resource embedded in the jar.
-    static final String DEFAULT_CONFIGURATION = "/org/hps/monitoring/config/default_config.prop";
-
-    // Encapsulation of ET connection and event processing.
-    EventProcessing processing;
-        
-    // Filters for opening files.
-    static final FileFilter lcioFilter = new FileNameExtensionFilter("LCIO files", "slcio");
-    static final EvioFileFilter evioFilter = new EvioFileFilter();
-    
-    AIDAServer server = new AIDAServer("hps-monitoring-app");
-    static final RmiStoreFactory rsf = new RmiStoreFactory();
-            
-    /**
-     * Default log handler.
+    /**
+     * The default log handler which puts records into the table GUI component.
      */
     class LogHandler extends Handler {
+
+        /**
+         * Close the handler.
+         *
+         * @throws SecurityException never
+         */
+        @Override
+        public void close() throws SecurityException {
+            // Does nothing.
+        }
+
+        /**
+         * Flush the handler.
+         */
+        @Override
+        public void flush() {
+            // Does nothing.
+        }
 
         /**
          * This method inserts a record into the log table.
          */
-        public void publish(LogRecord record) {
+        @Override
+        public void publish(final LogRecord record) {
+            // Add the record to the table's model.
             getLogRecordModel().add(record);
         }
-
-        public void close() throws SecurityException {
-        }
-
-        public void flush() {
-        }
-    }    
-    
-    LogRecordModel getLogRecordModel() {
-        return frame.logPanel.logTable.model;
-    }
-    
-    LogTable getLogTable() {
-        return frame.logPanel.logTable;
-    }
-    
+    }
+
+    /**
+     * Log handler which publishes messages to a stream (console or file in this case).
+     */
     class MonitoringApplicationStreamHandler extends StreamHandler {
-        
-        MonitoringApplicationStreamHandler(PrintStream ps) {
+
+        /**
+         * Class constructor.
+         *
+         * @param ps the output stream
+         */
+        MonitoringApplicationStreamHandler(final PrintStream ps) {
             super(ps, new DefaultLogFormatter());
         }
-        
-        public void publish(LogRecord record) {
+
+        /**
+         * Publish a record which will automatically flush the handler.
+         *
+         * @param record the <code>LogRecord</code> to publish
+         */
+        @Override
+        public void publish(final LogRecord record) {
             super.publish(record);
+
+            // FIXME: Is this efficient? Should this always happen here?
             flush();
         }
-        
-        public void setOutputStream(OutputStream out) {
+
+        /**
+         * Set the output stream.
+         *
+         * @param out the output stream
+         */
+        @Override
+        public void setOutputStream(final OutputStream out) {
             super.setOutputStream(out);
-        }        
-    }
-                 
+        }
+    }
+
+    /**
+     * The default configuration resource from the jar.
+     */
+    private static final String DEFAULT_CONFIGURATION = "/org/hps/monitoring/config/default_config.prop";
+
+    /**
+     * The default log level (shows all messages).
+     */
+    private static final Level DEFAULT_LEVEL = Level.ALL;
+
+    /**
+     * A filter for selecting EVIO files.
+     */
+    private static final EvioFileFilter EVIO_FILTER = new EvioFileFilter();
+
+    /**
+     * A filter for selecting LCIO files.
+     */
+    private static final FileFilter LCIO_FILTER = new FileNameExtensionFilter("LCIO files", "slcio");
+
+    /**
+     * Global logging object.
+     */
+    private static final Logger LOGGER;
+
+    /**
+     * Saved reference to <code>System.err</code> for convenience.
+     */
+    private static final PrintStream SYS_ERR = System.err;
+
+    /**
+     * Saved reference to <code>System.out</code> for convenience.
+     */
+    private static final PrintStream SYS_OUT = System.out;
+
+    /**
+     * Initialize logging which will be fully configured later.
+     */
+    static {
+        LOGGER = Logger.getLogger(MonitoringApplication.class.getSimpleName());
+    }
+
+    /**
+     * Static utility method for creating new instance.
+     *
+     * @param configuration the application settings
+     * @return the new monitoring application instance
+     */
+    static MonitoringApplication create(final Configuration configuration) {
+        return new MonitoringApplication(configuration);
+    }
+
+    /**
+     * The global configuration model.
+     */
+    private final ConfigurationModel configurationModel = new ConfigurationModel();
+
+    /**
+     * The global connection status model.
+     */
+    private final ConnectionStatusModel connectionModel = new ConnectionStatusModel();
+
+    /**
+     * The error handling object.
+     */
+    private ErrorHandler errorHandler;
+
+    /**
+     * The primary GUI component which is a <code>JFrame</code>.
+     */
+    private MonitoringApplicationFrame frame;
+
+    /**
+     * The current log handler.
+     */
+    private LogHandler logHandler;
+
+    /**
+     * Event processing wrapper.
+     */
+    private EventProcessing processing;
+
+    /**
+     * The model which has information about the current run and events being processed.
+     */
+    private final RunModel runModel = new RunModel();
+
+    /**
+     * A remote AIDA server instance.
+     */
+    private final AIDAServer server = new AIDAServer("hps-monitoring-app");
+
+    /**
+     * The handler for putting messages into the log table.
+     */
+    private MonitoringApplicationStreamHandler streamHandler;
+
     /**
      * Instantiate and show the monitoring application with the given configuration.
-     * @param userConfiguration The Configuration object containing application settings.
-     */
-    MonitoringApplication(Configuration userConfiguration) {
-        
+     *
+     * @param userConfiguration the Configuration object containing application settings
+     */
+    MonitoringApplication(final Configuration userConfiguration) {
+
         try {
-        
+
             // Setup the main GUI component.
-            frame = new MonitoringApplicationFrame(this);
-            
+            this.frame = new MonitoringApplicationFrame(this);
+
             // Add window listener to perform clean shutdown.
-            frame.addWindowListener(new WindowListener() {
+            this.frame.addWindowListener(new WindowListener() {
 
                 @Override
-                public void windowOpened(WindowEvent e) {
+                public void windowActivated(final WindowEvent e) {
                 }
 
+                /**
+                 * Activate cleanup when window closes.
+                 *
+                 * @param e the window event
+                 */
                 @Override
-                public void windowClosing(WindowEvent e) {
-                }
-
-                @Override
-                public void windowClosed(WindowEvent e) {
+                public void windowClosed(final WindowEvent e) {
                     exit();
                 }
 
                 @Override
-                public void windowIconified(WindowEvent e) {
+                public void windowClosing(final WindowEvent e) {
                 }
 
                 @Override
-                public void windowDeiconified(WindowEvent e) {
+                public void windowDeactivated(final WindowEvent e) {
                 }
 
                 @Override
-                public void windowActivated(WindowEvent e) {
+                public void windowDeiconified(final WindowEvent e) {
                 }
 
                 @Override
-                public void windowDeactivated(WindowEvent e) {
+                public void windowIconified(final WindowEvent e) {
+                }
+
+                @Override
+                public void windowOpened(final WindowEvent e) {
                 }
             });
-        
+
             // Setup the error handler.
-            errorHandler = new ErrorHandler(frame, logger);
-                       
+            this.errorHandler = new ErrorHandler(this.frame, LOGGER);
+
             // Add this class as a listener on the configuration model.
-            configurationModel.addPropertyChangeListener(this);
-        
+            this.configurationModel.addPropertyChangeListener(this);
+
             // Setup the logger.
             setupLogger();
-               
+
             // Setup AIDA plotting and connect it to the GUI.
             setupAida();
-            
+
             // Load the default configuration.
             loadConfiguration(new Configuration(DEFAULT_CONFIGURATION), false);
-                    
+
             if (userConfiguration != null) {
                 // Load user configuration.
                 loadConfiguration(userConfiguration, true);
-            } 
-        
+            }
+
             // Enable the GUI now that initialization is complete.
-            frame.setEnabled(true);
-        
-            logger.info("application initialized successfully");
-        
-        } catch (Exception e) {
+            this.frame.setEnabled(true);
+
+            LOGGER.info("application initialized successfully");
+
+        } catch (final Exception e) {
             // Don't use the ErrorHandler here because we don't know that it initialized successfully.
             System.err.println("MonitoringApplication failed to initialize without errors!");
-            DialogUtil.showErrorDialog(null, "Error Starting Monitoring Application", "Monitoring application failed to initialize.");
+            DialogUtil.showErrorDialog(null, "Error Starting Monitoring Application",
+                    "Monitoring application failed to initialize.");
             e.printStackTrace();
             System.exit(1);
-        }        
-    }
-    
-    /**
-     * Setup the logger.
-     */
-    void setupLogger() {
-        logger.setUseParentHandlers(false);        
-        logHandler = new LogHandler();
-        logger.addHandler(logHandler);
-        streamHandler = new MonitoringApplicationStreamHandler(System.out);
-        logger.addHandler(streamHandler);
-        for (Handler handler : logger.getHandlers()) {
-            handler.setLevel(DEFAULT_LEVEL);
-        }
-        logger.setLevel(DEFAULT_LEVEL);
-        logger.info("logging initialized");
-    }
-        
-    /**
-     * Static utility method for creating new instance.
-     * @param configuration The application settings.
-     * @return The new monitoring application instance.
-     */
-    static MonitoringApplication create(Configuration configuration) {
-        return new MonitoringApplication(configuration);
-    }    
-        
-    /**
-     * Handle property changes.
-     * @param evt The property change event.
+        }
+    }
+
+    /**
+     * The primary action handler for the application.
+     *
+     * @param e the {@link java.awt.ActionEvent} to handle
      */
     @Override
-    public void propertyChange(PropertyChangeEvent evt) {
-        if (evt.getPropertyName().equals(ConfigurationModel.LOG_LEVEL_PROPERTY)) {
-            setLogLevel();
-        }
-    }
-    
-    /**
-     * The primary action handler for the application.
-     * @param e The ActionEvent to handle.
-     */
-    public void actionPerformed(ActionEvent e) {
-
-        //logger.finest("actionPerformed - " + e.getActionCommand());
-        
-        String command = e.getActionCommand();
+    public void actionPerformed(final ActionEvent e) {
+
+        // logger.finest("actionPerformed - " + e.getActionCommand());
+
+        final String command = e.getActionCommand();
         if (Commands.CONNECT.equals(command)) {
             startSession();
         } else if (Commands.DISCONNECT.equals(command)) {
@@ -278,20 +339,20 @@
             savePlots();
         } else if (Commands.EXIT.equals(command)) {
             // This will trigger the window closing action that cleans everything up.
-            frame.dispose();
-        } else if (Commands.PAUSE.equals(command)) { 
-            processing.pause();
+            this.frame.dispose();
+        } else if (Commands.PAUSE.equals(command)) {
+            this.processing.pause();
         } else if (Commands.NEXT.equals(command)) {
-            processing.next();
+            this.processing.next();
         } else if (Commands.RESUME.equals(command)) {
-            processing.resume();
+            this.processing.resume();
         } else if (Commands.SHOW_SETTINGS.equals(command)) {
             showSettingsDialog();
         } else if (Commands.LOAD_SETTINGS.equals(command)) {
             loadSettings();
         } else if (Commands.SAVE_SETTINGS.equals(command)) {
             saveSettings();
-        }  else if (Commands.CLEAR_PLOTS.equals(command)) {
+        } else if (Commands.CLEAR_PLOTS.equals(command)) {
             clearPlots();
         } else if (Commands.LOAD_DEFAULT_SETTINGS.equals(command)) {
             loadDefaultSettings();
@@ -320,545 +381,672 @@
         } else if (Commands.STOP_AIDA_SERVER.equals(command)) {
             stopAIDAServer();
         }
-    }    
-    
-    /**
-     * Setup AIDA plotting into the GUI components.
-     */
-    void setupAida() {
-        // Register the factory for displaying plots in tabs.
-        MonitoringAnalysisFactory.register();
-        
-        // Set the root tab pane for displaying plots.
-        MonitoringPlotFactory.setRootPane(frame.plotPanel.getPlotPane());
-        
-        // Setup the region listener to connect the plot info window.
-        MonitoringPlotFactory.setPlotterRegionListener(new PlotterRegionListener() {
-            @Override
-            public void regionSelected(PlotterRegion region) {
-                if (region != null) {
-                    frame.plotInfoPanel.setCurrentRegion(region);
-                }
+    }
+
+    /**
+     * Redirect <code>System.out</code> and <code>System.err</code> to a file chosen by a file chooser.
+     */
+    private void chooseLogFile() {
+        final JFileChooser fc = new JFileChooser();
+        fc.setAcceptAllFileFilterUsed(false);
+        fc.setDialogTitle("Save Log Messages to File");
+        fc.setCurrentDirectory(new File("."));
+        final int r = fc.showSaveDialog(this.frame);
+        if (r == JFileChooser.APPROVE_OPTION) {
+            final String fileName = fc.getSelectedFile().getPath();
+            if (new File(fileName).exists()) {
+                DialogUtil.showErrorDialog(this.frame, "File Exists", "File already exists.");
+            } else {
+                logToFile(new File(fileName));
             }
-        });
-        
-        // Perform global configuration of the JFreeChart back end.
-        AnalysisFactory.configure();
-    }
-                
+        }
+    }
+
+    /**
+     * Clear the current set of AIDA plots in the default data tree.
+     */
+    private void clearPlots() {
+        final int confirmation = DialogUtil.showConfirmationDialog(this.frame,
+                "Are you sure you want to clear the plots", "Clear Plots Confirmation");
+        if (confirmation == JOptionPane.YES_OPTION) {
+            AIDA.defaultInstance().clearAll();
+            DialogUtil.showInfoDialog(this.frame, "Plots Clear", "The AIDA plots were cleared.");
+        }
+        LOGGER.info("plots were cleared");
+    }
+
+    /**
+     * Remove the currently selected file from the data source list.
+     */
+    private void closeFile() {
+        if (!this.configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER)) {
+            final DataSourceItem item = (DataSourceItem) this.frame.getToolbarPanel().getDataSourceComboBox()
+                    .getSelectedItem();
+            if (item.getPath().equals(this.configurationModel.getDataSourcePath())) {
+                this.frame.getToolbarPanel().getDataSourceComboBox()
+                        .removeItem(this.frame.getToolbarPanel().getDataSourceComboBox().getSelectedItem());
+            }
+        }
+    }
+
+    /**
+     * Exit from the application from exit menu item or hitting close window button.
+     */
+    private void exit() {
+        if (this.connectionModel.isConnected()) {
+            this.processing.stop();
+        }
+        this.logHandler.setLevel(Level.OFF);
+        LOGGER.info("exiting the application");
+        this.streamHandler.flush();
+        System.exit(0);
+    }
+
+    /**
+     * Get the current configuration model.
+     *
+     * @return the current configuration model
+     */
+    ConfigurationModel getConfigurationModel() {
+        return this.configurationModel;
+    }
+
+    /**
+     * Get the current connection status model.
+     *
+     * @return the current connections status model
+     */
+    ConnectionStatusModel getConnectionModel() {
+        return this.connectionModel;
+    }
+
+    /**
+     * Get the application's error handling object.
+     *
+     * @return the error handling object
+     */
+    ErrorHandler getErrorHandler() {
+        return this.errorHandler;
+    }
+
+    /**
+     * Get the logger.
+     *
+     * @return the logger
+     */
+    Logger getLogger() {
+        return LOGGER;
+    }
+
+    /**
+     * Get the table model for log records.
+     *
+     * @return the table model for log records
+     */
+    LogRecordModel getLogRecordModel() {
+        return this.frame.getLogPanel().getLogTable().getLogRecordModel();
+    }
+
+    /**
+     * Get the log table.
+     *
+     * @return the log table
+     */
+    LogTable getLogTable() {
+        return this.frame.getLogPanel().getLogTable();
+    }
+
+    /**
+     * Get a list of relevant run data from the model for writing to a PDF.
+     *
+     * @return the list of run data from the model
+     */
+    private List<String> getRunData() {
+        final List<String> data = new ArrayList<String>();
+        data.add("Created: " + new Date());
+        data.add("Run Number: " + this.runModel.getRunNumber());
+        data.add("Started: " + this.runModel.getStartDate());
+        data.add("Ended: " + this.runModel.getEndDate());
+        data.add("Length: " + this.runModel.getRunLength() + " seconds");
+        data.add("Total Events: " + this.runModel.getTotalEvents());
+        data.add("Elapsed Time: " + this.runModel.getElapsedTime());
+        data.add("Events Processed: " + this.runModel.getEventsReceived());
+        return data;
+    }
+
+    /**
+     * Get the run model with information about the run and event(s) currently being processed.
+     *
+     * @return the run model
+     */
+    RunModel getRunModel() {
+        return this.runModel;
+    }
+
     /**
      * This method sets the configuration on the model, which fires a change for every property.
-     * @param configuration The new configuration.
-     * @param merge True to merge the configuration into the current one rather than replace it.
-     */
-    void loadConfiguration(Configuration configuration, boolean merge) {
-                               
+     *
+     * @param configuration the new configuration
+     * @param merge <code>true</code> to merge the configuration into the current one rather than replace it
+     */
+    private void loadConfiguration(final Configuration configuration, final boolean merge) {
+
         if (merge) {
             // This will merge in additional properties so that default or current settings are preserved.
-            configurationModel.merge(configuration);
+            this.configurationModel.merge(configuration);
         } else {
             // HACK: Clear data source combo box for clean configuration.
-            frame.toolbarPanel.dataSourceComboBox.removeAllItems();
-            
+            this.frame.getToolbarPanel().getDataSourceComboBox().removeAllItems();
+
             // This will reset all configuration properties.
-            configurationModel.setConfiguration(configuration);
-        }
-        
-        if (configuration.getFile() != null)
-            logger.config("loaded config from file " + configuration.getFile().getPath());
-        else
-            logger.config("loaded config from resource " + configuration.getResourcePath());
-    }
-              
+            this.configurationModel.setConfiguration(configuration);
+        }
+
+        if (configuration.getFile() != null) {
+            LOGGER.config("loaded config from file " + configuration.getFile().getPath());
+        } else {
+            LOGGER.config("loaded config from resource " + configuration.getResourcePath());
+        }
+    }
+
+    /**
+     * Load default application settings.
+     */
+    private void loadDefaultSettings() {
+        loadConfiguration(new Configuration(MonitoringApplication.DEFAULT_CONFIGURATION), false);
+        DialogUtil.showInfoDialog(this.frame, "Default Configuration Loaded", "The default configuration was loaded.");
+        LOGGER.config("default settings loaded");
+    }
+
+    /**
+     * Load settings from a properties file using a file chooser.
+     */
+    private void loadSettings() {
+        final JFileChooser fc = new JFileChooser();
+        fc.setDialogTitle("Load Settings");
+        fc.setCurrentDirectory(new File("."));
+        final int r = fc.showDialog(this.frame, "Load ...");
+        if (r == JFileChooser.APPROVE_OPTION) {
+            final File f = fc.getSelectedFile();
+            loadConfiguration(new Configuration(f), true);
+            LOGGER.info("loaded configuration from file: " + f.getPath());
+            DialogUtil.showInfoDialog(this.frame, "Settings Loaded", "Settings were loaded successfully.");
+        }
+    }
+
+    /**
+     * Redirect <code>System.out</code> and <code>System.err</code> to a file.
+     *
+     * @param file the output log file
+     * @throws FileNotFoundException if the file does not exist
+     */
+    private void logToFile(final File file) {
+        try {
+
+            // Create the output file stream.
+            final PrintStream fileStream = new PrintStream(new FileOutputStream(file.getPath()));
+            System.setOut(fileStream);
+            System.setErr(fileStream);
+
+            // Flush the current handler, but do NOT close here or System.out gets clobbered!
+            this.streamHandler.flush();
+
+            // Replace the current handler with one using the file stream.
+            LOGGER.removeHandler(this.streamHandler);
+            this.streamHandler = new MonitoringApplicationStreamHandler(fileStream);
+            this.streamHandler.setLevel(LOGGER.getLevel());
+            LOGGER.addHandler(this.streamHandler);
+
+            // Set the properties on the model.
+            this.configurationModel.setLogFileName(file.getPath());
+            this.configurationModel.setLogToFile(true);
+
+            LOGGER.info("Saving log messages to " + this.configurationModel.getLogFileName());
+            DialogUtil.showInfoDialog(this.frame, "Logging to File", "Log messages redirected to file" + '\n'
+                    + this.configurationModel.getLogFileName());
+
+        } catch (final FileNotFoundException e) {
+            this.errorHandler.setError(e).log().showErrorDialog();
+        }
+    }
+
+    /**
+     * Send <code>System.out</code> and <code>System.err</code> back to the terminal, e.g. if they were previously sent
+     * to a file.
+     */
+    private void logToTerminal() {
+
+        // Reset System.out and err back to original streams.
+        System.setOut(MonitoringApplication.SYS_OUT);
+        System.setErr(MonitoringApplication.SYS_ERR);
+
+        // Flush and close the current handler, which is using a file stream.
+        this.streamHandler.flush();
+        this.streamHandler.close();
+
+        // Replace the handler with the one printing to the terminal.
+        LOGGER.removeHandler(this.streamHandler);
+        this.streamHandler = new MonitoringApplicationStreamHandler(System.out);
+        this.streamHandler.setLevel(LOGGER.getLevel());
+        LOGGER.addHandler(this.streamHandler);
+
+        LOGGER.log(Level.INFO, "log messages redirected to terminal");
+
+        // Update the model to indicate logging to file has been disabled.
+        this.configurationModel.setLogToFile(false);
+
+        DialogUtil.showInfoDialog(this.frame, "Log to Terminal", "Log messages will be sent to the terminal.");
+    }
+
+    /**
+     * Maximize the application window.
+     */
+    private void maximizeWindow() {
+        this.frame.setExtendedState(Frame.MAXIMIZED_BOTH);
+    }
+
+    /**
+     * Minimize the application window.
+     */
+    private void minimizeWindow() {
+        this.frame.setExtendedState(Frame.ICONIFIED);
+    }
+
+    /**
+     * Open a file data source using a <code>JFileChooser</code>.
+     */
+    private void openFile() {
+        final JFileChooser fc = new JFileChooser(System.getProperty("user.dir"));
+        fc.setAcceptAllFileFilterUsed(false);
+        fc.addChoosableFileFilter(LCIO_FILTER);
+        fc.addChoosableFileFilter(EVIO_FILTER);
+        fc.setDialogTitle("Select Data File");
+        final int r = fc.showDialog(this.frame, "Select ...");
+        if (r == JFileChooser.APPROVE_OPTION) {
+
+            // Set data source path.
+            final String filePath = fc.getSelectedFile().getPath();
+
+            // Set data source type.
+            final FileFilter filter = fc.getFileFilter();
+            DataSourceType type = null;
+            if (filter == LCIO_FILTER) {
+                type = DataSourceType.LCIO_FILE;
+            } else if (filter == EVIO_FILTER) {
+                type = DataSourceType.EVIO_FILE;
+            } else {
+                // This should never happen.
+                throw new RuntimeException();
+            }
+
+            this.configurationModel.setDataSourcePath(filePath);
+            this.configurationModel.setDataSourceType(type);
+
+            this.configurationModel.addRecentFile(filePath);
+
+            LOGGER.config("set new data source " + filePath + " with type " + type);
+        }
+    }
+
+    /**
+     * Handle property changes.
+     *
+     * @param evt the <code>PropertyChangeEvent</code> to handle
+     */
+    @Override
+    public void propertyChange(final PropertyChangeEvent evt) {
+        if (evt.getPropertyName().equals(ConfigurationModel.LOG_LEVEL_PROPERTY)) {
+            setLogLevel();
+        }
+    }
+
     /**
      * Reset the plots and clear the tabs in the plot window.
      */
-    void resetPlots() {
-        
+    private void resetPlots() {
+
         // Clear global list of registered plotters.
-        MonitoringPlotFactory.getPlotterRegistry().clear();  
-        
+        MonitoringPlotFactory.getPlotterRegistry().clear();
+
         // Clear the static AIDA tree in case plots are hanging around from previous sessions.
         AIDA.defaultInstance().clearAll();
 
         // Reset plot panel which removes all its tabs.
-        frame.plotPanel.reset();
-        
-        logger.info("plots were cleared");
-    }                                    
-                   
-    /**
-     * Configure the system status monitor panel for a new job.
-     */
-    void setupSystemStatusMonitor() {
-        
-        // Clear the system status monitor table.
-        frame.systemStatusPanel.clear();
-
-        // Get the global registry of SystemStatus objects.
-        SystemStatusRegistry registry = SystemStatusRegistry.getSystemStatusRegistery();
-
-        // Process the SystemStatus objects.
-        for (SystemStatus systemStatus : registry.getSystemStatuses()) {
-            // This will add the status to the two tables.
-            frame.systemStatusPanel.addSystemStatus(systemStatus);
-        }
-        
-        logger.info("system status monitor initialized successfully");
-    }
-    
-    /**
-     * Start a new monitoring session.
-     */
-    synchronized void startSession() {
-        
-        logger.info("starting new session");
-
-        try {
-                        
-            // Reset the plot panel and global AIDA state.
-            resetPlots();
-
-            // The system status registry is cleared here before any event processors
-            // which might create a SystemStatus are added to the event processing chain
-            // e.g. an LCSim Driver, etc.
-            SystemStatusRegistry.getSystemStatusRegistery().clear();
-
-            // List of extra composite record processors including the updater for the RunPanel.
-            List<CompositeRecordProcessor> processors = new ArrayList<CompositeRecordProcessor>();
-            processors.add(frame.dashboardPanel.new EventDashboardUpdater());
-            
-            // Add Driver to update the trigger diagnostics tables.
-            List<Driver> drivers = new ArrayList<Driver>();
-            drivers.add(frame.triggerPanel.new TriggerDiagnosticGUIDriver());
-
-            // Add listener to push conditions changes to conditions panel.
-            List<ConditionsListener> conditionsListeners = new ArrayList<ConditionsListener>();
-            conditionsListeners.add(frame.conditionsPanel.new ConditionsPanelListener());
-            
-            // Instantiate the event processing wrapper.
-            processing = new EventProcessing(this, processors, drivers, conditionsListeners);
-            
-            // Connect to the ET system, if applicable.
-            processing.connect();
-            
-            // Configure event processing from the global application settings, including setup of record loop.
-            logger.info("setting up event processing on source " + configurationModel.getDataSourcePath() 
-                    + " with type " + configurationModel.getDataSourceType());
-            processing.setup(configurationModel);
-                                  
-            // Setup the system status monitor table.
-            setupSystemStatusMonitor();
-                                            
-            // Start the event processing thread.            
-            processing.start();            
-            
-            logger.info("new session successfully initialized");
-
-        } catch (Exception e) {
-
-            // Disconnect from the ET system.
-            processing.disconnect();
-            
-            // Log the error that occurred and show a pop up dialog.
-            errorHandler.setError(e).log().printStackTrace().showErrorDialog("There was an error while starting the session." 
-                    + '\n' + "See the log for details.", "Session Error");
-            
-            logger.severe("failed to start new session");
-        }
-    }
-           
-    /**
-     * Exit from the application from exit menu item or hitting close window button.
-     */
-    void exit() {        
-        if (connectionModel.isConnected()) {
-            processing.stop();
-        }
-        logHandler.setLevel(Level.OFF);
-        logger.info("exiting the application");
-        streamHandler.flush();
-        System.exit(0);
-    }
-            
+        this.frame.getPlotPanel().reset();
+
+        LOGGER.info("plots were cleared");
+    }
+
+    /**
+     * Restore the default GUI layout.
+     */
+    private void restoreDefaultWindow() {
+        maximizeWindow();
+        this.frame.restoreDefaults();
+    }
+
+    /**
+     * Run the disconnection on a separate thread.
+     */
+    private void runDisconnectThread() {
+        new Thread() {
+            @Override
+            public void run() {
+                LOGGER.fine("disconnect thread is running ...");
+                MonitoringApplication.this.connectionModel.setConnectionStatus(ConnectionStatus.DISCONNECTING);
+                MonitoringApplication.this.processing.stop();
+                LOGGER.fine("disconnect thread finished!");
+            }
+        }.run();
+    }
+
+    /**
+     * Save the log table to a file using a file chooser.
+     */
+    private void saveLogTable() {
+        saveTable(this.frame.getLogPanel().getLogTable());
+    }
+
     /**
      * Save plots to an AIDA, ROOT or PDF file using a file chooser.
      */
-    void savePlots() {
-        JFileChooser fc = new JFileChooser();
+    private void savePlots() {
+        final JFileChooser fc = new JFileChooser();
         fc.addChoosableFileFilter(new FileNameExtensionFilter("ROOT file", "root"));
-        FileFilter filter = new FileNameExtensionFilter("AIDA file", "aida");
+        final FileFilter filter = new FileNameExtensionFilter("AIDA file", "aida");
         fc.addChoosableFileFilter(filter);
         fc.addChoosableFileFilter(new FileNameExtensionFilter("PDF file", "pdf"));
         fc.setAcceptAllFileFilterUsed(false);
         fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
         fc.setFileFilter(filter);
-        int r = fc.showSaveDialog(frame);
+        final int r = fc.showSaveDialog(this.frame);
         if (r == JFileChooser.APPROVE_OPTION) {
-            File selectedFile = fc.getSelectedFile();
+            final File selectedFile = fc.getSelectedFile();
             if (!selectedFile.exists()) {
                 String fileName = fc.getSelectedFile().getAbsolutePath();
-                String extension = ((FileNameExtensionFilter) fc.getFileFilter()).getExtensions()[0];
+                final String extension = ((FileNameExtensionFilter) fc.getFileFilter()).getExtensions()[0];
                 if (!fileName.endsWith(".aida") && !fileName.endsWith(".root") && !fileName.endsWith(".pdf")) {
                     fileName += "." + extension;
                 }
                 try {
-                    if (extension.equals("pdf")) {
+                    if ("pdf".equals(extension)) {
                         // Write to a single PDF file.
-                        ExportPdf.write(MonitoringPlotFactory.getPlotterRegistry().getPlotters(), fileName);
+                        ExportPdf.write(MonitoringPlotFactory.getPlotterRegistry().getPlotters(), fileName,
+                                getRunData());
                     } else {
                         // Save plot object data to AIDA or ROOT file.
                         AIDA.defaultInstance().saveAs(fileName);
                     }
-                    logger.info("saved plots to " + fileName);
-                    DialogUtil.showInfoDialog(frame, "Plots Saved", "Plots were successfully saved to " + '\n' + fileName);
-                } catch (IOException e) {
-                    errorHandler.setError(e).setMessage("Error Saving Plots").printStackTrace().log().showErrorDialog();
+                    LOGGER.info("saved plots to " + fileName);
+                    DialogUtil.showInfoDialog(this.frame, "Plots Saved", "Plots were successfully saved to " + '\n'
+                            + fileName);
+                } catch (final IOException e) {
+                    this.errorHandler.setError(e).setMessage("Error Saving Plots").printStackTrace().log()
+                            .showErrorDialog();
                 }
             } else {
-                DialogUtil.showErrorDialog(frame, "File Exists", "Selected file already exists.");
+                DialogUtil.showErrorDialog(this.frame, "File Exists", "Selected file already exists.");
             }
         }
     }
-    
-    /**
-     * Clear the current set of AIDA plots in the default data tree.
-     */
-    void clearPlots() {
-        int confirmation = DialogUtil.showConfirmationDialog(frame, 
-                "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.");
-        }
-        logger.info("plots were cleared");
-    }
-    
-    /**
-     * Load default application settings.
-     */
-    void loadDefaultSettings() {
-        loadConfiguration(new Configuration(MonitoringApplication.DEFAULT_CONFIGURATION), false);
-        DialogUtil.showInfoDialog(frame, "Default Configuration Loaded", "The default configuration was loaded.");
-        logger.config("default settings loaded");
-    }
-    
-    /**
-     * Show the settings dialog window.
-     */
-    void showSettingsDialog() {
-        frame.settingsDialog.setVisible(true);        
-    }
-        
-    /**
-     * Open a file data source using a <code>JFileChooser</code>.
-     */
-    void openFile() {
-        JFileChooser fc = new JFileChooser(System.getProperty("user.dir"));
-        fc.setAcceptAllFileFilterUsed(false);
-        fc.addChoosableFileFilter(lcioFilter);
-        fc.addChoosableFileFilter(evioFilter);
-        fc.setDialogTitle("Select Data File");
-        int r = fc.showDialog(frame, "Select ...");        
-        if (r == JFileChooser.APPROVE_OPTION) {
-                                  
-            // Set data source path.            
-            final String filePath = fc.getSelectedFile().getPath();
-            
-            // Set data source type.
-            FileFilter filter = fc.getFileFilter();
-            DataSourceType type = null;
-            if (filter == lcioFilter) {
-                type = DataSourceType.LCIO_FILE;
-            } else if (filter == evioFilter) {
-                type = DataSourceType.EVIO_FILE;
-            } else {
-                // This should never happen.
-                throw new RuntimeException();
-            }
-                        
-            configurationModel.setDataSourcePath(filePath);
-            configurationModel.setDataSourceType(type);
-            
-            configurationModel.addRecentFile(filePath);
-            
-            logger.config("set new data source " + filePath + " with type " + type);
-        }
-    }    
-    
-    /**
-     * Save current settings to a file using a file chooser.
-     */
-    void saveSettings() {
-        JFileChooser fc = new JFileChooser();
-        fc.setDialogTitle("Save Configuration");
-        fc.setCurrentDirectory(new File("."));
-        int r = fc.showSaveDialog(frame);
-        if (r == JFileChooser.APPROVE_OPTION) {
-            File f = fc.getSelectedFile();
-            configurationModel.getConfiguration().writeToFile(f);
-            logger.info("saved configuration to file: " + f.getPath());
-            DialogUtil.showInfoDialog(frame, "Settings Saved", "Settings were saved successfully.");
-        }
-    }
-    
-    /**
-     * Load settings from a properties file using a file chooser.
-     */
-    void loadSettings() {
-        JFileChooser fc = new JFileChooser();
-        fc.setDialogTitle("Load Settings");
-        fc.setCurrentDirectory(new File("."));
-        int r = fc.showDialog(frame, "Load ...");
-        if (r == JFileChooser.APPROVE_OPTION) {
-            File f = fc.getSelectedFile();
-            loadConfiguration(new Configuration(f), true);
-            logger.info("loaded configuration from file: " + f.getPath());
-            DialogUtil.showInfoDialog(frame, "Settings Loaded", "Settings were loaded successfully.");
-        }
-    }
-    
-    /**
-     * Maximize the application window.
-     */
-    void maximizeWindow() {
-        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
-    }   
-    
-    /**
-     * Minimize the application window.
-     */
-    void minimizeWindow() {
-        frame.setExtendedState(JFrame.ICONIFIED);
-    }    
-    
-    /**
-     * Restore the default GUI layout.
-     */
-    void restoreDefaultWindow() {
-        maximizeWindow();
-        frame.restoreDefaults();
-    }    
-    
-    /**
-     * Remove the currently selected file from the data source list.
-     */
-    void closeFile() {
-        if (!configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER)) {
-            DataSourceItem item = (DataSourceItem) frame.toolbarPanel.dataSourceComboBox.getSelectedItem();
-            if (item.getPath().equals(configurationModel.getDataSourcePath())) {
-                frame.toolbarPanel.dataSourceComboBox.removeItem(frame.toolbarPanel.dataSourceComboBox.getSelectedItem());    
-            }            
-        }
-    }
-    
+
     /**
      * Save a screenshot to a file using a file chooser.
      */
-    void saveScreenshot() {
-        JFileChooser fc = new JFileChooser();
+    private void saveScreenshot() {
+        final JFileChooser fc = new JFileChooser();
         fc.setAcceptAllFileFilterUsed(false);
         fc.setDialogTitle("Save Screenshot");
-        FileNameExtensionFilter pngFilter = new FileNameExtensionFilter("png file (*.png)", "png");
-        String format = pngFilter.getExtensions()[0];
+        final FileNameExtensionFilter pngFilter = new FileNameExtensionFilter("png file (*.png)", "png");
+        final String format = pngFilter.getExtensions()[0];
         fc.addChoosableFileFilter(pngFilter);
         fc.setCurrentDirectory(new File("."));
-        int r = fc.showSaveDialog(frame);
-        if (r == JFileChooser.APPROVE_OPTION) {            
+        final int r = fc.showSaveDialog(this.frame);
+        if (r == JFileChooser.APPROVE_OPTION) {
             String fileName = fc.getSelectedFile().getPath();
             if (!fileName.endsWith("." + format)) {
                 fileName += "." + format;
             }
-            frame.repaint();
-            Object lock = new Object();
-            synchronized (lock) {
-                try {
-                    lock.wait(500);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
+            /*
+             * final Object lock = new Object(); synchronized (lock) { try { lock.wait(500); } catch (final
+             * InterruptedException e) { e.printStackTrace(); } }
+             */
+            writeScreenshot(fileName, format);
+            DialogUtil.showInfoDialog(this.frame, "Screenshot Saved", "Screenshot was saved to file" + '\n' + fileName);
+            LOGGER.info("saved screenshot to " + fileName);
+        }
+    }
+
+    /**
+     * Save current settings to a file using a file chooser.
+     */
+    private void saveSettings() {
+        final JFileChooser fc = new JFileChooser();
+        fc.setDialogTitle("Save Configuration");
+        fc.setCurrentDirectory(new File("."));
+        final int r = fc.showSaveDialog(this.frame);
+        if (r == JFileChooser.APPROVE_OPTION) {
+            final File f = fc.getSelectedFile();
+            this.configurationModel.getConfiguration().writeToFile(f);
+            LOGGER.info("saved configuration to file: " + f.getPath());
+            DialogUtil.showInfoDialog(this.frame, "Settings Saved", "Settings were saved successfully.");
+        }
+    }
+
+    /**
+     * Export a JTable's data to a comma-delimited text file using a file chooser.
+     *
+     * @param table the table to export
+     */
+    private void saveTable(final JTable table) {
+        final JFileChooser fc = new JFileChooser();
+        fc.setDialogTitle("Save Table to Text File");
+        fc.setCurrentDirectory(new File("."));
+        final int r = fc.showSaveDialog(this.frame);
+        if (r == JFileChooser.APPROVE_OPTION) {
+            final String fileName = fc.getSelectedFile().getPath();
+            try {
+                TableExporter.export(table, fileName, ',');
+                LOGGER.info("saved table data to " + fileName);
+                DialogUtil.showInfoDialog(this.frame, "Table Data Saved", "The table was exported successfully.");
+            } catch (final IOException e) {
+                DialogUtil.showErrorDialog(this.frame, "Table Export Error", "The table export failed.");
+                LOGGER.warning("failed to save table data to " + fileName);
+            }
+        }
+    }
+
+    /**
+     * Set the log level from the configuration model.
+     */
+    private void setLogLevel() {
+        final Level newLevel = this.configurationModel.getLogLevel();
+        if (LOGGER.getLevel() != newLevel) {
+            LOGGER.setLevel(newLevel);
+            LOGGER.log(Level.INFO, "Log Level was changed to <" + this.configurationModel.getLogLevel().toString()
+                    + ">");
+        }
+    }
+
+    /**
+     * Setup AIDA plotting into the GUI components.
+     */
+    private void setupAida() {
+        // Register the factory for displaying plots in tabs.
+        MonitoringAnalysisFactory.register();
+
+        // Set the root tab pane for displaying plots.
+        MonitoringPlotFactory.setRootPane(this.frame.getPlotPanel().getPlotPane());
+
+        // Setup the region listener to connect the plot info window.
+        MonitoringPlotFactory.setPlotterRegionListener(new PlotterRegionListener() {
+            @Override
+            public void regionSelected(final PlotterRegion region) {
+                if (region != null) {
+                    MonitoringApplication.this.frame.getPlotInfoPanel().setCurrentRegion(region);
                 }
             }
-            writeScreenshot(fileName, format);
-            DialogUtil.showInfoDialog(frame, "Screenshot Saved", "Screenshot was saved to file" + '\n' + fileName);
-            logger.info("saved screenshot to " + fileName);
-        }
+        });
+
+        // Perform global configuration of the JFreeChart back end.
+        AnalysisFactory.configure();
+    }
+
+    /**
+     * Setup the logger.
+     */
+    private void setupLogger() {
+        LOGGER.setUseParentHandlers(false);
+        this.logHandler = new LogHandler();
+        LOGGER.addHandler(this.logHandler);
+        this.streamHandler = new MonitoringApplicationStreamHandler(System.out);
+        LOGGER.addHandler(this.streamHandler);
+        for (final Handler handler : LOGGER.getHandlers()) {
+            handler.setLevel(DEFAULT_LEVEL);
+        }
+        LOGGER.setLevel(DEFAULT_LEVEL);
+        LOGGER.info("logging initialized");
+    }
+
+    /**
+     * Configure the system status monitor panel for a new job.
+     */
+    private void setupSystemStatusMonitor() {
+
+        // Clear the system status monitor table.
+        this.frame.getSystemStatusPanel().clear();
+
+        // Get the global registry of SystemStatus objects.
+        final SystemStatusRegistry registry = SystemStatusRegistry.getSystemStatusRegistery();
+
+        // Process the SystemStatus objects.
+        for (final SystemStatus systemStatus : registry.getSystemStatuses()) {
+            // This will add the status to the two tables.
+            this.frame.getSystemStatusPanel().addSystemStatus(systemStatus);
+        }
+
+        LOGGER.info("system status monitor initialized successfully");
+    }
+
+    /**
+     * Show the settings dialog window.
+     */
+    private void showSettingsDialog() {
+        this.frame.getSettingsDialog().setVisible(true);
+    }
+
+    /**
+     * Start the AIDA server instance.
+     */
+    private void startAIDAServer() {
+        if (this.configurationModel.hasValidProperty(ConfigurationModel.AIDA_SERVER_NAME_PROPERTY)) {
+            this.server.setName(this.configurationModel.getAIDAServerName());
+        }
+        final boolean started = this.server.start();
+        if (started) {
+            this.frame.getApplicationMenu().startAIDAServer();
+            LOGGER.info("AIDA server started at " + this.server.getName());
+            DialogUtil
+                    .showInfoDialog(this.frame, "AIDA Server Started", "The remote AIDA server started successfully.");
+        } else {
+            LOGGER.warning("AIDA server failed to start");
+            DialogUtil.showErrorDialog(this.frame, "Failed to Start AIDA Server",
+                    "The remote AIDA server failed to start.");
+        }
+    }
+
+    /**
+     * Start a new monitoring session.
+     */
+    private synchronized void startSession() {
+
+        LOGGER.info("starting new session");
+
+        try {
+
+            // Reset the plot panel and global AIDA state.
+            resetPlots();
+
+            // The system status registry is cleared here before any event processors
+            // which might create a SystemStatus are added to the event processing chain
+            // e.g. an LCSim Driver, etc.
+            SystemStatusRegistry.getSystemStatusRegistery().clear();
+
+            // List of extra composite record processors including the updater for the RunPanel.
+            final List<CompositeRecordProcessor> processors = new ArrayList<CompositeRecordProcessor>();
+            processors.add(this.frame.getEventDashboard().new EventDashboardUpdater());
+
+            // Add Driver to update the trigger diagnostics tables.
+            final List<Driver> drivers = new ArrayList<Driver>();
+            drivers.add(this.frame.getTriggerPanel().new TriggerDiagnosticGUIDriver());
+
+            // Add listener to push conditions changes to conditions panel.
+            final List<ConditionsListener> conditionsListeners = new ArrayList<ConditionsListener>();
+            conditionsListeners.add(this.frame.getConditionsPanel().new ConditionsPanelListener());
+
+            // Instantiate the event processing wrapper.
+            this.processing = new EventProcessing(this, processors, drivers, conditionsListeners);
+
+            // Connect to the ET system, if applicable.
+            this.processing.connect();
+
+            // Configure event processing from the global application settings, including setup of record loop.
+            LOGGER.info("setting up event processing on source " + this.configurationModel.getDataSourcePath()
+                    + " with type " + this.configurationModel.getDataSourceType());
+            this.processing.setup(this.configurationModel);
+
+            // Setup the system status monitor table.
+            setupSystemStatusMonitor();
+
+            // Start the event processing thread.
+            this.processing.start();
+
+            LOGGER.info("new session successfully initialized");
+
+        } catch (final Exception e) {
+
+            // Disconnect from the ET system.
+            this.processing.disconnect();
+
+            // Log the error that occurred and show a pop up dialog.
+            this.errorHandler
+                    .setError(e)
+                    .log()
+                    .printStackTrace()
+                    .showErrorDialog(
+                            "There was an error while starting the session." + '\n' + "See the log for details.",
+                            "Session Error");
+
+            LOGGER.severe("failed to start new session");
+        }
+    }
+
+    /**
+     * Stop the AIDA server instance.
+     */
+    private void stopAIDAServer() {
+        this.server.disconnect();
+        this.frame.getApplicationMenu().stopAIDAServer();
+        LOGGER.info("AIDA server was stopped");
+        DialogUtil.showInfoDialog(this.frame, "AIDA Server Stopped", "The AIDA server was stopped.");
     }
 
     /**
      * Save a screenshot to an output file.
-     * @param fileName The name of the output file.
-     */
-    void writeScreenshot(String fileName, String format) {
-        BufferedImage image = new BufferedImage(frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_INT_RGB);
-        frame.paint(image.getGraphics()); 
+     *
+     * @param fileName the name of the output file
+     * @param format the output file format (must be accepted by <code>ImageIO</code>)
+     */
+    private void writeScreenshot(final String fileName, final String format) {
+        this.frame.repaint();
+        final BufferedImage image = new BufferedImage(this.frame.getWidth(), this.frame.getHeight(),
+                BufferedImage.TYPE_INT_RGB);
+        this.frame.paint(image.getGraphics());
         try {
             ImageIO.write(image, format, new File(fileName));
-        } catch (IOException e) {
-            errorHandler.setError(e).setMessage("Failed to save 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);
-    }
-        
-    /**
-     * Redirect <code>System.out</code> and <code>System.err</code> to file chosen
-     * by a file chooser.
-     */
-    void chooseLogFile() {
-        JFileChooser fc = new JFileChooser();
-        fc.setAcceptAllFileFilterUsed(false);
-        fc.setDialogTitle("Save Log Messages to File");       
-        fc.setCurrentDirectory(new File("."));
-        int r = fc.showSaveDialog(frame);
-        if (r == JFileChooser.APPROVE_OPTION) {            
-            String fileName = fc.getSelectedFile().getPath();
-            if (new File(fileName).exists()) {
-                DialogUtil.showErrorDialog(frame, "File Exists", "File already exists.");
-            } else {
-                logToFile(new File(fileName));
-            }
-        }        
-    }
-    
-    /**
-     * Redirect <code>System.out</code> and <code>System.err</code> to a file.
-     * @param file The output log file.
-     * @throws FileNotFoundException if the file does not exist.
-     */
-    void logToFile(File file) {
-        try {
-            
-            // Create the output file stream.
-            PrintStream fileStream = new PrintStream(new FileOutputStream(file.getPath()));
-            System.setOut(fileStream);
-            System.setErr(fileStream);
-            
-            // Flush the current handler, but do NOT close here or System.out gets clobbered!
-            streamHandler.flush();
-            
-            // Replace the current handler with one using the file stream.
-            logger.removeHandler(streamHandler);
-            streamHandler = new MonitoringApplicationStreamHandler(fileStream);
-            streamHandler.setLevel(logger.getLevel());
-            logger.addHandler(streamHandler);
-            
-            // Set the properties on the model.
-            configurationModel.setLogFileName(file.getPath());
-            configurationModel.setLogToFile(true);
-            
-            logger.info("Saving log messages to " + configurationModel.getLogFileName());
-            DialogUtil.showInfoDialog(frame, "Logging to File", 
-                    "Log messages redirected to file" + '\n' + configurationModel.getLogFileName());
-            
-        } catch (FileNotFoundException e) {
-            errorHandler.setError(e).log().showErrorDialog();
-        }
-    }      
-    
-    /**
-     * Send <code>System.out</code> and <code>System.err</code> back to the terminal, 
-     * e.g. if they were previously sent to a file.
-     */
-    void logToTerminal() {
-        
-        // Reset System.out and err back to original streams.
-        System.setOut(sysOut);
-        System.setErr(sysErr);
-        
-        // Flush and close the current handler, which is using a file stream.
-        streamHandler.flush();
-        streamHandler.close();
-        
-        // Replace the handler with the one printing to the terminal.
-        logger.removeHandler(streamHandler);               
-        streamHandler = new MonitoringApplicationStreamHandler(System.out);
-        streamHandler.setLevel(logger.getLevel());
-        logger.addHandler(streamHandler);
-        
-        logger.log(Level.INFO, "log messages redirected to terminal");
-        
-        // Update the model to indicate logging to file has been disabled.
-        configurationModel.setLogToFile(false);
-        
-        DialogUtil.showInfoDialog(frame, "Log to Terminal", "Log messages will be sent to the terminal.");
-    }    
-    
-    /**
-     * Start the AIDA server instance.
-     */
-    void startAIDAServer() {
-        if (configurationModel.hasValidProperty(ConfigurationModel.AIDA_SERVER_NAME_PROPERTY)) {
-            server.setName(configurationModel.getAIDAServerName());
-        }
-        boolean started = server.start();
-        if (started) {
-            frame.menu.startAIDAServer();
-            logger.info("AIDA server started at " + server.getName());
-            DialogUtil.showInfoDialog(frame, "AIDA Server Started", "The remote AIDA server started successfully.");
-        } else {
-            logger.warning("AIDA server failed to start");
-            DialogUtil.showErrorDialog(frame, "Failed to Start AIDA Server", "The remote AIDA server failed to start.");
-        }
-    }
-    
-    /**
-     * Stop the AIDA server instance.
-     */
-    void stopAIDAServer() {
-        server.disconnect();
-        frame.menu.stopAIDAServer();
-        logger.info("AIDA server was stopped");
-        DialogUtil.showInfoDialog(frame, "AIDA Server Stopped", "The AIDA server was stopped.");
-    }    
-    
-    /**
-     * Run the disconnection on a separate thread.
-     */
-    void runDisconnectThread() {
-        new Thread() {
-            public void run() {
-                logger.fine("disconnect thread is running ...");
-                connectionModel.setConnectionStatus(ConnectionStatus.DISCONNECTING);
-                MonitoringApplication.this.processing.stop();
-                logger.fine("disconnect thread finished!");
-            }
-        }.run();
-    }
-}
+        } catch (final IOException e) {
+            this.errorHandler.setError(e).setMessage("Failed to save screenshot.").printStackTrace().log()
+                    .showErrorDialog();
+        }
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java	Tue Apr 21 14:48:39 2015
@@ -2,6 +2,7 @@
 
 import java.awt.BorderLayout;
 import java.awt.Dimension;
+import java.awt.Frame;
 import java.awt.GraphicsEnvironment;
 import java.awt.Rectangle;
 
@@ -12,132 +13,283 @@
 
 /**
  * This class instantiates the primary GUI components of the monitoring application.
- * 
- * @author Jeremy McCormick <[log in to unmask]>
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 @SuppressWarnings("serial")
-class MonitoringApplicationFrame extends JFrame {
-            
-    EventDashboard dashboardPanel;    
-    PlotPanel plotPanel;
-    PlotInfoPanel plotInfoPanel;
-    LogPanel logPanel;
-    TriggerDiagnosticsPanel triggerPanel;
-    ConditionsPanel conditionsPanel;
-    SystemStatusPanel systemStatusPanel;
-    ToolbarPanel toolbarPanel;
-    MenuBar menu; 
-    
-    JSplitPane mainSplitPane;
-    JSplitPane rightSplitPane;
-    JSplitPane leftSplitPane;
-        
-    SettingsDialog settingsDialog;
-       
-    static final Rectangle BOUNDS = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
-    static final int PIXEL_WIDTH_MAX = (int) BOUNDS.getWidth();
-    static final int PIXEL_HEIGHT_MAX = (int) BOUNDS.getHeight();
-    
-    /**
-     * 
-     * @param listener
-     */
-    public MonitoringApplicationFrame(
-            MonitoringApplication application) {
-        
+final class MonitoringApplicationFrame extends JFrame {
+
+    /**
+     * The current graphics bounds.
+     */
+    private static final Rectangle BOUNDS = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
+
+    /**
+     * The maximum height of a window in pixels.
+     */
+    private static final int PIXEL_HEIGHT_MAX = (int) BOUNDS.getHeight();
+
+    /**
+     * The maximum width of a window in pixels.
+     */
+    private static final int PIXEL_WIDTH_MAX = (int) BOUNDS.getWidth();
+
+    /**
+     * The conditions panel.
+     */
+    private final ConditionsPanel conditionsPanel;
+
+    /**
+     * The dashboard panel.
+     */
+    private final EventDashboard dashboardPanel;
+
+    /**
+     * The left split pane that divides the dashboard and the tabs.
+     */
+    private final JSplitPane leftSplitPane;
+
+    /**
+     * The log panel.
+     */
+    private final LogPanel logPanel;
+
+    /**
+     * The primary split pain dividing the left and right panels.
+     */
+    private final JSplitPane mainSplitPane;
+
+    /**
+     * The application's menu bar.
+     */
+    private final MenuBar menu;
+
+    /**
+     * The plot info panel.
+     */
+    private final PlotInfoPanel plotInfoPanel;
+
+    /**
+     * The plot panel.
+     */
+    private final PlotPanel plotPanel;
+
+    /**
+     * The right split pane showing plots and statistics.
+     */
+    private final JSplitPane rightSplitPane;
+
+    /**
+     * The settings dialog window.
+     */
+    private final SettingsDialog settingsDialog;
+
+    /**
+     * The system status panel which shows under the tabs.
+     */
+    private final SystemStatusPanel systemStatusPanel;
+
+    /**
+     * The toolbar panel with the buttons, data source and connection information.
+     */
+    private final ToolbarPanel toolbarPanel;
+
+    /**
+     * The trigger diagnostics panel.
+     */
+    private final TriggerDiagnosticsPanel triggerPanel;
+
+    /**
+     * Class constructor.
+     *
+     * @param application the associated application object
+     */
+    public MonitoringApplicationFrame(final MonitoringApplication application) {
+
         // Disable interaction until specifically enabled externally after initialization.
-        setEnabled(false);
-                
+        this.setEnabled(false);
+
         // Create the content panel.
-        JPanel contentPanel = new JPanel();
-        setContentPane(contentPanel);
+        final JPanel contentPanel = new JPanel();
+        this.setContentPane(contentPanel);
         contentPanel.setLayout(new BorderLayout());
         contentPanel.setOpaque(true);
         contentPanel.setPreferredSize(new Dimension(PIXEL_WIDTH_MAX, PIXEL_HEIGHT_MAX));
-                
+
         // Create the top panel.
-        toolbarPanel = new ToolbarPanel(application.configurationModel, application.connectionModel, application);        
-        contentPanel.add(toolbarPanel, BorderLayout.NORTH);
-                        
+        this.toolbarPanel = new ToolbarPanel(application.getConfigurationModel(), application.getConnectionModel(),
+                application);
+        contentPanel.add(this.toolbarPanel, BorderLayout.NORTH);
+
         // Create the bottom panel.
-        JPanel bottomPanel = new JPanel();
+        final JPanel bottomPanel = new JPanel();
         bottomPanel.setLayout(new BorderLayout());
         contentPanel.add(bottomPanel, BorderLayout.CENTER);
-                                        
+
         // Create the left panel.
-        JPanel leftPanel = new JPanel();
+        final JPanel leftPanel = new JPanel();
         leftPanel.setLayout(new BorderLayout());
-                            
+
         // Create the run dashboard.
-        dashboardPanel = new EventDashboard(application.runModel);
+        this.dashboardPanel = new EventDashboard(application.getRunModel());
 
         // Create the tabbed pane for content in bottom of left panel such as log table and system monitor.
-        JTabbedPane tableTabbedPane = new JTabbedPane();
-        
+        final JTabbedPane tableTabbedPane = new JTabbedPane();
+
         // Create the log table and add it to the tabs.
-        logPanel = new LogPanel(application.configurationModel, application);
-        tableTabbedPane.addTab("Log Messages", logPanel);
-        
+        this.logPanel = new LogPanel(application.getConfigurationModel(), application);
+        tableTabbedPane.addTab("Log Messages", this.logPanel);
+
         // Create the system monitor.
-        //systemStatusTable = new SystemStatusTable();
-        systemStatusPanel = new SystemStatusPanel();
-        tableTabbedPane.addTab("System Status Monitor", systemStatusPanel);
-        
+        // systemStatusTable = new SystemStatusTable();
+        this.systemStatusPanel = new SystemStatusPanel();
+        tableTabbedPane.addTab("System Status Monitor", this.systemStatusPanel);
+
         // Add the trigger diagnostics tables.
-        triggerPanel = new TriggerDiagnosticsPanel();
-        tableTabbedPane.addTab("Trigger Diagnostics", triggerPanel);
-        
+        this.triggerPanel = new TriggerDiagnosticsPanel();
+        tableTabbedPane.addTab("Trigger Diagnostics", this.triggerPanel);
+
         // Add the conditions panel.
-        conditionsPanel = new ConditionsPanel();
-        tableTabbedPane.addTab("Detector Conditions", conditionsPanel);
-        
+        this.conditionsPanel = new ConditionsPanel();
+        tableTabbedPane.addTab("Detector Conditions", this.conditionsPanel);
+
         // Vertical split pane in left panel.
-        leftSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, dashboardPanel, tableTabbedPane);
-        leftSplitPane.setDividerLocation(250);
-        leftPanel.add(leftSplitPane, BorderLayout.CENTER);
-                                
+        this.leftSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, this.dashboardPanel, tableTabbedPane);
+        this.leftSplitPane.setDividerLocation(250);
+        leftPanel.add(this.leftSplitPane, BorderLayout.CENTER);
+
         // Create the right panel.
-        JPanel rightPanel = new JPanel();
+        final JPanel rightPanel = new JPanel();
         rightPanel.setLayout(new BorderLayout());
-                
+
         // Create the plot info panel.
-        plotInfoPanel = new PlotInfoPanel();
-                
+        this.plotInfoPanel = new PlotInfoPanel();
+
         // Create the plot panel.
-        plotPanel = new PlotPanel();        
-        plotInfoPanel.saveButton.addActionListener(plotPanel);
-        
+        this.plotPanel = new PlotPanel();
+        this.plotInfoPanel.addActionListener(this.plotPanel);
+
         // Create the right panel vertical split pane for displaying plots and their information and statistics.
-        rightSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, plotPanel, plotInfoPanel);
-        rightSplitPane.setDividerLocation(680);
-        rightPanel.add(rightSplitPane, BorderLayout.CENTER);
-                       
+        this.rightSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, this.plotPanel, this.plotInfoPanel);
+        this.rightSplitPane.setDividerLocation(680);
+        rightPanel.add(this.rightSplitPane, BorderLayout.CENTER);
+
         // Create the main horizontal split pane for dividing the left and right panels.
-        mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel);
-        mainSplitPane.setDividerLocation(600);
-        bottomPanel.add(mainSplitPane, BorderLayout.CENTER);
-        
+        this.mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel);
+        this.mainSplitPane.setDividerLocation(600);
+        bottomPanel.add(this.mainSplitPane, BorderLayout.CENTER);
+
         // Create the menu bar.
-        menu = new MenuBar(application.configurationModel, application.connectionModel, application);
-        setJMenuBar(menu);
-        toolbarPanel.dataSourceComboBox.addActionListener(menu);
-        
+        this.menu = new MenuBar(application.getConfigurationModel(), application.getConnectionModel(), application);
+        this.setJMenuBar(this.menu);
+        this.toolbarPanel.getDataSourceComboBox().addActionListener(this.menu);
+
         // Setup the settings dialog box (invisible until activated).
-        settingsDialog = new SettingsDialog(application.configurationModel, application);        
-               
-        // Setup the frame now that all components have been added.        
-        pack();
-        setExtendedState(JFrame.MAXIMIZED_BOTH);
-        setVisible(true); 
-    }
-             
+        this.settingsDialog = new SettingsDialog(application.getConfigurationModel(), application);
+
+        // Setup the frame now that all components have been added.
+        this.pack();
+        this.setExtendedState(Frame.MAXIMIZED_BOTH);
+        this.setVisible(true);
+    }
+
+    /**
+     * Get the application menu.
+     *
+     * @return the application menu
+     */
+    MenuBar getApplicationMenu() {
+        return this.menu;
+    }
+
+    /**
+     * Get the panel showing conditions information.
+     *
+     * @return the conditions panel
+     */
+    ConditionsPanel getConditionsPanel() {
+        return this.conditionsPanel;
+    }
+
+    /**
+     * Get the panel for the dashboard.
+     *
+     * @return the dashboard panel
+     */
+    EventDashboard getEventDashboard() {
+        return this.dashboardPanel;
+    }
+
+    /**
+     * Get the panel that shows the log table and controls.
+     *
+     * @return the log panel
+     */
+    LogPanel getLogPanel() {
+        return this.logPanel;
+    }
+
+    /**
+     * Get the plot info panel that shows plot statistics.
+     *
+     * @return the plot info panel
+     */
+    PlotInfoPanel getPlotInfoPanel() {
+        return this.plotInfoPanel;
+    }
+
+    /**
+     * Get the plot panel for displaying AIDA plots.
+     *
+     * @return the plot panel
+     */
+    PlotPanel getPlotPanel() {
+        return this.plotPanel;
+    }
+
+    /**
+     * Get the settings dialog window.
+     *
+     * @return the settings dialog window
+     */
+    SettingsDialog getSettingsDialog() {
+        return this.settingsDialog;
+    }
+
+    /**
+     * Get the system status panel.
+     *
+     * @return the system status panel
+     */
+    SystemStatusPanel getSystemStatusPanel() {
+        return this.systemStatusPanel;
+    }
+
+    /**
+     * Get the toolbar panel with the buttons etc.
+     *
+     * @return the toolbar panel
+     */
+    ToolbarPanel getToolbarPanel() {
+        return this.toolbarPanel;
+    }
+
+    /**
+     * Get the trigger diagnostics panel.
+     *
+     * @return the trigger diagnostics panel
+     */
+    TriggerDiagnosticsPanel getTriggerPanel() {
+        return this.triggerPanel;
+    }
+
     /**
      * Restore default window settings.
      */
     void restoreDefaults() {
-        setExtendedState(JFrame.MAXIMIZED_BOTH);
-        mainSplitPane.resetToPreferredSizes();
-        leftSplitPane.resetToPreferredSizes();
-        rightSplitPane.resetToPreferredSizes();        
-    }    
-}
+        this.setExtendedState(Frame.MAXIMIZED_BOTH);
+        this.mainSplitPane.resetToPreferredSizes();
+        this.leftSplitPane.resetToPreferredSizes();
+        this.rightSplitPane.resetToPreferredSizes();
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java	Tue Apr 21 14:48:39 2015
@@ -38,149 +38,284 @@
 
 /**
  * <p>
- * This is a GUI component for showing the statistics and other information about an AIDA plot
- * when it is clicked on in the monitoring application.
+ * This is a GUI component for showing the statistics and other information about an AIDA plot when it is clicked on in
+ * the monitoring application.
  * <p>
  * The information in the table is updated dynamically via the <code>AIDAObserver</code> API on the AIDA object.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class PlotInfoPanel extends JPanel implements AIDAListener, ActionListener, FunctionListener {
-
-    JComboBox<Object> plotComboBox;
-    JTable infoTable = new JTable();
-    DefaultTableModel model;
-    JButton saveButton;
-    
-    PlotterRegion currentRegion;
-    Object currentObject;
-    
-    static final int MAX_ROWS = 13;
-    static final int MIN_WIDTH = 400;
-    static final int MIN_HEIGHT = 300;
-    static final String[] COLUMN_NAMES = { "Field", "Value" };
-    static final String PLOT_SELECTED = "PlotSelected";
-
-    Timer timer = new Timer();
+@SuppressWarnings("serial")
+final class PlotInfoPanel extends JPanel implements AIDAListener, ActionListener, FunctionListener, AddActionListener {
+
+    /**
+     * The names of the two columns.
+     */
+    private static final String[] COLUMN_NAMES = {"Field", "Value"};
+
+    /**
+     * The maximum number of rows in the table.
+     */
+    private static final int MAX_ROWS = 13;
+
+    /**
+     * Minimum height of panel in pixels.
+     */
+    private static final int MIN_HEIGHT = 300;
+
+    /**
+     * Minimum width of panel in pixels.
+     */
+    private static final int MIN_WIDTH = 400;
+
+    /**
+     * The currently selected AIDA object.
+     */
+    private Object currentObject;
+
+    /**
+     * The currently selected plotter region.
+     */
+    private PlotterRegion currentRegion;
+
+    /**
+     * The table showing plot statistics.
+     */
+    private final JTable infoTable = new JTable();
+
+    /**
+     * The default table model.
+     */
+    private DefaultTableModel model;
+
+    /**
+     * The combo box for selecting the object from the region.
+     */
+    private JComboBox<Object> plotComboBox;
+
+    /**
+     * The button for saving plot graphics..
+     */
+    private JButton saveButton;
+
+    /**
+     * The timer for updating the table.
+     */
+    private final Timer timer = new Timer();
 
     /**
      * Class constructor, which will setup the GUI components.
      */
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings({"unchecked"})
     PlotInfoPanel() {
-                
-        setLayout(new FlowLayout(FlowLayout.CENTER));
-
-        JPanel leftPanel = new JPanel();
+
+        this.setLayout(new FlowLayout(FlowLayout.CENTER));
+
+        final JPanel leftPanel = new JPanel();
         leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.PAGE_AXIS));
         leftPanel.setPreferredSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
-        
-        Dimension filler = new Dimension(0, 10);
-        
+
+        final Dimension filler = new Dimension(0, 10);
+
         // Save button.
-        saveButton = new JButton("Save Plots ...");
-        saveButton.setActionCommand(Commands.SAVE_SELECTED_PLOTS);
-        saveButton.setAlignmentX(CENTER_ALIGNMENT);
-        leftPanel.add(saveButton);
-        
+        this.saveButton = new JButton("Save Current Plot Tab ...");
+        this.saveButton.setActionCommand(Commands.SAVE_SELECTED_PLOTS);
+        this.saveButton.setAlignmentX(CENTER_ALIGNMENT);
+        leftPanel.add(this.saveButton);
+
         leftPanel.add(new Box.Filler(filler, filler, filler));
 
         // Combo box for selecting plotted object.
-        plotComboBox = new JComboBox<Object>() {
+        this.plotComboBox = new JComboBox<Object>() {
+            @Override
             public Dimension getMaximumSize() {
-                Dimension max = super.getMaximumSize();
-                max.height = getPreferredSize().height;
+                final Dimension max = super.getMaximumSize();
+                max.height = this.getPreferredSize().height;
                 return max;
             }
         };
-        plotComboBox.setActionCommand(PLOT_SELECTED);
-        plotComboBox.setAlignmentX(CENTER_ALIGNMENT);
-        plotComboBox.setRenderer(new BasicComboBoxRenderer() {
+        this.plotComboBox.setActionCommand(Commands.PLOT_SELECTED);
+        this.plotComboBox.setAlignmentX(CENTER_ALIGNMENT);
+        this.plotComboBox.setRenderer(new BasicComboBoxRenderer() {
+            @Override
             @SuppressWarnings("rawtypes")
-            public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+            public Component getListCellRendererComponent(final JList list, final Object value, final int index,
+                    final boolean isSelected, final boolean cellHasFocus) {
                 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                 if (value != null) {
-                    String title = getObjectTitle(value);
-                    setText(value.getClass().getSimpleName() + " - " + title);
+                    final String title = PlotInfoPanel.this.getObjectTitle(value);
+                    this.setText(value.getClass().getSimpleName() + " - " + title);
                 } else {
-                    setText("Click on a plot region ...");
+                    this.setText("Click on a plot region ...");
                 }
                 return this;
             }
         });
-        plotComboBox.addActionListener(this);
-        leftPanel.add(plotComboBox);
-        
+        this.plotComboBox.addActionListener(this);
+        leftPanel.add(this.plotComboBox);
+
         leftPanel.add(new Box.Filler(filler, filler, filler));
-        
+
         // Table with plot info.
-        String data[][] = new String[0][0];
-        model = new DefaultTableModel(data, COLUMN_NAMES);
-        model.setColumnIdentifiers(COLUMN_NAMES);
-        infoTable.setModel(model);
-        ((DefaultTableModel)infoTable.getModel()).setRowCount(MAX_ROWS);
-        infoTable.setAlignmentX(CENTER_ALIGNMENT);
-        leftPanel.add(infoTable);
-        
-        add(leftPanel);
-    }
-
-    /**
-     * This method will be called when the backing AIDA object is updated and a state change is
-     * fired via the <code>AIDAObservable</code> API. The table is updated to reflect the new state
-     * of the object.
-     * @param evt The EventObject pointing to the backing AIDA object.
+        final String[][] data = new String[0][0];
+        this.model = new DefaultTableModel(data, COLUMN_NAMES);
+        this.model.setColumnIdentifiers(COLUMN_NAMES);
+        this.infoTable.setModel(this.model);
+        ((DefaultTableModel) this.infoTable.getModel()).setRowCount(MAX_ROWS);
+        this.infoTable.setAlignmentX(CENTER_ALIGNMENT);
+        leftPanel.add(this.infoTable);
+
+        this.add(leftPanel);
+    }
+
+    /**
+     * Implementation of <code>actionPerformed</code> to handle the selection of a new object from the combo box.
+     *
+     * @param e the {@link java.awt.event.ActionEvent} to handle
      */
     @Override
-    public void stateChanged(final EventObject evt) {
-               
-        // Make a timer task for running the update.
-        TimerTask task = new TimerTask() {
-            public void run() {
-                                
-                // Is the state change from the current AIDAObservable?
-                if (evt.getSource() != currentObject) {
-                    // Assume this means that a different AIDAObservable was selected in the GUI.
-                    return;
-                }
-
-                // Update the table values on the Swing EDT.
-                runUpdateTable();
-
-                // Set the observable to valid so subsequent state changes are received.
-                ((AIDAObservable) currentObject).setValid((AIDAListener) PlotInfoPanel.this);
-            }
-        };
-
-        /*
-         * Schedule the task to run in ~0.5 seconds. If the Runnable runs immediately, somehow the
-         * observable state gets permanently set to invalid and additional state changes will not be
-         * received!
-         */
-        timer.schedule(task, 500);
-    }
-
-    /**
-     * Implementation of <code>actionPerformed</code> to handle the selection of a new object from
-     * the combo box.
+    public void actionPerformed(final ActionEvent e) {
+        // Is there a new item selected in the combo box?
+        if (Commands.PLOT_SELECTED.equals(e.getActionCommand())) {
+            if (this.plotComboBox.getSelectedItem() != null) {
+                // Set the current object from the combo box value, to update the GUI state.
+                this.setCurrentObject(this.plotComboBox.getSelectedItem());
+            }
+        }
+    }
+
+    /**
+     * Assign an action listener to certain components.
+     *
+     * @param listener the action listener to add
      */
     @Override
-    public void actionPerformed(ActionEvent e) {
-        // Is there a new item selected in the combo box?
-        if (PLOT_SELECTED.equals(e.getActionCommand())) {
-            if (plotComboBox.getSelectedItem() != null) {
-                // Set the current object from the combo box value, to update the GUI state.
-                setCurrentObject(plotComboBox.getSelectedItem());
-            }
-        }
-    }
-
-    /**
-     * Get the title of an AIDA object.  Unfortunately there is no base type with this information,
-     * so it is read manually from each possible type.
-     * @param object The AIDA object.
-     * @return The title of the object from its title method or value of its toString method, if
-     *         none exists.
-     */
-    String getObjectTitle(Object object) {
+    public void addActionListener(final ActionListener listener) {
+        this.saveButton.addActionListener(listener);
+    }
+
+    /**
+     * Add this object as an <code>AIDAListener</code> on the current <code>AIDAObservable</code>.
+     */
+    private void addListener() {
+        if (this.currentObject instanceof AIDAObservable && !(this.currentObject instanceof FunctionDispatcher)) {
+            // Setup a listener on the current AIDA object.
+            final AIDAObservable observable = (AIDAObservable) this.currentObject;
+            observable.addListener(this);
+            observable.setValid(this);
+            observable.setConnected(true);
+        } else if (this.currentObject instanceof IFunction) {
+            if (this.currentObject instanceof FunctionDispatcher) {
+                ((FunctionDispatcher) this.currentObject).addFunctionListener(this);
+            }
+        }
+    }
+
+    /**
+     * Add a row to the info table.
+     *
+     * @param field the field name
+     * @param value the field value
+     */
+    private void addRow(final String field, final Object value) {
+        this.model.insertRow(this.infoTable.getRowCount(), new Object[] {field, value});
+    }
+
+    /**
+     * Add rows to the info table from the state of a 2D cloud.
+     *
+     * @param cloud the AIDA object
+     */
+    private void addRows(final ICloud2D cloud) {
+        this.addRow("title", cloud.title());
+        this.addRow("entries", cloud.entries());
+        this.addRow("max entries", cloud.maxEntries());
+        this.addRow("x lower edge", cloud.lowerEdgeX());
+        this.addRow("x upper edge", cloud.upperEdgeX());
+        this.addRow("y lower edge", cloud.lowerEdgeY());
+        this.addRow("y upper edge", cloud.upperEdgeY());
+        this.addRow("x mean", String.format("%.10f%n", cloud.meanX()));
+        this.addRow("y mean", String.format("%.10f%n", cloud.meanY()));
+        this.addRow("x rms", String.format("%.10f%n", cloud.rmsX()));
+        this.addRow("y rms", String.format("%.10f%n", cloud.rmsY()));
+    }
+
+    /**
+     * Add rows to the info table from the state of a function.
+     *
+     * @param function the AIDA function object
+     */
+    private void addRows(final IFunction function) {
+        this.addRow("title", function.title());
+
+        // Add generically the values of all function parameters.
+        for (final String parameter : function.parameterNames()) {
+            this.addRow(parameter, function.parameter(parameter));
+        }
+    }
+
+    /**
+     * Add rows to the info table from the state of a 1D histogram.
+     *
+     * @param histogram the AIDA object
+     */
+    private void addRows(final IHistogram1D histogram) {
+        this.addRow("title", histogram.title());
+        this.addRow("bins", histogram.axis().bins());
+        this.addRow("entries", histogram.entries());
+        this.addRow("mean", String.format("%.10f%n", histogram.mean()));
+        this.addRow("rms", String.format("%.10f%n", histogram.rms()));
+        this.addRow("sum bin heights", histogram.sumBinHeights());
+        this.addRow("max bin height", histogram.maxBinHeight());
+        this.addRow("overflow entries", histogram.binEntries(IAxis.OVERFLOW_BIN));
+        this.addRow("underflow entries", histogram.binEntries(IAxis.UNDERFLOW_BIN));
+    }
+
+    /**
+     * Add rows to the info table from the state of a 2D histogram.
+     *
+     * @param histogram the AIDA object
+     */
+    private void addRows(final IHistogram2D histogram) {
+        this.addRow("title", histogram.title());
+        this.addRow("x bins", histogram.xAxis().bins());
+        this.addRow("y bins", histogram.yAxis().bins());
+        this.addRow("entries", histogram.entries());
+        this.addRow("x mean", String.format("%.10f%n", histogram.meanX()));
+        this.addRow("y mean", String.format("%.10f%n", histogram.meanY()));
+        this.addRow("x rms", String.format("%.10f%n", histogram.rmsX()));
+        this.addRow("y rms", String.format("%.10f%n", histogram.rmsY()));
+        this.addRow("sum bin heights", histogram.sumBinHeights());
+        this.addRow("max bin height", histogram.maxBinHeight());
+        this.addRow("x overflow entries", histogram.binEntriesX(IAxis.OVERFLOW_BIN));
+        this.addRow("y overflow entries", histogram.binEntriesY(IAxis.OVERFLOW_BIN));
+        this.addRow("x underflow entries", histogram.binEntriesX(IAxis.UNDERFLOW_BIN));
+        this.addRow("y underflow entries", histogram.binEntriesY(IAxis.UNDERFLOW_BIN));
+    }
+
+    /**
+     * Callback for updating from changed to <code>IFunction</code> object.
+     *
+     * @param event the change event (unused in this method)
+     */
+    @Override
+    public void functionChanged(final FunctionChangedEvent event) {
+        try {
+            this.runUpdateTable();
+        } catch (final Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Get the title of an AIDA object. Unfortunately there is no base type with this information, so it is read
+     * manually from each possible type.
+     *
+     * @param object the AIDA object
+     * @return the title of the object from its title method or value of its <code>toString</code> method, if none
+     *         exists
+     */
+    private String getObjectTitle(final Object object) {
         if (object instanceof IBaseHistogram) {
             return ((IBaseHistogram) object).title();
         } else if (object instanceof IDataPointSet) {
@@ -193,226 +328,166 @@
     }
 
     /**
-     * Set the current plotter region, which will rebuild the GUI accordingly.
-     * @param region The current plotter region.
-     */
-    synchronized void setCurrentRegion(PlotterRegion region) {
-        if (region != currentRegion) {
-            currentRegion = region;
-            updateComboBox();
-            setCurrentObject(plotComboBox.getSelectedItem());
-            setupContentPane();
-        }
-    }
-
-    /**
-     * Configure the frame's content panel from current component settings.
-     */
-    void setupContentPane() {
-        plotComboBox.setSize(plotComboBox.getPreferredSize());
-        infoTable.setSize(infoTable.getPreferredSize());
-        setVisible(true);
-    }
-
-    /**
-     * Update the info table from the state of the current AIDA object.
-     */
-    void updateTable() {
-        model.setRowCount(0);        
-        if (currentObject instanceof IHistogram1D) {
-            addRows((IHistogram1D) currentObject);
-        } else if (currentObject instanceof IHistogram2D) {
-            addRows((IHistogram2D) currentObject);
-        } else if (currentObject instanceof ICloud2D) {
-            addRows((ICloud2D) currentObject);
-        } else if (currentObject instanceof ICloud1D) {
-            if (((ICloud1D) currentObject).isConverted()) {
-                addRows(((ICloud1D) currentObject).histogram());
-            }
-        } else if (currentObject instanceof IFunction) {
-            addRows((IFunction) currentObject);
-        }
-    }
-
-    /**
-     * Run the {@link #updateTable()} method on the Swing EDT.
-     */
-    void runUpdateTable() {
-        SwingUtilities.invokeLater(new Runnable() {
-            public void run() {
-                updateTable();
-            }
-        });
-    }
-
-    /**
-     * Update the combo box contents with the plots from the current region.
-     */
-    void updateComboBox() {
-        plotComboBox.removeAllItems();
-        List<Object> objects = currentRegion.getPlottedObjects();
-        for (Object object : objects) {
-            if (isValidObject(object)) {
-                plotComboBox.addItem(object);
-            }
-        }
-    }
-
-    boolean isValidObject(Object object) {
-        if (object == null)
+     * Return <code>true</code> if the object is a valid AIDA object.
+     *
+     * @param object the object
+     * @return <code>true</code> if object is a valid AIDA object
+     */
+    private boolean isValidObject(final Object object) {
+        if (object == null) {
             return false;
+        }
         if (object instanceof IBaseHistogram || object instanceof IFunction || object instanceof IDataPointSet) {
             return true;
-        } 
+        }
         return false;
     }
 
     /**
-     * Add rows to the info table from the state of a 1D histogram.
-     * @param histogram The AIDA object.
-     */
-    void addRows(IHistogram1D histogram) {
-        addRow("title", histogram.title());
-        addRow("bins", histogram.axis().bins());
-        addRow("entries", histogram.entries());
-        addRow("mean", String.format("%.10f%n", histogram.mean()));
-        addRow("rms", String.format("%.10f%n", histogram.rms()));
-        addRow("sum bin heights", histogram.sumBinHeights());
-        addRow("max bin height", histogram.maxBinHeight());
-        addRow("overflow entries", histogram.binEntries(IAxis.OVERFLOW_BIN));
-        addRow("underflow entries", histogram.binEntries(IAxis.UNDERFLOW_BIN));
-    }
-
-    /**
-     * Add rows to the info table from the state of a 2D histogram.
-     * @param histogram The AIDA object.
-     */
-    void addRows(IHistogram2D histogram) {
-        addRow("title", histogram.title());
-        addRow("x bins", histogram.xAxis().bins());
-        addRow("y bins", histogram.yAxis().bins());
-        addRow("entries", histogram.entries());
-        addRow("x mean", String.format("%.10f%n", histogram.meanX()));
-        addRow("y mean", String.format("%.10f%n", histogram.meanY()));
-        addRow("x rms", String.format("%.10f%n", histogram.rmsX()));
-        addRow("y rms", String.format("%.10f%n", histogram.rmsY()));
-        addRow("sum bin heights", histogram.sumBinHeights());
-        addRow("max bin height", histogram.maxBinHeight());
-        addRow("x overflow entries", histogram.binEntriesX(IAxis.OVERFLOW_BIN));
-        addRow("y overflow entries", histogram.binEntriesY(IAxis.OVERFLOW_BIN));
-        addRow("x underflow entries", histogram.binEntriesX(IAxis.UNDERFLOW_BIN));
-        addRow("y underflow entries", histogram.binEntriesY(IAxis.UNDERFLOW_BIN));
-    }
-
-    /**
-     * Add rows to the info table from the state of a 2D cloud.
-     * @param cloud The AIDA object.
-     */
-    void addRows(ICloud2D cloud) {
-        addRow("title", cloud.title());
-        addRow("entries", cloud.entries());
-        addRow("max entries", cloud.maxEntries());
-        addRow("x lower edge", cloud.lowerEdgeX());
-        addRow("x upper edge", cloud.upperEdgeX());
-        addRow("y lower edge", cloud.lowerEdgeY());
-        addRow("y upper edge", cloud.upperEdgeY());
-        addRow("x mean", String.format("%.10f%n", cloud.meanX()));
-        addRow("y mean", String.format("%.10f%n", cloud.meanY()));
-        addRow("x rms", String.format("%.10f%n", cloud.rmsX()));
-        addRow("y rms", String.format("%.10f%n", cloud.rmsY()));
-    }
-    
-    /**
-     * Add rows to the info table from the state of a 2D cloud.
-     * @param cloud The AIDA object.
-     */
-    void addRows(IFunction function) {
-        addRow("title", function.title());
-        
-        // Add generically the values of all function parameters.
-        for (String parameter : function.parameterNames()) {
-            addRow(parameter, function.parameter(parameter));
-        }
-    }
-    
-    /**
-     * Add a row to the info table.
-     * @param field The field name.
-     * @param value The field value.
-     */
-    void addRow(String field, Object value) {
-        model.insertRow(infoTable.getRowCount(), new Object[] { field, value });
-    }
-
-    /**
-     * Set the current AIDA object that backs this GUI, i.e. an IHistogram1D etc.
-     * @param object The backing AIDA object.
-     */
-    synchronized void setCurrentObject(Object object) {
-        
-        if (object == null)
+     * Remove this as a listener on the current AIDA object.
+     */
+    private void removeListener() {
+        if (this.currentObject != null) {
+            if (this.currentObject instanceof AIDAObservable && !(this.currentObject instanceof IFunction)) {
+                // Remove this object as an listener on the AIDA observable.
+                ((AIDAObservable) this.currentObject).removeListener(this);
+            } else if (this.currentObject instanceof FunctionDispatcher) {
+                // Remove this object as function listener.
+                ((FunctionDispatcher) this.currentObject).removeFunctionListener(this);
+            }
+        }
+    }
+
+    /**
+     * Run the {@link #updateTable()} method on the Swing EDT.
+     */
+    private void runUpdateTable() {
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                PlotInfoPanel.this.updateTable();
+            }
+        });
+    }
+
+    /**
+     * Set the current AIDA object that backs this GUI, i.e. an IHistogram1D or other plot object etc.
+     *
+     * @param object the backing AIDA object
+     */
+    private synchronized void setCurrentObject(final Object object) {
+
+        if (object == null) {
             throw new IllegalArgumentException("The object arg is null!");
-        
-        if (object == currentObject)
+        }
+
+        if (object == this.currentObject) {
             return;
+        }
 
         // Remove the AIDAListener from the previous object.
-        removeListener();
+        this.removeListener();
 
         // Set the current object reference.
-        currentObject = object;
+        this.currentObject = object;
 
         // Update the table immediately with information from the current object.
         // We need to wait for this the first time, so we know the preferred size
         // of the table GUI component when resizing the content pane.
-        updateTable();
+        this.updateTable();
 
         // Add an AIDAListener to the AIDA object via the AIDAObservable API.
-        addListener();
-    }
-
-    /**
-     * Remove this as a listener on the current AIDA object.
-     */
-    void removeListener() {
-        if (currentObject != null) {
-            if (currentObject instanceof AIDAObservable && !(currentObject instanceof IFunction)) {
-                // Remove this object as an listener on the AIDA observable.
-                ((AIDAObservable) currentObject).removeListener(this);
-            } else if (currentObject instanceof FunctionDispatcher) {
-                // Remove this object as function listener.
-                ((FunctionDispatcher)currentObject).removeFunctionListener(this);
-            }
-        }
-    }
-
-    /**
-     * Add this object as an <code>AIDAListener</code> on the current <code>AIDAObservable</code>.
-     */
-    void addListener() {
-        if (currentObject instanceof AIDAObservable && !(currentObject instanceof FunctionDispatcher)) {
-            // Setup a listener on the current AIDA object.
-            AIDAObservable observable = (AIDAObservable) currentObject;
-            observable.addListener(this);
-            observable.setValid(this);
-            observable.setConnected(true);
-        } else if (currentObject instanceof IFunction) {
-            if (currentObject instanceof FunctionDispatcher) {
-                ((FunctionDispatcher)currentObject).addFunctionListener(this);
-            }
-        }
-    }
-
-    /**
-     * Callback for updating from changed to <code>IFunction</code> object.
-     * @param event The change event (unused in this method).
+        this.addListener();
+    }
+
+    /**
+     * Set the current plotter region, which will rebuild the GUI accordingly.
+     *
+     * @param region The current plotter region.
+     */
+    synchronized void setCurrentRegion(final PlotterRegion region) {
+        if (region != this.currentRegion) {
+            this.currentRegion = region;
+            this.updateComboBox();
+            this.setCurrentObject(this.plotComboBox.getSelectedItem());
+            this.setupContentPane();
+        }
+    }
+
+    /**
+     * Configure the frame's content panel from current component settings.
+     */
+    private void setupContentPane() {
+        this.plotComboBox.setSize(this.plotComboBox.getPreferredSize());
+        this.infoTable.setSize(this.infoTable.getPreferredSize());
+        this.setVisible(true);
+    }
+
+    /**
+     * This method will be called when the backing AIDA object is updated and a state change is fired via the
+     * <code>AIDAObservable</code> API. The table is updated to reflect the new state of the object.
+     *
+     * @param evt the EventObject pointing to the backing AIDA object
      */
     @Override
-    public void functionChanged(FunctionChangedEvent event) {
-        try {
-            runUpdateTable();
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-}
+    public void stateChanged(final EventObject evt) {
+
+        // Make a timer task for running the update.
+        final TimerTask task = new TimerTask() {
+            @Override
+            public void run() {
+
+                // Is the state change from the current AIDAObservable?
+                if (evt.getSource() != PlotInfoPanel.this.currentObject) {
+                    // Assume this means that a different AIDAObservable was selected in the GUI.
+                    return;
+                }
+
+                // Update the table values on the Swing EDT.
+                PlotInfoPanel.this.runUpdateTable();
+
+                // Set the observable to valid so subsequent state changes are received.
+                ((AIDAObservable) PlotInfoPanel.this.currentObject).setValid(PlotInfoPanel.this);
+            }
+        };
+
+        /*
+         * Schedule the task to run in ~0.5 seconds. If the Runnable runs immediately, somehow the observable state gets
+         * permanently set to invalid and additional state changes will not be received!
+         */
+        this.timer.schedule(task, 500);
+    }
+
+    /**
+     * Update the combo box contents with the plots from the current region.
+     */
+    private void updateComboBox() {
+        this.plotComboBox.removeAllItems();
+        final List<Object> objects = this.currentRegion.getPlottedObjects();
+        for (final Object object : objects) {
+            if (this.isValidObject(object)) {
+                this.plotComboBox.addItem(object);
+            }
+        }
+    }
+
+    /**
+     * Update the info table from the state of the current AIDA object.
+     */
+    private void updateTable() {
+        this.model.setRowCount(0);
+        if (this.currentObject instanceof IHistogram1D) {
+            this.addRows((IHistogram1D) this.currentObject);
+        } else if (this.currentObject instanceof IHistogram2D) {
+            this.addRows((IHistogram2D) this.currentObject);
+        } else if (this.currentObject instanceof ICloud2D) {
+            this.addRows((ICloud2D) this.currentObject);
+        } else if (this.currentObject instanceof ICloud1D) {
+            if (((ICloud1D) this.currentObject).isConverted()) {
+                this.addRows(((ICloud1D) this.currentObject).histogram());
+            }
+        } else if (this.currentObject instanceof IFunction) {
+            this.addRows((IFunction) this.currentObject);
+        }
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/PlotPanel.java	Tue Apr 21 14:48:39 2015
@@ -6,83 +6,130 @@
 import java.awt.Component;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
 
+import javax.imageio.ImageIO;
 import javax.swing.JFileChooser;
 import javax.swing.JPanel;
 import javax.swing.JTabbedPane;
+import javax.swing.filechooser.FileNameExtensionFilter;
 
 import org.hps.monitoring.application.util.DialogUtil;
+import org.hps.monitoring.plotting.ExportPdf;
 import org.hps.monitoring.plotting.MonitoringPlotFactory;
 
 /**
  * This is the panel containing the tabs with the monitoring plots.
- * @author Jeremy McCormick <[log in to unmask]>
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class PlotPanel extends JPanel implements ActionListener {
-    
-    private JTabbedPane plotPane;    
-    
+@SuppressWarnings("serial")
+final class PlotPanel extends JPanel implements ActionListener {
+
+    /**
+     * The tabs containing the plots.
+     */
+    private final JTabbedPane plotPane;
+
+    /**
+     * Class constructor.
+     */
     public PlotPanel() {
-        setLayout(new BorderLayout());
-        plotPane = new JTabbedPane();
-        plotPane.setPreferredSize(getPreferredSize());
-        add(plotPane, BorderLayout.CENTER);
-    }
-    
-    JTabbedPane getPlotPane() {
-        return plotPane;
+        this.setLayout(new BorderLayout());
+        this.plotPane = new JTabbedPane();
+        this.plotPane.setPreferredSize(this.getPreferredSize());
+        this.add(this.plotPane, BorderLayout.CENTER);
     }
 
     /**
-     * Get the indices of the current selected tabs.
-     * @return The indices of the current tabs.
+     * Handle an {@link java.awt.event.ActionEvent}.
+     *
+     * @param event the {@link java.awt.event.ActionEvent} to handle
      */
-    int[] getSelectedTabs() {
-        int[] indices = new int[2];
-        indices[0] = plotPane.getSelectedIndex();
-        Component component = plotPane.getSelectedComponent();
-        if (component instanceof JTabbedPane) {
-            indices[1] = ((JTabbedPane)component).getSelectedIndex();
-        } 
-        return indices;
-    }
-    
-    public void actionPerformed(ActionEvent event) {
+    @Override
+    public void actionPerformed(final ActionEvent event) {
         if (event.getActionCommand().equals(Commands.SAVE_SELECTED_PLOTS)) {
-            int[] indices = getSelectedTabs();
-            IPlotter plotter = MonitoringPlotFactory.getPlotterRegistry().find(indices[0], indices[1]);
+            final int[] indices = this.getSelectedTabIndices();
+            final IPlotter plotter = MonitoringPlotFactory.getPlotterRegistry().find(indices[0], indices[1]);
             if (plotter != null) {
-                savePlotter(plotter);
+                this.savePlotter(plotter);
             } else {
                 DialogUtil.showErrorDialog(this, "Error Finding Plots", "No plots found in selected tab.");
             }
         }
     }
-            
-    static final String DEFAULT_FORMAT = "png";
-    void savePlotter(IPlotter plotter) {
-        JFileChooser fc = new JFileChooser();
+
+    /**
+     * Get the tabbed pane with the plots.
+     *
+     * @return the tabbed pane with the plots
+     */
+    JTabbedPane getPlotPane() {
+        return this.plotPane;
+    }
+
+    /**
+     * Get the currently selected plot tab.
+     *
+     * @return the currently selected plot tab
+     */
+    Component getSelectedTab() {
+        return ((JTabbedPane) this.plotPane.getSelectedComponent()).getSelectedComponent();
+    }
+
+    /**
+     * Get the indices of the current selected tabs.
+     *
+     * @return The indices of the current tabs.
+     */
+    private int[] getSelectedTabIndices() {
+        final int[] indices = new int[2];
+        indices[0] = this.plotPane.getSelectedIndex();
+        final Component component = this.plotPane.getSelectedComponent();
+        if (component instanceof JTabbedPane) {
+            indices[1] = ((JTabbedPane) component).getSelectedIndex();
+        }
+        return indices;
+    }
+
+    /**
+     * Remove all tabs from the plot pane.
+     */
+    void reset() {
+        this.plotPane.removeAll();
+    }
+
+    /**
+     * Save the plotter from a tab to a graphics file.
+     *
+     * @param plotter the plotter to save
+     */
+    private void savePlotter(final IPlotter plotter) {
+        final JFileChooser fc = new JFileChooser();
         fc.setAcceptAllFileFilterUsed(false);
         fc.setDialogTitle("Save Plots - " + plotter.title());
         fc.setCurrentDirectory(new File("."));
-        int r = fc.showSaveDialog(this);
-        if (r == JFileChooser.APPROVE_OPTION) {                        
+        fc.setAcceptAllFileFilterUsed(false);
+        fc.setFileFilter(new FileNameExtensionFilter("PNG file", "png"));
+        fc.addChoosableFileFilter(new FileNameExtensionFilter("JPG file", "jpg"));
+        fc.addChoosableFileFilter(new FileNameExtensionFilter("GIF file", "gif"));
+        final int r = fc.showSaveDialog(this);
+        if (r == JFileChooser.APPROVE_OPTION) {
             String path = fc.getSelectedFile().getPath();
-            if (path.lastIndexOf(".") == -1) {
-                path += "." + DEFAULT_FORMAT;
+            final FileNameExtensionFilter filter = (FileNameExtensionFilter) fc.getFileFilter();
+            if (!path.endsWith("." + filter.getExtensions()[0])) {
+                path += "." + filter.getExtensions()[0];
             }
+            final BufferedImage image = ExportPdf.getImage(this.getSelectedTab());
             try {
-                plotter.writeToFile(path);
-            } catch (IOException e) {
+                ImageIO.write(image, filter.getExtensions()[0], new File(path));
+                DialogUtil.showInfoDialog(this, "Plots Saved", "Plots from panel were saved to" + '\n' + path);
+            } catch (final IOException e) {
                 e.printStackTrace();
                 DialogUtil.showErrorDialog(this, "Error Saving Plots", "There was an error saving the plots.");
             }
-        }        
+        }
     }
-    
-    void reset() {
-        plotPane.removeAll();        
-    }    
-}
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsDialog.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsDialog.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsDialog.java	Tue Apr 21 14:48:39 2015
@@ -9,35 +9,50 @@
 import org.hps.monitoring.application.model.ConfigurationModel;
 
 /**
- * The modal dialog for entering settings. It contains a <code>JPanel</code> with the different
- * settings sub-tabs.
+ * The modal dialog for entering application settings.
+ * <p>
+ * It contains a <code>JPanel</code> with the different settings sub-tabs.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class SettingsDialog extends JDialog {
+@SuppressWarnings("serial")
+final class SettingsDialog extends JDialog {
 
-    final SettingsPanel settingsPanel;
+    /**
+     * The panel with the settings.
+     */
+    private final SettingsPanel settingsPanel;
 
-    public SettingsDialog(ConfigurationModel configurationModel, ActionListener listener) {
+    /**
+     * Class constructor.
+     *
+     * @param configurationModel the configuration model with global settings
+     * @param listener the action listener assigned to certain components
+     */
+    public SettingsDialog(final ConfigurationModel configurationModel, final ActionListener listener) {
 
         // Initialize the GUI panel.
-        settingsPanel = new SettingsPanel(this, configurationModel, listener);
-        
+        this.settingsPanel = new SettingsPanel(this, configurationModel, listener);
+
         // Configure the frame.
-        setTitle("Settings");
-        setContentPane(settingsPanel);
-        setResizable(false);
-        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
-        setModalityType(ModalityType.APPLICATION_MODAL);
-        pack();
+        this.setTitle("Settings");
+        this.setContentPane(this.settingsPanel);
+        this.setResizable(false);
+        this.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+        this.setModalityType(ModalityType.APPLICATION_MODAL);
+        this.pack();
 
         // Add window listener for turning invisible when closing.
-        addWindowListener(new WindowAdapter() {
-            public void windowClosing(WindowEvent e) {
-                setVisible(false);
+        this.addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowClosing(final WindowEvent e) {
+                SettingsDialog.this.setVisible(false);
             }
-            
-            public void windowOpened(WindowEvent event) {
-                SettingsDialog.this.setLocationRelativeTo(null);                    
+
+            @Override
+            public void windowOpened(final WindowEvent event) {
+                SettingsDialog.this.setLocationRelativeTo(null);
             }
-        });        
+        });
     }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SettingsPanel.java	Tue Apr 21 14:48:39 2015
@@ -16,54 +16,82 @@
 
 /**
  * The container component with the tabs that have job and connection settings.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class SettingsPanel extends JPanel implements ActionListener {
+@SuppressWarnings("serial")
+final class SettingsPanel extends JPanel implements ActionListener {
 
-    JTabbedPane tabs;
-    JobSettingsPanel jobPanel;
-    ConnectionSettingsPanel connectionPanel;
-    static final String OKAY_COMMAND = "settingsOkay";
+    /**
+     * The panel with connection settings.
+     */
+    private final ConnectionSettingsPanel connectionPanel;
 
-    JDialog parent;
+    /**
+     * The panel with general job settings.
+     */
+    private final JobSettingsPanel jobPanel;
 
-    SettingsPanel(JDialog parent, ConfigurationModel configurationModel, ActionListener listener) {
+    /**
+     * The parent dialog window.
+     */
+    private final JDialog parent;
+
+    /**
+     * The tabs with the sub-panels.
+     */
+    private final JTabbedPane tabs;
+
+    /**
+     * Class constructor.
+     *
+     * @param parent the parent dialog window
+     * @param configurationModel the global configuration model
+     * @param listener the action listener assigned to certain components
+     */
+    SettingsPanel(final JDialog parent, final ConfigurationModel configurationModel, final ActionListener listener) {
 
         this.parent = parent;
-        
-        connectionPanel = new ConnectionSettingsPanel();        
-        jobPanel = new JobSettingsPanel(configurationModel);
-        
+
+        this.connectionPanel = new ConnectionSettingsPanel();
+        this.jobPanel = new JobSettingsPanel(configurationModel);
+
         // Push configuration to sub-components.
-        connectionPanel.setConfigurationModel(configurationModel);
-        jobPanel.setConfigurationModel(configurationModel);
-        
+        this.connectionPanel.setConfigurationModel(configurationModel);
+        this.jobPanel.setConfigurationModel(configurationModel);
+
         // Add ActionListener to sub-components.
-        connectionPanel.addActionListener(listener);
-        jobPanel.addActionListener(listener);
-               
+        this.connectionPanel.addActionListener(listener);
+        this.jobPanel.addActionListener(listener);
+
         this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
 
-        tabs = new JTabbedPane();
-        tabs.addTab("Connection Settings", connectionPanel);
-        tabs.addTab("Job Settings", jobPanel);
-        add(tabs);
+        this.tabs = new JTabbedPane();
+        this.tabs.addTab("Connection Settings", this.connectionPanel);
+        this.tabs.addTab("Job Settings", this.jobPanel);
+        this.add(this.tabs);
 
-        JButton okayButton = new JButton("Okay");
-        okayButton.setActionCommand(OKAY_COMMAND);
+        final JButton okayButton = new JButton("Okay");
+        okayButton.setActionCommand(Commands.SETTINGS_OKAY_COMMAND);
         okayButton.addActionListener(this);
 
-        add(Box.createRigidArea(new Dimension(1, 5)));
-        JPanel buttonsPanel = new JPanel();
+        this.add(Box.createRigidArea(new Dimension(1, 5)));
+        final JPanel buttonsPanel = new JPanel();
         buttonsPanel.add(okayButton);
         buttonsPanel.setLayout(new FlowLayout());
-        add(buttonsPanel);
-        add(Box.createRigidArea(new Dimension(1, 5)));
+        this.add(buttonsPanel);
+        this.add(Box.createRigidArea(new Dimension(1, 5)));
     }
 
+    /**
+     * Handle action events.
+     *
+     * @param e the action event to handle
+     */
     @Override
-    public void actionPerformed(ActionEvent e) {
-        if (e.getActionCommand().equals(OKAY_COMMAND)) {
-            parent.setVisible(false);
+    public void actionPerformed(final ActionEvent e) {
+        if (e.getActionCommand().equals(Commands.SETTINGS_OKAY_COMMAND)) {
+            this.parent.setVisible(false);
         }
-    }    
+    }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java	Tue Apr 21 14:48:39 2015
@@ -1,6 +1,3 @@
-/**
- * 
- */
 package org.hps.monitoring.application;
 
 import java.awt.Component;
@@ -22,125 +19,190 @@
 
 /**
  * This is a table that shows every system status change in a different row.
- * 
- * @author Jeremy McCormick <[log in to unmask]>
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-public class SystemStatusEventsTable extends JTable {
-    
-    SystemStatusEventsTableModel tableModel = new SystemStatusEventsTableModel();
-    
+@SuppressWarnings("serial")
+final class SystemStatusEventsTable extends JTable {
+
+    /**
+     * The model for the system status events table.
+     */
+    static class SystemStatusEventsTableModel extends DefaultTableModel implements SystemStatusListener {
+
+        /**
+         * The classes of the table columns.
+         */
+        private final Class<?>[] columnClasses = {Date.class, Subsystem.class, SystemStatus.class, String.class,
+                String.class};
+
+        /**
+         * The names of the columns.
+         */
+        private final String[] columnNames = {"Date", "Subsystem", "Status Code", "Description", "Message"};
+
+        /**
+         * The list of statuses shown in the table.
+         */
+        private final List<SystemStatus> statuses = new ArrayList<SystemStatus>();
+
+        /**
+         * Class constructor.
+         */
+        SystemStatusEventsTableModel() {
+        }
+
+        /**
+         * Register the listener on this status.
+         *
+         * @param status the system status
+         */
+        void addSystemStatus(final SystemStatus status) {
+            status.addListener(this);
+        }
+
+        /**
+         * Clear all the records from the table.
+         */
+        void clear() {
+            this.statuses.clear();
+            this.setRowCount(0);
+        }
+
+        /**
+         * Get the column class.
+         *
+         * @param columnIndex the column index
+         */
+        @Override
+        public Class<?> getColumnClass(final int columnIndex) {
+            return this.columnClasses[columnIndex];
+        }
+
+        /**
+         * Get the column count.
+         *
+         * @return the column count
+         */
+        @Override
+        public int getColumnCount() {
+            return this.columnNames.length;
+        }
+
+        /**
+         * Get the column name.
+         *
+         * @param columnIndex the column index
+         */
+        @Override
+        public String getColumnName(final int columnIndex) {
+            return this.columnNames[columnIndex];
+        }
+
+        /**
+         * Get the row count.
+         *
+         * @return the row count
+         */
+        @Override
+        public int getRowCount() {
+            if (this.statuses != null) {
+                return this.statuses.size();
+            } else {
+                return 0;
+            }
+        }
+
+        /**
+         * Get a cell value from the table.
+         *
+         * @param rowIndex the row index
+         * @param columnIndex the column index
+         * @return the cell value at the rowIndex and columnIndex
+         */
+        @Override
+        public Object getValueAt(final int rowIndex, final int columnIndex) {
+            final SystemStatus status = this.statuses.get(rowIndex);
+            switch (columnIndex) {
+            case 0:
+                return new Date(status.getLastChangedMillis());
+            case 1:
+                return status.getSubsystem();
+            case 2:
+                return status.getStatusCode();
+            case 3:
+                return status.getDescription();
+            case 4:
+                return status.getMessage();
+            default:
+                return null;
+            }
+        }
+
+        /**
+         * Update the table with status changes.
+         *
+         * @param status the system status
+         */
+        @Override
+        public void statusChanged(final SystemStatus status) {
+            final SystemStatus newStatus = new SystemStatusImpl(status);
+            this.statuses.add(newStatus);
+            this.fireTableDataChanged();
+        }
+    }
+
+    /**
+     * The table model.
+     */
+    private final SystemStatusEventsTableModel tableModel = new SystemStatusEventsTableModel();
+
+    /**
+     * Class constructor.
+     */
     SystemStatusEventsTable() {
-        setModel(tableModel);
-        
+        this.setModel(this.tableModel);
+
         // Date formatting.
-        getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
+        this.getColumnModel().getColumn(0).setCellRenderer(new DefaultTableCellRenderer() {
 
             final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS");
 
             @Override
-            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+            public Component getTableCellRendererComponent(final JTable table, Object value, final boolean isSelected,
+                    final boolean hasFocus, final int row, final int column) {
                 if (value instanceof Date) {
-                    value = dateFormat.format(value);
+                    value = this.dateFormat.format(value);
                 }
                 return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
             }
         });
-        
+
         // Rendering of system status cells using different background colors.
-        getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() {
+        this.getColumnModel().getColumn(2).setCellRenderer(new DefaultTableCellRenderer() {
 
             @Override
-            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
+            public Component getTableCellRendererComponent(final JTable table, final Object value,
+                    final boolean isSelected, final boolean hasFocus, final int row, final int col) {
 
                 // Cells are by default rendered as a JLabel.
-                JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
+                final JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
+                        row, col);
 
                 // Color code the cell by its status.
-                StatusCode statusCode = (StatusCode) value;
+                final StatusCode statusCode = (StatusCode) value;
                 label.setBackground(statusCode.getColor());
                 return label;
             }
         });
     }
-    
-    void registerListener() {
+
+    /**
+     * Get the system status events table model.
+     *
+     * @return the system status events table model
+     */
+    SystemStatusEventsTableModel getSystemStatusEventsTableModel() {
+        return this.tableModel;
     }
-    
-    static class SystemStatusEventsTableModel extends DefaultTableModel implements SystemStatusListener {
-        
-        List<SystemStatus> statuses = new ArrayList<SystemStatus>();
-        
-        String[] columnNames = { "Date", "Subsystem", "Status Code", "Description", "Message" };
-        Class<?>[] columnClasses = { Date.class, Subsystem.class, SystemStatus.class, String.class, String.class };
-
-        SystemStatusEventsTableModel() {
-        }
-        
-        @Override
-        public String getColumnName(int column) {
-            return columnNames[column];
-        }
-        
-        @Override
-        public Class<?> getColumnClass(int column) {
-            return columnClasses[column];
-        }
-
-        /**
-         * Update the table with status changes.
-         * @param status The system status.
-         */
-        @Override
-        public void statusChanged(SystemStatus status) {
-            SystemStatus newStatus = new SystemStatusImpl(status);
-            statuses.add(newStatus);
-            fireTableDataChanged();
-        }
-        
-        /**
-         * Register the listener on this status.
-         * @param status The system status.
-         */
-        void addSystemStatus(SystemStatus status) {
-            status.addListener(this);
-        }
-        
-        @Override
-        public int getColumnCount() {
-            return columnNames.length;
-        }
-        
-        @Override
-        public int getRowCount() {
-            if (statuses != null) {
-                return statuses.size();
-            } else {
-                return 0;
-            }
-        }
-        
-        @Override
-        public Object getValueAt(int row, int column) {
-            SystemStatus status = statuses.get(row);
-            switch (column) {
-                case 0:
-                    return new Date(status.getLastChangedMillis());
-                case 1:
-                    return status.getSubsystem();
-                case 2:
-                    return status.getStatusCode();
-                case 3:
-                    return status.getDescription();
-                case 4: 
-                    return status.getMessage();
-                default:
-                    return null;
-            }
-        }
-        
-        public void clear() {
-            this.statuses.clear();
-            this.setRowCount(0);
-        }
-    }    
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java	Tue Apr 21 14:48:39 2015
@@ -1,5 +1,5 @@
 /**
- * 
+ *
  */
 package org.hps.monitoring.application;
 
@@ -13,39 +13,54 @@
 import org.hps.monitoring.subsys.SystemStatus;
 
 /**
- * This is a panel showing the two tables for viewing the system statuses,
- * one showing the current state of all system status monitors and the other
- * all system status change events.
- * 
- * @author Jeremy McCormick <[log in to unmask]>
+ * This is a panel showing the two tables for viewing the system statuses, one showing the current state of all system
+ * status monitors and the other with all system status change events.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-public class SystemStatusPanel extends JPanel {
-    
-    SystemStatusTable statusTable = new SystemStatusTable();
-    SystemStatusEventsTable eventsTable = new SystemStatusEventsTable();
-        
-    SystemStatusPanel() {         
+@SuppressWarnings("serial")
+final class SystemStatusPanel extends JPanel {
+
+    /**
+     * The system status events table.
+     */
+    private final SystemStatusEventsTable eventsTable = new SystemStatusEventsTable();
+
+    /**
+     * The system status table.
+     */
+    private final SystemStatusTable statusTable = new SystemStatusTable();
+
+    /**
+     * Class constructor.
+     */
+    SystemStatusPanel() {
         super(new BorderLayout());
-        JSplitPane splitPane = new JSplitPane(
-                JSplitPane.VERTICAL_SPLIT, 
-                new JScrollPane(statusTable), 
-                new JScrollPane(eventsTable));
+        final JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(this.statusTable),
+                new JScrollPane(this.eventsTable));
         splitPane.setDividerLocation(50);
-        add(splitPane,
-            BorderLayout.CENTER);
-    }   
-    
-    void addSystemStatus(SystemStatus status) {
+        this.add(splitPane, BorderLayout.CENTER);
+    }
+
+    /**
+     * Add a system status.
+     *
+     * @param status the system status to add
+     */
+    void addSystemStatus(final SystemStatus status) {
         // Register listeners of table models on this status.
-        statusTable.getTableModel().addSystemStatus(status);        
-        eventsTable.tableModel.addSystemStatus(status);
+        this.statusTable.getTableModel().addSystemStatus(status);
+        this.eventsTable.getSystemStatusEventsTableModel().addSystemStatus(status);
     }
-    
+
+    /**
+     * Clear all the table records.
+     */
     void clear() {
         // Clear the system status monitor table.
-        statusTable.getTableModel().clear();    
+        this.statusTable.getTableModel().clear();
 
         // Clear the system status events table.
-        ((SystemStatusEventsTableModel)eventsTable.getModel()).clear();
+        ((SystemStatusEventsTableModel) this.eventsTable.getModel()).clear();
     }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusTable.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusTable.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusTable.java	Tue Apr 21 14:48:39 2015
@@ -17,102 +17,152 @@
 
 /**
  * This table shows the current state of {@link org.hps.monitoring.subsys.SystemStatus} objects.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class SystemStatusTable extends JTable {
-
-    SystemStatusTable() {
-
-        setModel(new SystemStatusTableModel());
-
-        // Rendering of system status cells using different background colors.
-        getColumnModel().getColumn(SystemStatusTableModel.STATUS_COL).setCellRenderer(new DefaultTableCellRenderer() {
-
-            @Override
-            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
-
-                // Cells are by default rendered as a JLabel.
-                JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
-
-                // Color code the cell by its status.
-                StatusCode statusCode = StatusCode.valueOf((String) value);
-                label.setBackground(statusCode.getColor());
-                return label;
-            }
-        });
-
-        // Date formatting for last changed.
-        getColumnModel().getColumn(SystemStatusTableModel.LAST_CHANGED_COL).setCellRenderer(new DefaultTableCellRenderer() {
-
-            final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS");
-
-            @Override
-            public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-                if (value instanceof Date) {
-                    value = dateFormat.format(value);
-                }
-                return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
-            }
-        });
-
-        // Button for clearing system statuses.
-        getColumnModel().getColumn(SystemStatusTableModel.RESET_COL).setCellRenderer(new ButtonRenderer("Clear"));
-        addMouseListener(new JTableButtonMouseListener(this));
-        getColumn("Clearable").setWidth(0);
-        getColumn("Clearable").setMinWidth(0);
-        getColumn("Clearable").setMaxWidth(0);
-
-        // Column widths.
-        getColumnModel().getColumn(SystemStatusTableModel.ACTIVE_COL).setPreferredWidth(8);
-        getColumnModel().getColumn(SystemStatusTableModel.STATUS_COL).setPreferredWidth(10);
-        getColumnModel().getColumn(SystemStatusTableModel.SYSTEM_COL).setPreferredWidth(10);
-        // TODO: Add default width setting for every column.
-
-        setAutoCreateRowSorter(true);
-    }
-
-    public SystemStatusTableModel getTableModel() {
-        return (SystemStatusTableModel) getModel();
-    }
+@SuppressWarnings("serial")
+final class SystemStatusTable extends JTable {
 
     /**
-     * Renders a button if the status is clearable.
+     * Renders a button if the status is clear-able.
      */
     private class ButtonRenderer extends JButton implements TableCellRenderer {
 
-        public ButtonRenderer(String label) {
+        /**
+         * Class constructor.
+         *
+         * @param label the label of the button
+         */
+        public ButtonRenderer(final String label) {
             this.setText(label);
         }
 
-        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-            boolean clearable = (Boolean) table.getModel().getValueAt(row, SystemStatusTableModel.CLEARABLE_COL);
-            if (clearable)
+        /**
+         * Get the renderer for the table cell.
+         *
+         * @param table the table
+         * @param value the object from the table cell
+         * @param isSelected <code>true</code> if cell is selected
+         * @param hasFocus <code>true</code> if cell has focus
+         * @param rowIndex the row index
+         * @param columnIndex the column index
+         */
+        @Override
+        public Component getTableCellRendererComponent(final JTable table, final Object value,
+                final boolean isSelected, final boolean hasFocus, final int rowIndex, final int columnIndex) {
+            final boolean clearable = (Boolean) table.getModel().getValueAt(rowIndex,
+                    SystemStatusTableModel.CLEARABLE_COLUMN_INDEX);
+            if (clearable) {
                 return this;
-            else
+            } else {
                 return null;
+            }
         }
     }
 
     /**
-     * Fires a mouse click event when the clear button is pressed, which in turn will activate the
-     * action event for the button. The <code>ActionListener</code> then sets the
-     * <code>StatusCode</code> to <code>CLEARED</code>.
+     * Fires a mouse click event when the clear button is pressed, which in turn will activate the action event for the
+     * button. The <code>ActionListener</code> then sets the <code>StatusCode</code> to <code>CLEARED</code>.
      */
     private static class JTableButtonMouseListener extends MouseAdapter {
+
+        /**
+         * The table.
+         */
         private final JTable table;
 
-        public JTableButtonMouseListener(JTable table) {
+        /**
+         * Class constructor.
+         *
+         * @param table the table for the listener
+         */
+        public JTableButtonMouseListener(final JTable table) {
             this.table = table;
         }
 
-        public void mouseClicked(MouseEvent e) {
-            int column = table.getColumnModel().getColumnIndexAtX(e.getX());
-            int row = e.getY() / table.getRowHeight();
-            if (row < table.getRowCount() && row >= 0 && column < table.getColumnCount() && column >= 0) {
-                Object value = table.getValueAt(row, column);
+        /**
+         * Implement mouse clicked action.
+         *
+         * @param e the mouse event
+         */
+        @Override
+        public void mouseClicked(final MouseEvent e) {
+            final int column = this.table.getColumnModel().getColumnIndexAtX(e.getX());
+            final int row = e.getY() / this.table.getRowHeight();
+            if (row < this.table.getRowCount() && row >= 0 && column < this.table.getColumnCount() && column >= 0) {
+                final Object value = this.table.getValueAt(row, column);
                 if (value instanceof JButton) {
                     ((JButton) value).doClick();
                 }
             }
         }
     }
-}
+
+    /**
+     * Class constructor.
+     */
+    SystemStatusTable() {
+
+        this.setModel(new SystemStatusTableModel());
+
+        // Rendering of system status cells using different background colors.
+        this.getColumnModel().getColumn(SystemStatusTableModel.STATUS_COLUMN_INDEX)
+                .setCellRenderer(new DefaultTableCellRenderer() {
+
+                    @Override
+                    public Component getTableCellRendererComponent(final JTable table, final Object value,
+                            final boolean isSelected, final boolean hasFocus, final int row, final int col) {
+
+                        // Cells are by default rendered as a JLabel.
+                        final JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected,
+                                hasFocus, row, col);
+
+                        // Color code the cell by its status.
+                        final StatusCode statusCode = StatusCode.valueOf((String) value);
+                        label.setBackground(statusCode.getColor());
+                        return label;
+                    }
+                });
+
+        // Date formatting for last changed.
+        this.getColumnModel().getColumn(SystemStatusTableModel.LAST_CHANGED_COLUMN_INDEX)
+                .setCellRenderer(new DefaultTableCellRenderer() {
+
+                    final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS");
+
+                    @Override
+                    public Component getTableCellRendererComponent(final JTable table, Object value,
+                            final boolean isSelected, final boolean hasFocus, final int row, final int column) {
+                        if (value instanceof Date) {
+                            value = this.dateFormat.format(value);
+                        }
+                        return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
+                    }
+                });
+
+        // Button for clearing system statuses.
+        this.getColumnModel().getColumn(SystemStatusTableModel.RESET_COLUMN_INDEX)
+                .setCellRenderer(new ButtonRenderer("Clear"));
+        this.addMouseListener(new JTableButtonMouseListener(this));
+        this.getColumn("Clearable").setWidth(0);
+        this.getColumn("Clearable").setMinWidth(0);
+        this.getColumn("Clearable").setMaxWidth(0);
+
+        // Column widths.
+        this.getColumnModel().getColumn(SystemStatusTableModel.ACTIVE_COLUMN_INDEX).setPreferredWidth(8);
+        this.getColumnModel().getColumn(SystemStatusTableModel.STATUS_COLUMN_INDEX).setPreferredWidth(10);
+        this.getColumnModel().getColumn(SystemStatusTableModel.SYSTEM_COLUMN_INDEX).setPreferredWidth(10);
+        // TODO: Add default width setting for every column.
+
+        this.setAutoCreateRowSorter(true);
+    }
+
+    /**
+     * Get the tqble model.
+     *
+     * @return the table model
+     */
+    public SystemStatusTableModel getTableModel() {
+        return (SystemStatusTableModel) this.getModel();
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ToolbarPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ToolbarPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ToolbarPanel.java	Tue Apr 21 14:48:39 2015
@@ -13,21 +13,37 @@
 
 /**
  * A GUI component for the top-level toolbar of the monitoring app.
- * 
- * @author Jeremy McCormick <[log in to unmask]>
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-public class ToolbarPanel extends JPanel {
+@SuppressWarnings("serial")
+final class ToolbarPanel extends JPanel {
 
-    DataSourceComboBox dataSourceComboBox;
-    JPanel buttonsPanel;
+    /**
+     * The panel with the buttons.
+     */
+    private final JPanel buttonsPanel;
 
-    ToolbarPanel(ConfigurationModel configurationModel, ConnectionStatusModel connectionModel, ActionListener listener) {
+    /**
+     * The combo box with the list of data sources.
+     */
+    private final DataSourceComboBox dataSourceComboBox;
 
-        setLayout(new FlowLayout(FlowLayout.LEFT));
-        
-        JPanel containerPanel = new JPanel();
+    /**
+     * Class constructor.
+     *
+     * @param configurationModel the configuration model for the application
+     * @param connectionModel the connection status model
+     * @param listener the action listener to assign to certain components
+     */
+    ToolbarPanel(final ConfigurationModel configurationModel, final ConnectionStatusModel connectionModel,
+            final ActionListener listener) {
+
+        this.setLayout(new FlowLayout(FlowLayout.LEFT));
+
+        final JPanel containerPanel = new JPanel();
         containerPanel.setLayout(new GridBagLayout());
-        
+
         // Create the connection status panel.
         GridBagConstraints gbs = new GridBagConstraints();
         gbs.anchor = GridBagConstraints.WEST;
@@ -36,30 +52,38 @@
         gbs.weightx = 0.5;
         gbs.fill = GridBagConstraints.BOTH;
         gbs.insets = new Insets(10, 0, 0, 10);
-        JPanel connectionPanel = new ConnectionStatusPanel(connectionModel);
+        final JPanel connectionPanel = new ConnectionStatusPanel(connectionModel);
         containerPanel.add(connectionPanel, gbs);
 
         // Create the buttons panel.
-        buttonsPanel = new EventButtonsPanel(connectionModel, listener);
+        this.buttonsPanel = new EventButtonsPanel(connectionModel, listener);
         gbs.anchor = GridBagConstraints.WEST;
         gbs.gridx = 1;
         gbs.gridy = 0;
         gbs.weightx = 0.5;
         gbs.fill = GridBagConstraints.BOTH;
         gbs.insets = new Insets(0, 0, 0, 10);
-        containerPanel.add(buttonsPanel, gbs);
+        containerPanel.add(this.buttonsPanel, gbs);
 
         // Add the data source combo box.
-        dataSourceComboBox = new DataSourceComboBox(configurationModel, connectionModel);
+        this.dataSourceComboBox = new DataSourceComboBox(configurationModel, connectionModel);
         gbs = new GridBagConstraints();
         gbs.anchor = GridBagConstraints.WEST;
         gbs.gridx = 2;
         gbs.gridy = 0;
         gbs.weightx = 1.0;
         gbs.fill = GridBagConstraints.HORIZONTAL;
-        containerPanel.add(dataSourceComboBox, gbs);
-        
-        add(containerPanel);
+        containerPanel.add(this.dataSourceComboBox, gbs);
+
+        this.add(containerPanel);
     }
 
+    /**
+     * Get the combo box with the data sources
+     *
+     * @return the combo box with the data sources
+     */
+    DataSourceComboBox getDataSourceComboBox() {
+        return this.dataSourceComboBox;
+    }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/TriggerDiagnosticsPanel.java	Tue Apr 21 14:48:39 2015
@@ -7,7 +7,7 @@
 import javax.swing.JPanel;
 import javax.swing.JTabbedPane;
 
-import org.hps.analysis.trigger.DiagSnapshot;
+import org.hps.analysis.trigger.data.DiagnosticSnapshot;
 import org.hps.monitoring.trigger.ClusterTablePanel;
 import org.hps.monitoring.trigger.DiagnosticUpdatable;
 import org.hps.monitoring.trigger.EfficiencyTablePanel;
@@ -18,63 +18,94 @@
 
 /**
  * This is a panel containing the trigger diagnostics tables.
- * 
- * @author Jeremy McCormick <[log in to unmask]>
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-class TriggerDiagnosticsPanel extends JPanel {
+@SuppressWarnings("serial")
+final class TriggerDiagnosticsPanel extends JPanel {
 
-    JTabbedPane tabs = new JTabbedPane();
-    ClusterTablePanel clusterPanel = new ClusterTablePanel();
-    SinglesTablePanel singlesPanel = new SinglesTablePanel();
-    PairTablePanel pairsPanel = new PairTablePanel();
-    EfficiencyTablePanel efficiencyPanel = new EfficiencyTablePanel();
-    
-    List<DiagnosticUpdatable> updateList = new ArrayList<DiagnosticUpdatable>();
-    
-    TriggerDiagnosticsPanel() {
-        setLayout(new BorderLayout());
-                       
-        tabs.addTab("Clusters", clusterPanel);
-        tabs.addTab("Singles", singlesPanel);
-        tabs.addTab("Pairs", pairsPanel);
-        tabs.addTab("Efficiency", efficiencyPanel);
-        
-        updateList.add(clusterPanel);
-        updateList.add(singlesPanel);
-        updateList.add(pairsPanel);
-        updateList.add(efficiencyPanel);
-        
-        add(tabs, BorderLayout.CENTER);
-    }
-        
     /**
      * Driver for updating the tables.
      */
     class TriggerDiagnosticGUIDriver extends Driver {
 
-        // FIXME: Hard-coded collection name.
+        /**
+         * Default name of trigger diagnostics collection.
+         */
         private String diagnosticCollectionName = "DiagnosticSnapshot";
-        
+
         @Override
-        public void process(EventHeader event) {
+        public void process(final EventHeader event) {
             // Updates are only performed if a diagnostic snapshot object
             // exists. Otherwise, do nothing.
-            if(event.hasCollection(DiagSnapshot.class, diagnosticCollectionName)) {
+            if (event.hasCollection(DiagnosticSnapshot.class, this.diagnosticCollectionName)) {
                 // Get the snapshot collection.
-                List<DiagSnapshot> snapshotList = event.get(DiagSnapshot.class, diagnosticCollectionName);
-                
-                // Get the snapshot. There will only ever be one.
-                DiagSnapshot snapshot = snapshotList.get(0);
-                
+                final List<DiagnosticSnapshot> snapshotList = event.get(DiagnosticSnapshot.class,
+                        this.diagnosticCollectionName);
+
                 // Update the GUI panels.
-                for (DiagnosticUpdatable update : updateList) {
-                    update.updatePanel(snapshot);
+                for (final DiagnosticUpdatable update : TriggerDiagnosticsPanel.this.updateList) {
+                    update.updatePanel(snapshotList.get(1), snapshotList.get(0));
                 }
-            } 
+            }
         }
-        
-        void setDiagnosticCollectionName(String name) {
-            diagnosticCollectionName = name;
+
+        /**
+         * Set the name of the trigger diagnostics collection.
+         *
+         * @param name the name of the trigger diagnostics collection
+         */
+        void setDiagnosticCollectionName(final String name) {
+            this.diagnosticCollectionName = name;
         }
-    }  
+    }
+
+    /**
+     * The panel with cluster statistics.
+     */
+    private final ClusterTablePanel clusterPanel = new ClusterTablePanel();
+
+    /**
+     * The panel with efficiency statistics.
+     */
+    private final EfficiencyTablePanel efficiencyPanel = new EfficiencyTablePanel();
+
+    /**
+     * The panel with pairs statistics.
+     */
+    private final PairTablePanel pairsPanel = new PairTablePanel();
+
+    /**
+     * The panel with singles statistics.
+     */
+    private final SinglesTablePanel singlesPanel = new SinglesTablePanel();
+
+    /**
+     * The tabs containing the statistics panels.
+     */
+    private final JTabbedPane tabs = new JTabbedPane();
+
+    /**
+     * The list of objects that can be updated with trigger diagnostics.
+     */
+    private final List<DiagnosticUpdatable> updateList = new ArrayList<DiagnosticUpdatable>();
+
+    /**
+     * Class constructor.
+     */
+    TriggerDiagnosticsPanel() {
+        this.setLayout(new BorderLayout());
+
+        this.tabs.addTab("Clusters", this.clusterPanel);
+        this.tabs.addTab("Singles", this.singlesPanel);
+        this.tabs.addTab("Pairs", this.pairsPanel);
+        this.tabs.addTab("Efficiency", this.efficiencyPanel);
+
+        this.updateList.add(this.clusterPanel);
+        this.updateList.add(this.singlesPanel);
+        this.updateList.add(this.pairsPanel);
+        this.updateList.add(this.efficiencyPanel);
+
+        this.add(this.tabs, BorderLayout.CENTER);
+    }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/AbstractModel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/AbstractModel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/AbstractModel.java	Tue Apr 21 14:48:39 2015
@@ -10,97 +10,38 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 import javassist.Modifier;
 
+import org.lcsim.util.log.DefaultLogFormatter;
+import org.lcsim.util.log.LogUtil;
+
 /**
  * An abstract class which updates a set of listeners when there are property changes to a backing model.
- * @author Jeremy McCormick <[log in to unmask]>
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 public abstract class AbstractModel {
 
-    protected PropertyChangeSupport propertyChangeSupport;
-
-    public AbstractModel() {
-        propertyChangeSupport = new PropertyChangeSupport(this);
-    }
-
-    public void addPropertyChangeListener(PropertyChangeListener listener) {
-        propertyChangeSupport.addPropertyChangeListener(listener);
-    }
-
-    public void removePropertyChangeListener(PropertyChangeListener listener) {
-        propertyChangeSupport.removePropertyChangeListener(listener);
-    }
-       
-    protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
-        propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
-    }
-
-    protected void firePropertyChange(PropertyChangeEvent evt) {
-        propertyChangeSupport.firePropertyChange(evt);
-    }
-
-    abstract public String[] getPropertyNames();
-
-    void firePropertiesChanged(Collection<String> properties) {
-        propertyLoop: for (String property : properties) {
-            Method getMethod = null;
-            for (Method method : getClass().getMethods()) {
-                if (method.getName().equals("get" + property)) {
-                    getMethod = method;
-                    break;
-                }
-            }
-            //System.out.println(getMethod.getName());
-            try {
-                Object value = null;
-                try {
-                    value = getMethod.invoke(this, (Object[]) null);
-                    //System.out.println("  value = " + value);
-                } catch (NullPointerException e) {
-                    // This means there is no get method for the property which is a throwable error.
-                    throw new RuntimeException("Property " + property + " is missing a get method.", e);
-                } catch (InvocationTargetException e) {
-                    // Is the cause of the problem an illegal argument to the method?
-                    if (e.getCause() instanceof IllegalArgumentException) {
-                        // For this error, assume that the key itself is missing from the configuration which is a warning.
-                        System.err.println("The key " + property + " is not set in the configuration.");
-                        continue propertyLoop;
-                    } else {
-                        e.printStackTrace();
-                        throw new RuntimeException(e);
-                    }
-                }
-                if (value != null) {
-                    firePropertyChange(property, value, value);
-                    for (PropertyChangeListener listener : propertyChangeSupport.getPropertyChangeListeners()) {
-                        // FIXME: For some reason calling the propertyChangeSupport methods directly here doesn't work!
-                        listener.propertyChange(new PropertyChangeEvent(this, property, value, value));
-                    }
-                }
-            } catch (IllegalAccessException | IllegalArgumentException e) {
-                e.printStackTrace();
-                throw new RuntimeException(e);
-            }
-        }
-    }
-    
-    public void fireModelChanged() {
-        firePropertiesChanged(Arrays.asList(getPropertyNames()));
-    }
+    /**
+     * Setup logging.
+     */
+    private static final Logger LOGGER = LogUtil.create(AbstractModel.class.getName(), new DefaultLogFormatter(),
+            Level.INFO);
 
     /**
-     * This method will statically extract property names from a class, which in this package's conventions are statically declared, 
-     * public strings that end with "_PROPERTY".
-     * 
-     * @param type The class with the properties.
-     * @return The list of property names.
+     * This method will extract property names from a class, which in this package's conventions are statically
+     * declared, public strings that end with the sub-string "_PROPERTY".
+     *
+     * @param type the class with the properties settings
+     * @return the list of property names
      */
-    protected static String[] getPropertyNames(Class<? extends AbstractModel> type) {
-        List<String> fields = new ArrayList<String>();
-        for (Field field : type.getDeclaredFields()) {
-            int modifiers = field.getModifiers();
+    protected static String[] getPropertyNames(final Class<? extends AbstractModel> type) {
+        final List<String> fields = new ArrayList<String>();
+        for (final Field field : type.getDeclaredFields()) {
+            final int modifiers = field.getModifiers();
             if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers) && field.getName().endsWith("_PROPERTY")) {
                 try {
                     fields.add((String) field.get(null));
@@ -111,4 +52,135 @@
         }
         return fields.toArray(new String[] {});
     }
-}
+
+    /**
+     * The property change support object.
+     */
+    private final PropertyChangeSupport propertyChangeSupport;
+
+    /**
+     * Class constructor.
+     */
+    public AbstractModel() {
+        this.propertyChangeSupport = new PropertyChangeSupport(this);
+    }
+
+    /**
+     * Add a property change listener.
+     *
+     * @param listener the property change listener
+     */
+    public void addPropertyChangeListener(final PropertyChangeListener listener) {
+        this.propertyChangeSupport.addPropertyChangeListener(listener);
+    }
+
+    /**
+     * Fire property change events.
+     */
+    public void fireModelChanged() {
+        this.firePropertiesChanged(Arrays.asList(this.getPropertyNames()));
+    }
+
+    /**
+     * Fire property change for a list of named properties.
+     *
+     * @param properties the list of property names
+     */
+    void firePropertiesChanged(final Collection<String> properties) {
+        for (final String property : properties) {
+
+            // Find the getter for this property.
+            Method getMethod = null;
+            for (final Method method : this.getClass().getMethods()) {
+                if (method.getName().equals("get" + property)) {
+                    getMethod = method;
+                    break;
+                }
+            }
+
+            // Is there a valid get method for the property?
+            if (getMethod != null) {
+                LOGGER.fine("property: " + property + ", method: " + getMethod.getName());
+                try {
+                    Object value = null;
+                    try {
+                        value = getMethod.invoke(this, (Object[]) null);
+                    } catch (final InvocationTargetException e) {
+                        // Is the cause of the problem an illegal argument to the method?
+                        if (e.getCause() instanceof IllegalArgumentException) {
+                            // Property key is not in the configuration (this should not happen under normal
+                            // circumstances).
+                            LOGGER.log(Level.WARNING, "Property key missing from configuration: " + property, e);
+                            continue;
+                        } else {
+                            // Something else went wrong, which we assume is a fatal error.
+                            LOGGER.log(Level.SEVERE, "Error setting property: " + property, e);
+                            throw new RuntimeException("Error setting property: " + property, e);
+                        }
+                    }
+                    if (value != null) {
+                        this.firePropertyChange(property, value, value);
+                        for (final PropertyChangeListener listener : this.propertyChangeSupport
+                                .getPropertyChangeListeners()) {
+                            // FIXME: For some reason calling the propertyChangeSupport methods directly here doesn't
+                            // work!
+                            listener.propertyChange(new PropertyChangeEvent(this, property, value, value));
+                        }
+                    }
+                } catch (IllegalAccessException | IllegalArgumentException e) {
+                    // This should not usually happen.
+                    LOGGER.log(Level.SEVERE, "Error setting property: " + property, e);
+                    throw new RuntimeException("Error setting property: " + property, e);
+                }
+            } else {
+                // There was no getter found for the property which is a non-fatal warning.
+                LOGGER.log(Level.WARNING, "Unknown property in configuration: " + property);
+            }
+        }
+    }
+
+    /**
+     * Fire a property change event.
+     *
+     * @param evt the property change event
+     */
+    protected void firePropertyChange(final PropertyChangeEvent evt) {
+        this.propertyChangeSupport.firePropertyChange(evt);
+    }
+
+    /**
+     * Fire a property change.
+     *
+     * @param propertyName the name of the property
+     * @param oldValue the old property value
+     * @param newValue the new property value
+     */
+    protected void firePropertyChange(final String propertyName, final Object oldValue, final Object newValue) {
+        this.propertyChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
+    }
+
+    /**
+     * Get the property change support object.
+     *
+     * @return the property change support object
+     */
+    PropertyChangeSupport getPropertyChangeSupport() {
+        return this.propertyChangeSupport;
+    }
+
+    /**
+     * Get the list of the property names for this model.
+     *
+     * @return the list of the property names for this model
+     */
+    abstract public String[] getPropertyNames();
+
+    /**
+     * Remove a property change listener from the model.
+     *
+     * @param listener the property change listener to remove
+     */
+    public void removePropertyChangeListener(final PropertyChangeListener listener) {
+        this.propertyChangeSupport.removePropertyChangeListener(listener);
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/Configuration.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/Configuration.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/Configuration.java	Tue Apr 21 14:48:39 2015
@@ -9,210 +9,244 @@
 import java.util.Set;
 
 /**
- * This class provides a list of key, value pairs backed by a <code>Properties</code> object. The
- * getter and setter methods for these values are not public, because the 
- * {@link org.hps.monitoring.application.model.ConfigurationModel} class should be used instead
- * to get or set application configuration values.
+ * This class provides a list of key, value pairs backed by a <code>Properties</code> object. The getter and setter
+ * methods for these values are not public, because the {@link org.hps.monitoring.application.model.ConfigurationModel}
+ * class should be used instead to get or set application configuration values.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 public final class Configuration {
 
-    Properties properties;
-    File file;
-    String resourcePath;
-
+    /**
+     * The file containing the keys and values.
+     */
+    private File file;
+
+    /**
+     * The Java properties file.
+     */
+    private Properties properties;
+
+    /**
+     * The path to an embedded properties resource from a jar.
+     */
+    private String resourcePath;
+
+    /**
+     * Class constructor.
+     */
     Configuration() {
-        properties = new Properties();
-    }
-
-    /**
-     * Load a configuration from a properties file.
-     * @param file The properties file.
-     */
-    public Configuration(File file) {
+        this.properties = new Properties();
+    }
+
+    /**
+     * Class constructor.
+     * <p>
+     * Loads a configuration from a properties file.
+     *
+     * @param file the properties file
+     */
+    public Configuration(final File file) {
         this.file = file;
         try {
-            properties = new Properties();
-            properties.load(new FileInputStream(this.file));
-        } catch (IOException e) {
+            this.properties = new Properties();
+            this.properties.load(new FileInputStream(this.file));
+        } catch (final IOException e) {
             throw new RuntimeException("Error parsing properties file.", e);
         }
     }
 
     /**
+     * Class constructor.
+     * <p>
      * Load a configuration from a resource path pointing to a properties file.
-     * @param resourcePath The resource path to the properties file.
-     */
-    public Configuration(String resourcePath) {
+     *
+     * @param resourcePath the resource path to the properties file
+     */
+    public Configuration(final String resourcePath) {
         this.resourcePath = resourcePath;
-        InputStream is = this.getClass().getResourceAsStream(this.resourcePath);
-        try {
-            properties = new Properties();
-            properties.load(is);
-        } catch (IOException e) {
+        final InputStream is = this.getClass().getResourceAsStream(this.resourcePath);
+        try {
+            this.properties = new Properties();
+            this.properties.load(is);
+        } catch (final IOException e) {
             throw new RuntimeException("Error parsing properties resource.", e);
         }
     }
 
     /**
+     * Check if the properties contains the key and if it has a non-null value.
+     *
+     * @param key the properties key
+     * @return <code>true</code> if properties key is valid
+     */
+    boolean checkKey(final String key) {
+        return this.hasKey(key) && this.properties.getProperty(key) != null;
+    }
+
+    /**
+     * Get a key value as a string.
+     *
+     * @param key the key to lookup
+     * @return the value or null if does not exist
+     */
+    String get(final String key) {
+        if (this.checkKey(key)) {
+            // Return the key value for properties that are set.
+            return this.properties.getProperty(key);
+        } else {
+            // Return null for unset properties.
+            return null;
+        }
+    }
+
+    /**
+     * Get a key value as a boolean.
+     *
+     * @param key the key to lookup
+     * @return the value or null if does not exist
+     */
+    Boolean getBoolean(final String key) {
+        if (this.checkKey(key)) {
+            return Boolean.parseBoolean(this.properties.getProperty(key));
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get a key value as a double.
+     *
+     * @param key the key to lookup
+     * @return the value as a <code>Double</code> or <code>null</code> if does not exist
+     */
+    Double getDouble(final String key) {
+        if (this.checkKey(key)) {
+            return Double.parseDouble(this.properties.getProperty(key));
+        } else {
+            return null;
+        }
+    }
+
+    /**
      * Get the file associated with this configuration or <code>null</code> if not set.
-     * @return The file associated with the configuration.
+     *
+     * @return the file associated with the configuration
      */
     public File getFile() {
-        return file;
-    }
-
-    /**
-     * Get the resource path associated with this configuration or <code>null</code> if not
-     * applicable.
-     * @return The resource path of this configuration.
+        return this.file;
+    }
+
+    /**
+     * Get a key value as an integer.
+     *
+     * @param key the key to lookup
+     * @return the value as an <code>Integer</code> or <code>null</code> if does not exist
+     */
+    Integer getInteger(final String key) {
+        if (this.checkKey(key)) {
+            return Integer.parseInt(this.properties.getProperty(key));
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get the property keys.
+     *
+     * @return the collection of property keys
+     */
+    public Set<String> getKeys() {
+        return this.properties.stringPropertyNames();
+    }
+
+    /**
+     * Get a key value as a Long.
+     *
+     * @param key the key to lookup
+     * @return the key value as a <code>Long</code>
+     */
+    Long getLong(final String key) {
+        if (this.checkKey(key)) {
+            return Long.parseLong(this.properties.getProperty(key));
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Get the resource path associated with this configuration or <code>null</code> if not applicable.
+     *
+     * @return the resource path of this configuration
      */
     public String getResourcePath() {
-        return resourcePath;
-    }
-
-    /**
-     * True if configuration has value for the key.
-     * @param key The key.
-     * @return True if configuration has value for the key.
-     */
-    boolean hasKey(String key) {
-        try {
-            return properties.containsKey(key);
-        } catch (java.lang.NullPointerException e) {
+        return this.resourcePath;
+    }
+
+    /**
+     * Return <code>true</code> if configuration has value for the key.
+     *
+     * @param key the key
+     * @return <code>true</code> if configuration has value for the key
+     */
+    boolean hasKey(final String key) {
+        try {
+            return this.properties.containsKey(key);
+        } catch (final java.lang.NullPointerException e) {
             return false;
         }
     }
 
     /**
-     * Get a key value as a string.
-     * @param key The key to lookup.
-     * @return The value or null if does not exist.
-     */
-    String get(String key) {
-        if (checkKey(key)) {
-            // Return the key value for properties that are set.
-            return properties.getProperty(key);
-        } else {
-            // Return null for unset properties.
-            return null;
-        }
-    }
-
-    /**
-     * Get a key value as a boolean.
-     * @param key The key to lookup.
-     * @return The value or null if does not exist.
-     */
-    Boolean getBoolean(String key) {
-        if (checkKey(key)) {
-            return Boolean.parseBoolean(properties.getProperty(key));    
-        } else {
-            return null;
-        }        
-    }
-
-    /**
-     * Get a key value as a double.
-     * @param key The key to lookup.
-     * @return The value or null if does not exist.
-     */
-    Double getDouble(String key) {
-        if (checkKey(key)) {
-            return Double.parseDouble(properties.getProperty(key));
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Get a key value as an integer.
-     * @param key The key to lookup.
-     * @return The value or null if does not exist.
-     */
-    Integer getInteger(String key) {
-        if (checkKey(key)) {
-            return Integer.parseInt(properties.getProperty(key));
-        } else {
-            return null;
-        }
-    }
-    
-    /**
-     * Get a key value as a Long.
-     * @param key The key to lookup.
-     * @param key The value or null if does not exist.
-     * @return
-     */
-    Long getLong(String key) {
-        if (checkKey(key)) {
-            return Long.parseLong(properties.getProperty(key));
-        } else {
-            return null;
-        }
+     * Merge in values from another configuration into this one which will override properties that already exist with
+     * new values.
+     *
+     * @param configuration the configuration with the properties to merge
+     */
+    void merge(final Configuration configuration) {
+        for (final String property : configuration.getKeys()) {
+            this.set(property, configuration.get(property));
+        }
+    }
+
+    /**
+     * Remove a configuration value.
+     *
+     * @param key the key of the value
+     */
+    void remove(final String key) {
+        this.properties.remove(key);
+    }
+
+    /**
+     * Set a configuration value.
+     *
+     * @param key the key for lookup
+     * @param value the value to assign to that key
+     */
+    void set(final String key, final Object value) {
+        this.properties.put(key, String.valueOf(value));
+    }
+
+    /**
+     * Convert this object to a string by printing out its properties list.
+     */
+    @Override
+    public String toString() {
+        return this.properties.toString();
     }
 
     /**
      * Write this configuration to a file and set that file as the current one.
+     *
      * @param file The output file.
      */
-    public void writeToFile(File file) {
+    public void writeToFile(final File file) {
         this.file = file;
         try {
-            properties.store(new FileOutputStream(this.file), null);
-        } catch (IOException e) {
+            this.properties.store(new FileOutputStream(this.file), null);
+        } catch (final IOException e) {
             throw new RuntimeException("Error saving properties file.", e);
         }
     }
-    
-    /**
-     * Check if the properties contains the key and if it has a non-null value.
-     * @param key The properties key.
-     * @return True if properties key is valid.
-     */
-    boolean checkKey(String key) {
-        return hasKey(key) && properties.getProperty(key) != null;
-    }
-
-    /**
-     * Set a configuration value.
-     * @param key The key for lookup.
-     * @param value The value to assign to that key.
-     */
-    void set(String key, Object value) {
-        properties.put(key, String.valueOf(value));
-    }
-
-    /**
-     * Remove a configuration value.
-     * @param key The key of the value.
-     */
-    void remove(String key) {
-        properties.remove(key);
-    }
-
-    /**
-     * Convert this object to a string by printing out its properties list.
-     */
-    public String toString() {
-        return properties.toString();        
-    }
-    
-    /**
-     * Get the property keys.
-     * @return The collection of property keys.
-     */
-    public Set<String> getKeys() {
-        return properties.stringPropertyNames();
-    }
-    
-    /**
-     * Merge in values from another configuration into this one which will override
-     * properties that already exist with new values.
-     * @param configuration The configuration with the properties to merge.
-     */
-    void merge(Configuration configuration) {
-        for (String property : configuration.getKeys()) {
-            this.set(property, configuration.get(property));
-        }
-    }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConfigurationModel.java	Tue Apr 21 14:48:39 2015
@@ -9,497 +9,1072 @@
 import org.jlab.coda.et.enums.Mode;
 
 /**
- * A model of the global configuration parameters that can be used to automatically update the GUI
- * from a configuration or push changes from GUI components into the current configuration.
+ * A model of the global configuration parameters that can be used to automatically update the GUI from a configuration
+ * or push changes from GUI components into the current configuration.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 public final class ConfigurationModel extends AbstractModel {
 
-    Configuration configuration;    
-    
-    // Job setting properties.
+    /**
+     * Name of AIDA server.
+     */
     public static final String AIDA_SERVER_NAME_PROPERTY = "AIDAServerName";
+
+    /**
+     * ET blocking setting.
+     */
+    public static final String BLOCKING_PROPERTY = "Blocking";
+
+    /**
+     * ET chunk size (number of events per ET <code>getEvents</code>).
+     */
+    public static final String CHUNK_SIZE_PROPERTY = "ChunkSize";
+
+    /**
+     * Conditions tag.
+     */
     public static final String CONDITIONS_TAG_PROPERTY = "ConditionsTag";
+
+    /**
+     * The list of all property names.
+     */
+    static final String[] CONFIG_PROPERTIES = AbstractModel.getPropertyNames(ConfigurationModel.class);
+
+    /**
+     * The data source path which is a file path if using a file source (EVIO or LCIO file.
+     */
+    public static final String DATA_SOURCE_PATH_PROPERTY = "DataSourcePath";
+
+    /**
+     * The data source type (EVIO, LCIO or ET).
+     *
+     * @see org.hps.record.enums.DataSourceType
+     * @return the data source type
+     */
+    public static final String DATA_SOURCE_TYPE_PROPERTY = "DataSourceType";
+
+    /**
+     * The detector alias which is pointing to a local compact.xml detector file.
+     */
+    public static final String DETECTOR_ALIAS_PROPERTY = "DetectorAlias";
+
+    /**
+     * The name of a detector model to use from the jar file.
+     */
     public static final String DETECTOR_NAME_PROPERTY = "DetectorName";
-    public static final String DETECTOR_ALIAS_PROPERTY = "DetectorAlias";
+
+    /**
+     * Flag to enable disconnecting when an EVIO END event is received.
+     */
+    public static final String DISCONNECT_ON_END_RUN_PROPERTY = "DisconnectOnEndRun";
+
+    /**
+     * Flag to enable disconnecting if an event processing error occurs.
+     */
     public static final String DISCONNECT_ON_ERROR_PROPERTY = "DisconnectOnError";
-    public static final String DISCONNECT_ON_END_RUN_PROPERTY = "DisconnectOnEndRun";
+
+    /**
+     * The name of the ET system which is generally a file on disk.
+     */
+    public static final String ET_NAME_PROPERTY = "EtName";
+
+    /**
+     * The name of the event builder for converting from EVIO to LCIO events.
+     */
     public static final String EVENT_BUILDER_PROPERTY = "EventBuilderClassName";
+
+    /**
+     * Flag to freeze conditions system after initialization.
+     */
     public static final String FREEZE_CONDITIONS_PROPERTY = "FreezeConditions";
+
+    /**
+     * The ET host property (TCP/IP host name).
+     */
+    public static final String HOST_PROPERTY = "Host";
+
+    /**
+     * The name of the output log file.
+     */
     public static final String LOG_FILE_NAME_PROPERTY = "LogFileName";
+
+    /**
+     * The filter level for displaying records in the log table.
+     */
+    public static final String LOG_LEVEL_FILTER_PROPERTY = "LogLevelFilter";
+
+    /**
+     * The global log level.
+     */
     public static final String LOG_LEVEL_PROPERTY = "LogLevel";
-    public static final String LOG_LEVEL_FILTER_PROPERTY = "LogLevelFilter";
+
+    /**
+     * Flag to log to a file.
+     */
     public static final String LOG_TO_FILE_PROPERTY = "LogToFile";
+
+    /**
+     * Max events after which session will be automatically ended.
+     */
     public static final String MAX_EVENTS_PROPERTY = "MaxEvents";
+
+    /**
+     * The maximum number of recent files (hard-coded to 10 to match 0-9 shortcut mnemonics).
+     */
+    private static final int MAX_RECENT_FILES = 10;
+
+    /**
+     * The ET TCP/IP port.
+     */
+    public static final String PORT_PROPERTY = "Port";
+
+    /**
+     * The ET pre-scaling value which throttles event rate.
+     */
+    public static final String PRESCALE_PROPERTY = "Prescale";
+
+    /**
+     * The processing stage(s) to execute (ET, EVIO or LCIO).
+     */
+    public static final String PROCESSING_STAGE_PROPERTY = "ProcessingStage";
+
+    /**
+     * The ET queue size.
+     */
+    public static final String QUEUE_SIZE_PROPERTY = "QueueSize";
+
+    /**
+     * The list of recent files.
+     */
     public static final String RECENT_FILES_PROPERTY = "RecentFiles";
+
+    /**
+     * The ET station name.
+     */
+    public static final String STATION_NAME_PROPERTY = "StationName";
+
+    /**
+     * The ET station position.
+     */
+    public static final String STATION_POSITION_PROPERTY = "StationPosition";
+
+    /**
+     * The steering file.
+     */
+    public static final String STEERING_FILE_PROPERTY = "SteeringFile";
+
+    /**
+     * The steering resource.
+     */
+    public static final String STEERING_RESOURCE_PROPERTY = "SteeringResource";
+
+    /**
+     * The steering type (file or resource).
+     */
     public static final String STEERING_TYPE_PROPERTY = "SteeringType";
-    public static final String STEERING_FILE_PROPERTY = "SteeringFile";
-    public static final String STEERING_RESOURCE_PROPERTY = "SteeringResource";
+
+    /**
+     * A user run number to use for initializing the conditions system.
+     */
     public static final String USER_RUN_NUMBER_PROPERTY = "UserRunNumber";
 
-    // Data source properties.
-    public static final String DATA_SOURCE_TYPE_PROPERTY = "DataSourceType";
-    public static final String DATA_SOURCE_PATH_PROPERTY = "DataSourcePath";
-    public static final String PROCESSING_STAGE_PROPERTY = "ProcessingStage";
-
-    // ET connection parameters.
-    public static final String ET_NAME_PROPERTY = "EtName";
-    public static final String HOST_PROPERTY = "Host";
-    public static final String PORT_PROPERTY = "Port";
-    public static final String BLOCKING_PROPERTY = "Blocking";
+    /**
+     * The verbose setting for the ET system.
+     */
     public static final String VERBOSE_PROPERTY = "Verbose";
-    public static final String STATION_NAME_PROPERTY = "StationName";
-    public static final String CHUNK_SIZE_PROPERTY = "ChunkSize";
-    public static final String QUEUE_SIZE_PROPERTY = "QueueSize";
-    public static final String STATION_POSITION_PROPERTY = "StationPosition";
+
+    /**
+     * The ET wait mode.
+     */
     public static final String WAIT_MODE_PROPERTY = "WaitMode";
+
+    /**
+     * The ET wait time (if using timed wait mode).
+     */
     public static final String WAIT_TIME_PROPERTY = "WaitTime";
-    public static final String PRESCALE_PROPERTY = "Prescale";
-    
-    // Action command to get notified after configuration change is performed.
-    public static final String CONFIGURATION_CHANGED = "configurationChanged";
-
-    static final String[] CONFIG_PROPERTIES = AbstractModel.getPropertyNames(ConfigurationModel.class);
-
+
+    /**
+     * The underlying properties for the model.
+     */
+    private Configuration configuration;
+
+    /**
+     * Class constructor.
+     * <p>
+     * Create a new model without any initial property settings.
+     */
     public ConfigurationModel() {
         this.configuration = new Configuration();
     }
 
-    public ConfigurationModel(Configuration configuration) {
+    /**
+     * Class constructor.
+     * <p>
+     * Sets the properties from a configuration (file or resource).
+     *
+     * @param configuration the configuration containing property settings
+     */
+    public ConfigurationModel(final Configuration configuration) {
         this.configuration = configuration;
-        fireModelChanged();
-    }
-    
-    public void setConfiguration(Configuration configuration) {
-        this.configuration = configuration;
-        fireModelChanged();
-    }
-     
+        this.fireModelChanged();
+    }
+
+    /**
+     * Add a single recent file.
+     *
+     * @param recentFile the recent file to add
+     */
+    public void addRecentFile(final String recentFile) {
+        if (!this.configuration.checkKey(RECENT_FILES_PROPERTY)) {
+            this.configuration.set(RECENT_FILES_PROPERTY, recentFile);
+            this.firePropertyChange(RECENT_FILES_PROPERTY, null, recentFile);
+        } else {
+            final List<String> recentFilesList = this.getRecentFilesList();
+            if (!recentFilesList.contains(recentFile)) {
+                if (this.getRecentFilesList().size() >= MAX_RECENT_FILES) {
+                    // Bump the first file from the list if max recent files is exceeded (10 files).
+                    recentFilesList.remove(0);
+                    this.setRecentFilesList(recentFilesList);
+                }
+                final String oldValue = this.configuration.get(RECENT_FILES_PROPERTY);
+                final String recentFiles = oldValue + "\n" + recentFile;
+                this.configuration.set(RECENT_FILES_PROPERTY, recentFiles);
+                this.firePropertyChange(RECENT_FILES_PROPERTY, oldValue, recentFile);
+            }
+        }
+
+    }
+
+    /**
+     * Fire property change for all property keys.
+     */
+    @Override
+    public void fireModelChanged() {
+        this.firePropertiesChanged(this.configuration.getKeys());
+    }
+
+    /**
+     * Get the AIDA server name.
+     *
+     * @return the AIDA server name
+     */
+    public String getAIDAServerName() {
+        return this.configuration.get(AIDA_SERVER_NAME_PROPERTY);
+    }
+
+    /**
+     * Get the ET blocking setting.
+     *
+     * @return the ET blocking setting
+     */
+    public Boolean getBlocking() {
+        return this.configuration.getBoolean(BLOCKING_PROPERTY);
+    }
+
+    /**
+     * Get the ET chunk size, which is the number of events that will be retrieved at once from the server.
+     *
+     * @return the ET chunk size
+     */
+    public Integer getChunkSize() {
+        return this.configuration.getInteger(CHUNK_SIZE_PROPERTY);
+    }
+
+    /**
+     * Get the conditions system tag.
+     *
+     * @return the conditions system tag
+     */
+    public String getConditionsTag() {
+        return this.configuration.get(CONDITIONS_TAG_PROPERTY);
+    }
+
+    /**
+     * Get the underlying configuration containing properties.
+     *
+     * @return the underlying configuration with properties settings
+     */
     public Configuration getConfiguration() {
         return this.configuration;
     }
 
-    public Level getLogLevel() {
-        return Level.parse(configuration.get(LOG_LEVEL_PROPERTY));
-    }
-
-    public void setLogLevel(Level level) { 
-        Level oldValue = getLogLevel();
-        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));
-    }
-
-    public void setSteeringType(SteeringType steeringType) {
-        SteeringType oldValue = getSteeringType();
-        configuration.set(STEERING_TYPE_PROPERTY, steeringType.name());
-        firePropertyChange(STEERING_TYPE_PROPERTY, oldValue, getSteeringType());
-    }
-
-    public String getSteeringFile() {        
-        return configuration.get(STEERING_FILE_PROPERTY);
-    }
-
-    public void setSteeringFile(String steeringFile) {
-        String oldValue = getSteeringFile();
-        configuration.set(STEERING_FILE_PROPERTY, steeringFile);
-        firePropertyChange(STEERING_FILE_PROPERTY, oldValue, getSteeringFile());
-    }
-
-    public String getSteeringResource() {
-        return configuration.get(STEERING_RESOURCE_PROPERTY);
-    }
-
-    public void setSteeringResource(String steeringResource) {
-        String oldValue = getSteeringResource();
-        configuration.set(STEERING_RESOURCE_PROPERTY, steeringResource);
-        firePropertyChange(STEERING_RESOURCE_PROPERTY, oldValue, steeringResource);
-    }
-
-    public String getDetectorName() {
-        return configuration.get(DETECTOR_NAME_PROPERTY);
-    }
-
-    public void setDetectorName(String detectorName) {
-        String oldValue = getDetectorName();
-        configuration.set(DETECTOR_NAME_PROPERTY, detectorName);
-        firePropertyChange(DETECTOR_NAME_PROPERTY, oldValue, getDetectorName());
-    }
-
-    public String getDetectorAlias() {
-        return configuration.get(DETECTOR_ALIAS_PROPERTY);
-    }
-
-    public void setDetectorAlias(String detectorAlias) {
-        String oldValue = null;
-        if (hasPropertyKey(DETECTOR_ALIAS_PROPERTY)) {
-            oldValue = getDetectorAlias();
-        }
-        configuration.set(DETECTOR_ALIAS_PROPERTY, detectorAlias);
-        firePropertyChange(DETECTOR_ALIAS_PROPERTY, oldValue, getDetectorAlias());
-    }
-
-    public String getEventBuilderClassName() {
-        return configuration.get(EVENT_BUILDER_PROPERTY);
-    }
-
-    public void setEventBuilderClassName(String eventBuilderClassName) {
-        String oldValue = getEventBuilderClassName();
-        configuration.set(EVENT_BUILDER_PROPERTY, eventBuilderClassName);
-        firePropertyChange(EVENT_BUILDER_PROPERTY, oldValue, getEventBuilderClassName());
-    }
-
-    public Boolean getLogToFile() {
-        return configuration.getBoolean(LOG_TO_FILE_PROPERTY);
-    }
-
-    public void setLogToFile(Boolean logToFile) {
-        Boolean oldValue = getLogToFile();
-        configuration.set(LOG_TO_FILE_PROPERTY, logToFile);
-        firePropertyChange(LOG_TO_FILE_PROPERTY, oldValue, getLogToFile());
-    }
-
-    public String getLogFileName() {
-        return configuration.get(LOG_FILE_NAME_PROPERTY);
-    }
-
-    public void setLogFileName(String logFileName) {
-        String oldValue = getLogFileName();
-        configuration.set(LOG_FILE_NAME_PROPERTY, logFileName);
-        firePropertyChange(LOG_FILE_NAME_PROPERTY, oldValue, getLogFileName());
-    }
-
-    public Boolean getDisconnectOnError() {
-        return configuration.getBoolean(DISCONNECT_ON_ERROR_PROPERTY);
-    }
-
-    public void setDisconnectOnError(Boolean disconnectOnError) {
-        Boolean oldValue = getDisconnectOnError();
-        configuration.set(DISCONNECT_ON_ERROR_PROPERTY, disconnectOnError);
-        firePropertyChange(DISCONNECT_ON_ERROR_PROPERTY, oldValue, getDisconnectOnError());
-    }
-
-    public Boolean getDisconnectOnEndRun() {
-        return configuration.getBoolean(DISCONNECT_ON_END_RUN_PROPERTY);
-    }
-
-    public void setDisconnectOnEndRun(Boolean disconnectOnEndRun) {
-        Boolean oldValue = getDisconnectOnEndRun();
-        configuration.set(DISCONNECT_ON_END_RUN_PROPERTY, disconnectOnEndRun);
-        firePropertyChange(DISCONNECT_ON_END_RUN_PROPERTY, oldValue, getDisconnectOnEndRun());
-    }
-
+    /**
+     * Get the data source path.
+     *
+     * @return the data source path
+     */
+    public String getDataSourcePath() {
+        return this.configuration.get(DATA_SOURCE_PATH_PROPERTY);
+    }
+
+    /**
+     * Get the data source type (EVIO, LCIO or ET).
+     *
+     * @return the data source type
+     */
     public DataSourceType getDataSourceType() {
-        if (configuration.checkKey(DATA_SOURCE_TYPE_PROPERTY)) {
-            return DataSourceType.valueOf(configuration.get(DATA_SOURCE_TYPE_PROPERTY));
+        if (this.configuration.checkKey(DATA_SOURCE_TYPE_PROPERTY)) {
+            return DataSourceType.valueOf(this.configuration.get(DATA_SOURCE_TYPE_PROPERTY));
         } else {
             return null;
         }
     }
 
-    public void setDataSourceType(DataSourceType dataSourceType) {
-        DataSourceType oldValue = getDataSourceType();
-        configuration.set(DATA_SOURCE_TYPE_PROPERTY, dataSourceType);
-        firePropertyChange(DATA_SOURCE_TYPE_PROPERTY, oldValue, getDataSourceType());
-    }
-
-    public String getDataSourcePath() {
-        return configuration.get(DATA_SOURCE_PATH_PROPERTY);
-    }
-
-    public void setDataSourcePath(String dataSourcePath) {
-        String oldValue = getDataSourcePath();
-        configuration.set(DATA_SOURCE_PATH_PROPERTY, dataSourcePath);
-        firePropertyChange(DATA_SOURCE_PATH_PROPERTY, oldValue, getDataSourcePath());
-    }
-     
-    /*
-    public void setDataSource(String dataSource) {
-        setDataSourcePath(dataSource);
-        DataSourceType dst = DataSourceType.getDataSourceType(dataSource);
-        setDataSourceType(dst);
-    }
-    */
-
+    /**
+     * Get the detector alias which is a compact.xml file on disk.
+     *
+     * @return the detector alias
+     */
+    public String getDetectorAlias() {
+        return this.configuration.get(DETECTOR_ALIAS_PROPERTY);
+    }
+
+    /**
+     * Get the detector name.
+     *
+     * @return the detector name
+     */
+    public String getDetectorName() {
+        return this.configuration.get(DETECTOR_NAME_PROPERTY);
+    }
+
+    /**
+     * Get the disconnect on end run flag.
+     *
+     * @return the disconnect on end run flag
+     */
+    public Boolean getDisconnectOnEndRun() {
+        return this.configuration.getBoolean(DISCONNECT_ON_END_RUN_PROPERTY);
+    }
+
+    /**
+     * Get the disconnect on error flag.
+     *
+     * @return the disconnect on error flag
+     */
+    public Boolean getDisconnectOnError() {
+        return this.configuration.getBoolean(DISCONNECT_ON_ERROR_PROPERTY);
+    }
+
+    /**
+     * Get the ET system name.
+     *
+     * @return the ET system name
+     */
+    public String getEtName() {
+        return this.configuration.get(ET_NAME_PROPERTY);
+    }
+
+    /**
+     * Get the ET path from concatenating the ET system name, host and post (which is just used for the GUI).
+     *
+     * @return the ET path
+     */
+    public String getEtPath() {
+        return this.getEtName() + "@" + this.getHost() + ":" + this.getPort();
+    }
+
+    /**
+     * Get the event builder class name.
+     *
+     * @return the event builder class name
+     */
+    public String getEventBuilderClassName() {
+        return this.configuration.get(EVENT_BUILDER_PROPERTY);
+    }
+
+    /**
+     * Get the freeze conditions setting which will cause conditions system to be frozen after initialization with the
+     * currently selected run number and detector name.
+     *
+     * @return the freeze conditions setting
+     */
+    public Boolean getFreezeConditions() {
+        return this.configuration.getBoolean(FREEZE_CONDITIONS_PROPERTY);
+    }
+
+    /**
+     * Get the ET host name.
+     *
+     * @return the ET host name
+     */
+    public String getHost() {
+        return this.configuration.get(HOST_PROPERTY);
+    }
+
+    /**
+     * Get the log file name.
+     *
+     * @return the log file name
+     */
+    public String getLogFileName() {
+        return this.configuration.get(LOG_FILE_NAME_PROPERTY);
+    }
+
+    /**
+     * Get the global log level.
+     *
+     * @return the global log level
+     */
+    public Level getLogLevel() {
+        return Level.parse(this.configuration.get(LOG_LEVEL_PROPERTY));
+    }
+
+    /**
+     * Get the log level filter for displaying messages in the log table.
+     *
+     * @return the log level filter
+     */
+    public Level getLogLevelFilter() {
+        return Level.parse(this.configuration.get(LOG_LEVEL_FILTER_PROPERTY));
+    }
+
+    /**
+     * Get the log to file setting which redirects monitoring application log messages from the console to a file.
+     *
+     * @return the log to file setting
+     */
+    public Boolean getLogToFile() {
+        return this.configuration.getBoolean(LOG_TO_FILE_PROPERTY);
+    }
+
+    /**
+     * Get the maximum number of events before disconnecting.
+     *
+     * @return the maximum number of events before disconnecting
+     */
+    public Long getMaxEvents() {
+        return this.configuration.getLong(MAX_EVENTS_PROPERTY);
+    }
+
+    /**
+     * Get the ET TCP/IP port value.
+     *
+     * @return the ET TCP/IP port value
+     */
+    public Integer getPort() {
+        return this.configuration.getInteger(PORT_PROPERTY);
+    }
+
+    /**
+     * Get the ET station prescale value.
+     *
+     * @return the ET station prescale value
+     */
+    public Integer getPrescale() {
+        return this.configuration.getInteger(PRESCALE_PROPERTY);
+    }
+
+    /**
+     * Get the processing stage.
+     * <p>
+     * Each level will execute the preceding ones, e.g. LCIO exectures EVIO, ET and LCIO event processing
+     *
+     * @return the processing stage to execute
+     */
     public ProcessingStage getProcessingStage() {
-        if (configuration.get(PROCESSING_STAGE_PROPERTY) == null)
+        if (this.configuration.get(PROCESSING_STAGE_PROPERTY) == null) {
             throw new RuntimeException(PROCESSING_STAGE_PROPERTY + " is null!!!");
-        return ProcessingStage.valueOf(configuration.get(PROCESSING_STAGE_PROPERTY));
-    }
-
-    public void setProcessingStage(ProcessingStage processingStage) {
-        ProcessingStage oldValue = getProcessingStage();
-        configuration.set(PROCESSING_STAGE_PROPERTY, processingStage);
-        firePropertyChange(PROCESSING_STAGE_PROPERTY, oldValue, getProcessingStage());
-    }
-
-    public String getEtName() {
-        return configuration.get(ET_NAME_PROPERTY);
-    }
-
-    public void setEtName(String etName) {
-        String oldValue = getEtName();
-        configuration.set(ET_NAME_PROPERTY, etName);
-        firePropertyChange(ET_NAME_PROPERTY, oldValue, getEtName());
-    }
-
-    public String getHost() {
-        return configuration.get(HOST_PROPERTY);
-    }
-
-    public void setHost(String host) {
-        String oldValue = getHost();
-        configuration.set(HOST_PROPERTY, host);
-        firePropertyChange(HOST_PROPERTY, oldValue, getHost());
-    }
-
-    public Integer getPort() {
-        return configuration.getInteger(PORT_PROPERTY);
-    }
-
-    public void setPort(Integer port) {
-        Integer oldValue = getPort();
-        configuration.set(PORT_PROPERTY, port);
-        firePropertyChange(PORT_PROPERTY, oldValue, getPort());
-    }
-
-    public Boolean getBlocking() {
-        return configuration.getBoolean(BLOCKING_PROPERTY);
-    }
-
-    public void setBlocking(Boolean blocking) {
-        Boolean oldValue = getBlocking();
-        configuration.set(BLOCKING_PROPERTY, blocking);
-        firePropertyChange(BLOCKING_PROPERTY, oldValue, getBlocking());
-    }
-
-    public Boolean getVerbose() {
-        return configuration.getBoolean(VERBOSE_PROPERTY);
-    }
-
-    public void setVerbose(Boolean verbose) {
-        Boolean oldValue = getVerbose();
-        configuration.set(VERBOSE_PROPERTY, verbose);
-        firePropertyChange(VERBOSE_PROPERTY, oldValue, getVerbose());
-    }
-
-    public String getStationName() {
-        return configuration.get(STATION_NAME_PROPERTY);
-    }
-
-    public void setStationName(String stationName) {
-        String oldValue = getStationName();
-        configuration.set(STATION_NAME_PROPERTY, stationName);
-        firePropertyChange(STATION_NAME_PROPERTY, oldValue, getStationName());
-    }
-
-    public Integer getChunkSize() {
-        return configuration.getInteger(CHUNK_SIZE_PROPERTY);
-    }
-
-    public void setChunkSize(Integer chunkSize) {
-        Integer oldValue = getChunkSize();
-        configuration.set(CHUNK_SIZE_PROPERTY, chunkSize);
-        firePropertyChange(CHUNK_SIZE_PROPERTY, oldValue, getChunkSize());
-    }
-
+        }
+        return ProcessingStage.valueOf(this.configuration.get(PROCESSING_STAGE_PROPERTY));
+    }
+
+    /**
+     * Get the property names in the configuration.
+     *
+     * @return the property names in the configuration
+     */
+    @Override
+    public String[] getPropertyNames() {
+        return CONFIG_PROPERTIES;
+    }
+
+    /**
+     * Get the ET queue size.
+     *
+     * @return the ET queue size
+     */
     public Integer getQueueSize() {
-        return configuration.getInteger(QUEUE_SIZE_PROPERTY);
-    }
-
-    public void setQueueSize(Integer queueSize) {
-        Integer oldValue = getQueueSize();
-        configuration.set(QUEUE_SIZE_PROPERTY, queueSize);
-        firePropertyChange(QUEUE_SIZE_PROPERTY, oldValue, getQueueSize());
-    }
-
-    public Integer getStationPosition() {
-        return configuration.getInteger(STATION_POSITION_PROPERTY);
-    }
-
-    public void setStationPosition(Integer stationPosition) {
-        Integer oldValue = getStationPosition();
-        configuration.set(STATION_POSITION_PROPERTY, stationPosition);
-        firePropertyChange(STATION_POSITION_PROPERTY, oldValue, getStationPosition());
-    }
-
-    public Mode getWaitMode() {
-        return Mode.valueOf(configuration.get(WAIT_MODE_PROPERTY));
-    }
-
-    public void setWaitMode(Mode waitMode) {
-        Mode oldValue = getWaitMode();
-        configuration.set(WAIT_MODE_PROPERTY, waitMode.name());
-        firePropertyChange(WAIT_MODE_PROPERTY, oldValue, getWaitMode());
-    }
-
-    public Integer getWaitTime() {
-        return configuration.getInteger(WAIT_TIME_PROPERTY);
-    }
-
-    public void setWaitTime(Integer waitTime) {
-        Integer oldValue = getWaitTime();
-        configuration.set(WAIT_TIME_PROPERTY, waitTime);
-        firePropertyChange(WAIT_TIME_PROPERTY, oldValue, getWaitTime());
-    }
-
-    public Integer getPrescale() {
-        return configuration.getInteger(PRESCALE_PROPERTY);
-    }
-
-    public void setPrescale(Integer prescale) {
-        Integer oldValue = getPrescale();
-        configuration.set(PRESCALE_PROPERTY, prescale);
-        firePropertyChange(PRESCALE_PROPERTY, oldValue, getPrescale());
-    }
-
-    public void setUserRunNumber(Integer userRunNumber) {
-        Integer oldValue = null;
-        if (hasPropertyKey(USER_RUN_NUMBER_PROPERTY)) {
-            oldValue = getUserRunNumber();
-        }
-        configuration.set(USER_RUN_NUMBER_PROPERTY, userRunNumber);
-        firePropertyChange(USER_RUN_NUMBER_PROPERTY, oldValue, getUserRunNumber());
-    }
-
-    public Integer getUserRunNumber() {
-        return configuration.getInteger(USER_RUN_NUMBER_PROPERTY);
-    }
-
-    public void setFreezeConditions(Boolean freezeConditions) {
-        Boolean oldValue = null;
-        if (hasPropertyKey(FREEZE_CONDITIONS_PROPERTY)) {
-            oldValue = getFreezeConditions();
-        }
-        configuration.set(FREEZE_CONDITIONS_PROPERTY, freezeConditions);
-        firePropertyChange(FREEZE_CONDITIONS_PROPERTY, oldValue, freezeConditions);
-    }
-
-    public Boolean getFreezeConditions() {
-        return configuration.getBoolean(FREEZE_CONDITIONS_PROPERTY);
-    }
-
-    public void setMaxEvents(Long maxEvents) {
-        Long oldValue = getMaxEvents();
-        configuration.set(MAX_EVENTS_PROPERTY, maxEvents);
-        firePropertyChange(MAX_EVENTS_PROPERTY, oldValue, getMaxEvents());
-    }
-
-    public Long getMaxEvents() {
-        return configuration.getLong(MAX_EVENTS_PROPERTY);
-    }
-       
-    public String getEtPath() {
-        return getEtName() + "@" + getHost() + ":" + getPort();
-    }
-    
-    public void setConditionsTag(String conditionsTag) {
-        String oldValue = getConditionsTag();
-        configuration.set(CONDITIONS_TAG_PROPERTY, conditionsTag);
-        firePropertyChange(CONDITIONS_TAG_PROPERTY, oldValue, getConditionsTag());
-    }     
-    
-    public String getConditionsTag() {
-        return configuration.get(CONDITIONS_TAG_PROPERTY);
-    }
-    
-    public void setAIDAServerName(String AIDAServerName) {
-        String oldValue = getAIDAServerName();
-        configuration.set(AIDA_SERVER_NAME_PROPERTY, AIDAServerName);
-        firePropertyChange(AIDA_SERVER_NAME_PROPERTY, oldValue, getAIDAServerName());
-    } 
-    
-    public String getAIDAServerName() {
-        return configuration.get(AIDA_SERVER_NAME_PROPERTY);
-    }
-    
+        return this.configuration.getInteger(QUEUE_SIZE_PROPERTY);
+    }
+
+    /**
+     * Get recent files as a string with paths separated by the '\n' string.
+     *
+     * @return the recent files as a delimited string
+     */
     public String getRecentFiles() {
-        if (configuration.hasKey(RECENT_FILES_PROPERTY)) {
-            return configuration.get(RECENT_FILES_PROPERTY);
+        if (this.configuration.hasKey(RECENT_FILES_PROPERTY)) {
+            return this.configuration.get(RECENT_FILES_PROPERTY);
         } else {
             return null;
-        }         
-    }
-    
+        }
+    }
+
+    /**
+     * Get the recent files list.
+     * <p>
+     * This is actually just a copy from the property, so to set the recent file list call
+     * {@link #setRecentFiles(String)}.
+     *
+     * @return the recent files list
+     */
     public List<String> getRecentFilesList() {
-        List<String> recentFilesList = new ArrayList<String>();
-        if (configuration.hasKey(RECENT_FILES_PROPERTY)) {
-            for (String recentFile : configuration.get(RECENT_FILES_PROPERTY).split("\n")) {
+        final List<String> recentFilesList = new ArrayList<String>();
+        if (this.configuration.hasKey(RECENT_FILES_PROPERTY)) {
+            for (final String recentFile : this.configuration.get(RECENT_FILES_PROPERTY).split("\n")) {
                 recentFilesList.add(recentFile);
             }
         }
         return recentFilesList;
     }
-    
-    public void addRecentFile(String recentFile) {
-        if (!configuration.checkKey(RECENT_FILES_PROPERTY)) {
-            configuration.set(RECENT_FILES_PROPERTY, recentFile);
-            firePropertyChange(RECENT_FILES_PROPERTY, null, recentFile);
-        } else {
-            List<String> recentFilesList = getRecentFilesList();
-            if (!recentFilesList.contains(recentFile)) {            
-                if (getRecentFilesList().size() >= 10) {
-                    throw new IllegalArgumentException("Maximum number of recent files reached.");
-                }                                   
-                String oldValue = configuration.get(RECENT_FILES_PROPERTY);
-                String recentFiles = oldValue + "\n" + recentFile;
-                configuration.set(RECENT_FILES_PROPERTY, recentFiles);
-                firePropertyChange(RECENT_FILES_PROPERTY, oldValue, recentFile);
+
+    /**
+     * Get the ET station name.
+     *
+     * @return the ET station name
+     */
+    public String getStationName() {
+        return this.configuration.get(STATION_NAME_PROPERTY);
+    }
+
+    /**
+     * Get the ET station position.
+     *
+     * @return the ET station position
+     */
+    public Integer getStationPosition() {
+        return this.configuration.getInteger(STATION_POSITION_PROPERTY);
+    }
+
+    /**
+     * Get the steering file location (if using a file on disk).
+     *
+     * @return the XML file steering path
+     */
+    public String getSteeringFile() {
+        return this.configuration.get(STEERING_FILE_PROPERTY);
+    }
+
+    /**
+     * Get the steering resource (if using a jar resource).
+     *
+     * @return the steering resource location
+     */
+    public String getSteeringResource() {
+        return this.configuration.get(STEERING_RESOURCE_PROPERTY);
+    }
+
+    /**
+     * Get whether the steering is a file or resource.
+     *
+     * @return whether the steering is a file or resource
+     */
+    public SteeringType getSteeringType() {
+        return SteeringType.valueOf(this.configuration.get(STEERING_TYPE_PROPERTY));
+    }
+
+    /**
+     * Get the user run number for configuring the conditions system.
+     *
+     * @return the user run number for configuring the conditions system
+     */
+    public Integer getUserRunNumber() {
+        return this.configuration.getInteger(USER_RUN_NUMBER_PROPERTY);
+    }
+
+    /**
+     * Get the ET verbose flag.
+     *
+     * @return the ET verbose flag
+     */
+    public Boolean getVerbose() {
+        return this.configuration.getBoolean(VERBOSE_PROPERTY);
+    }
+
+    /**
+     * Get the ET wait mode.
+     *
+     * @return the ET wait mode
+     */
+    public Mode getWaitMode() {
+        return Mode.valueOf(this.configuration.get(WAIT_MODE_PROPERTY));
+    }
+
+    /**
+     * Get the ET wait time.
+     *
+     * @return the ET wait time
+     */
+    public Integer getWaitTime() {
+        return this.configuration.getInteger(WAIT_TIME_PROPERTY);
+    }
+
+    /**
+     * Return <code>true</code> if the given property key exists.
+     *
+     * @param key the property key
+     * @return <code>true</code> if property key exists (still might be <code>null</code>)
+     */
+    public boolean hasPropertyKey(final String key) {
+        return this.configuration.hasKey(key);
+    }
+
+    /**
+     * Return <code>true</code> if the given property key exists and is non-null.
+     *
+     * @param key the property key
+     * @return <code>true</code> if the property key exists and is non-null
+     */
+    public boolean hasValidProperty(final String key) {
+        return this.configuration.checkKey(key);
+    }
+
+    /**
+     * Merge another properties configuration into this one.
+     * <p>
+     * Settings from the merged properties will override this one.
+     *
+     * @param configuration the properties configuration to merge in
+     */
+    public void merge(final Configuration configuration) {
+        this.configuration.merge(configuration);
+        this.firePropertiesChanged(configuration.getKeys());
+    }
+
+    /**
+     * Remove the given property which should remove its key and value.
+     *
+     * @param property the property to remove
+     */
+    public void remove(final String property) {
+        if (this.hasPropertyKey(property)) {
+            final Object oldValue = this.configuration.get(property);
+            if (oldValue != null) {
+                this.configuration.remove(property);
+                this.firePropertyChange(property, oldValue, null);
             }
         }
-        
-    }
-    
-    public void setRecentFiles(String recentFiles) {
+    }
+
+    /**
+     * Set the name of the AIDA server.
+     *
+     * @param aidaServerName the name of the AIDA server
+     */
+    public void setAIDAServerName(final String aidaServerName) {
+        final String oldValue = this.getAIDAServerName();
+        this.configuration.set(AIDA_SERVER_NAME_PROPERTY, aidaServerName);
+        this.firePropertyChange(AIDA_SERVER_NAME_PROPERTY, oldValue, this.getAIDAServerName());
+    }
+
+    /**
+     * Set whether the ET station is blocking (generally this should not be set to <code>true</code>!)
+     *
+     * @param blocking <code>true</code> if station should be blocking
+     */
+    public void setBlocking(final Boolean blocking) {
+        final Boolean oldValue = this.getBlocking();
+        this.configuration.set(BLOCKING_PROPERTY, blocking);
+        this.firePropertyChange(BLOCKING_PROPERTY, oldValue, this.getBlocking());
+    }
+
+    /**
+     * The ET chunk size which is how many events should be returned at once in the array.
+     *
+     * @param chunkSize the ET chunk size
+     */
+    public void setChunkSize(final Integer chunkSize) {
+        final Integer oldValue = this.getChunkSize();
+        this.configuration.set(CHUNK_SIZE_PROPERTY, chunkSize);
+        this.firePropertyChange(CHUNK_SIZE_PROPERTY, oldValue, this.getChunkSize());
+    }
+
+    /**
+     * Set the conditions system tag.
+     *
+     * @param conditionsTag the conditions system tag
+     */
+    public void setConditionsTag(final String conditionsTag) {
+        final String oldValue = this.getConditionsTag();
+        this.configuration.set(CONDITIONS_TAG_PROPERTY, conditionsTag);
+        this.firePropertyChange(CONDITIONS_TAG_PROPERTY, oldValue, this.getConditionsTag());
+    }
+
+    /**
+     * Set a new configuration for the model which will fire property change events on all properties.
+     *
+     * @param configuration the configuration with properties for the model
+     */
+    public void setConfiguration(final Configuration configuration) {
+        this.configuration = configuration;
+        this.fireModelChanged();
+    }
+
+    /**
+     * Set the data source path which should be a valid EVIO or LCIO file on an accessible disk.
+     *
+     * @param dataSourcePath the data source path
+     */
+    public void setDataSourcePath(final String dataSourcePath) {
+        final String oldValue = this.getDataSourcePath();
+        this.configuration.set(DATA_SOURCE_PATH_PROPERTY, dataSourcePath);
+        this.firePropertyChange(DATA_SOURCE_PATH_PROPERTY, oldValue, this.getDataSourcePath());
+    }
+
+    /**
+     * Set the data source type (EVIO, LCIO or ET).
+     *
+     * @param dataSourceType the data source type
+     */
+    public void setDataSourceType(final DataSourceType dataSourceType) {
+        final DataSourceType oldValue = this.getDataSourceType();
+        this.configuration.set(DATA_SOURCE_TYPE_PROPERTY, dataSourceType);
+        this.firePropertyChange(DATA_SOURCE_TYPE_PROPERTY, oldValue, this.getDataSourceType());
+    }
+
+    /**
+     * Set the detector alias which is an alternate file path to use for the detector model instead of the one from jar.
+     *
+     * @param detectorAlias the detector alias
+     */
+    public void setDetectorAlias(final String detectorAlias) {
         String oldValue = null;
-        if (configuration.checkKey(RECENT_FILES_PROPERTY)) {
-            oldValue = configuration.get(RECENT_FILES_PROPERTY);
+        if (this.hasPropertyKey(DETECTOR_ALIAS_PROPERTY)) {
+            oldValue = this.getDetectorAlias();
         }
-        configuration.set(RECENT_FILES_PROPERTY, recentFiles);
-        firePropertyChange(RECENT_FILES_PROPERTY, oldValue, configuration.get(RECENT_FILES_PROPERTY));
-    }
-
-    public void remove(String property) {
-        if (hasPropertyKey(property)) {
-            Object oldValue = configuration.get(property);
-            if (oldValue != null) {
-                configuration.remove(property);
-                firePropertyChange(property, oldValue, null);
-            }
+        this.configuration.set(DETECTOR_ALIAS_PROPERTY, detectorAlias);
+        this.firePropertyChange(DETECTOR_ALIAS_PROPERTY, oldValue, this.getDetectorAlias());
+    }
+
+    /**
+     * Set the detector to load from the detector model resources in the jar.
+     * <p>
+     * These are present in the jar according to the LCSim convention:
+     *
+     * <pre>
+     * ${DETECTOR_NAME}/detector.properties
+     * </pre>
+     * <p>
+     * where <code>detector.properties</code> has the name of the detector matching the directory name.
+     *
+     * @param detectorName the name of the detector name
+     */
+    public void setDetectorName(final String detectorName) {
+        final String oldValue = this.getDetectorName();
+        this.configuration.set(DETECTOR_NAME_PROPERTY, detectorName);
+        this.firePropertyChange(DETECTOR_NAME_PROPERTY, oldValue, this.getDetectorName());
+    }
+
+    /**
+     * Set to <code>true</code> to disconnect when an EVIO END event is received.
+     *
+     * @param disconnectOnEndRun <code>true</code> to disconnect when an EVIO END event is received
+     */
+    public void setDisconnectOnEndRun(final Boolean disconnectOnEndRun) {
+        final Boolean oldValue = this.getDisconnectOnEndRun();
+        this.configuration.set(DISCONNECT_ON_END_RUN_PROPERTY, disconnectOnEndRun);
+        this.firePropertyChange(DISCONNECT_ON_END_RUN_PROPERTY, oldValue, this.getDisconnectOnEndRun());
+    }
+
+    /**
+     * Set to <code>true<code> to disconnect if event processing errors occur.
+     *
+     * @param disconnectOnError set to <code>true</code> to disconnect if event processing errors occur
+     */
+    public void setDisconnectOnError(final Boolean disconnectOnError) {
+        final Boolean oldValue = this.getDisconnectOnError();
+        this.configuration.set(DISCONNECT_ON_ERROR_PROPERTY, disconnectOnError);
+        this.firePropertyChange(DISCONNECT_ON_ERROR_PROPERTY, oldValue, this.getDisconnectOnError());
+    }
+
+    /**
+     * Set the name of the ET system which is usually a file.
+     * <p>
+     * Setting this to a valid file on disk being used by the ET server to buffer events will result in event processing
+     * speedup.
+     *
+     * @param etName the name of the ET system (usually a path on disk used as an event buffer by an ET server)
+     */
+    public void setEtName(final String etName) {
+        final String oldValue = this.getEtName();
+        this.configuration.set(ET_NAME_PROPERTY, etName);
+        this.firePropertyChange(ET_NAME_PROPERTY, oldValue, this.getEtName());
+    }
+
+    /**
+     * Set the fully qualified class name of the {@link org.hps.record.LCSimEventBuilder} that should be used to build
+     * LCIO events from EVIO.
+     *
+     * @param eventBuilderClassName the fully qualified class name of the event builder
+     */
+    public void setEventBuilderClassName(final String eventBuilderClassName) {
+        final String oldValue = this.getEventBuilderClassName();
+        this.configuration.set(EVENT_BUILDER_PROPERTY, eventBuilderClassName);
+        this.firePropertyChange(EVENT_BUILDER_PROPERTY, oldValue, this.getEventBuilderClassName());
+    }
+
+    /**
+     * Set to <code>true</code> to freeze the conditions system after initialization if there is also a valid detector
+     * name and run number setting.
+     *
+     * @param freezeConditions <code>true</code> to freeze the conditions
+     */
+    public void setFreezeConditions(final Boolean freezeConditions) {
+        Boolean oldValue = null;
+        if (this.hasPropertyKey(FREEZE_CONDITIONS_PROPERTY)) {
+            oldValue = this.getFreezeConditions();
         }
-    }
-
-    public boolean hasPropertyKey(String key) {
-        return configuration.hasKey(key);
-    }
-
-    public boolean hasValidProperty(String key) {
-        return configuration.checkKey(key);
-    }
-
-    @Override
-    public String[] getPropertyNames() {
-        return CONFIG_PROPERTIES;
-    }    
-    
-    public void fireModelChanged() {
-        firePropertiesChanged(configuration.getKeys());
-    }    
-    
-    public void merge(Configuration configuration) {
-        this.configuration.merge(configuration);
-        this.firePropertiesChanged(configuration.getKeys());
+        this.configuration.set(FREEZE_CONDITIONS_PROPERTY, freezeConditions);
+        this.firePropertyChange(FREEZE_CONDITIONS_PROPERTY, oldValue, freezeConditions);
+    }
+
+    /**
+     * Set the ET TCP/IP host name of the server.
+     *
+     * @param host the host name
+     */
+    public void setHost(final String host) {
+        final String oldValue = this.getHost();
+        this.configuration.set(HOST_PROPERTY, host);
+        this.firePropertyChange(HOST_PROPERTY, oldValue, this.getHost());
+    }
+
+    /**
+     * Set the log file name if using file logging.
+     *
+     * @param logFileName the log file name
+     */
+    public void setLogFileName(final String logFileName) {
+        final String oldValue = this.getLogFileName();
+        this.configuration.set(LOG_FILE_NAME_PROPERTY, logFileName);
+        this.firePropertyChange(LOG_FILE_NAME_PROPERTY, oldValue, this.getLogFileName());
+    }
+
+    /**
+     * Set the global log level.
+     *
+     * @param level the global log level
+     */
+    public void setLogLevel(final Level level) {
+        final Level oldValue = this.getLogLevel();
+        this.configuration.set(LOG_LEVEL_PROPERTY, level.getName());
+        this.firePropertyChange(LOG_LEVEL_PROPERTY, oldValue, this.getLogLevel());
+    }
+
+    /**
+     * Set log filter level for the log table.
+     *
+     * @param level the log filter level
+     */
+    public void setLogLevelFilter(final Level level) {
+        final Level oldValue = this.getLogLevelFilter();
+        this.configuration.set(LOG_LEVEL_FILTER_PROPERTY, level.getName());
+        this.firePropertyChange(LOG_LEVEL_FILTER_PROPERTY, oldValue, this.getLogLevelFilter());
+    }
+
+    /**
+     * Set to <code>true</code> to send global messages to a file instead of the console.
+     *
+     * @param logToFile <code>true</code> to log to file
+     */
+    public void setLogToFile(final Boolean logToFile) {
+        final Boolean oldValue = this.getLogToFile();
+        this.configuration.set(LOG_TO_FILE_PROPERTY, logToFile);
+        this.firePropertyChange(LOG_TO_FILE_PROPERTY, oldValue, this.getLogToFile());
+    }
+
+    /**
+     * Set the maximum number of events to process before the session will automatically end.
+     *
+     * @param maxEvents the maximum number of events
+     */
+    public void setMaxEvents(final Long maxEvents) {
+        final Long oldValue = this.getMaxEvents();
+        this.configuration.set(MAX_EVENTS_PROPERTY, maxEvents);
+        this.firePropertyChange(MAX_EVENTS_PROPERTY, oldValue, this.getMaxEvents());
+    }
+
+    /**
+     * Set the TCP/IP port number of the ET server for the client connection.
+     *
+     * @param port the ET port number
+     */
+    public void setPort(final Integer port) {
+        final Integer oldValue = this.getPort();
+        this.configuration.set(PORT_PROPERTY, port);
+        this.firePropertyChange(PORT_PROPERTY, oldValue, this.getPort());
+    }
+
+    /**
+     * Set a prescale value for the ET station which will decrease the event rate.
+     * <p>
+     * A prescale of 2 would mean every 2nd event is processed, etc.
+     *
+     * @param prescale the ET station prescale value
+     */
+    public void setPrescale(final Integer prescale) {
+        final Integer oldValue = this.getPrescale();
+        this.configuration.set(PRESCALE_PROPERTY, prescale);
+        this.firePropertyChange(PRESCALE_PROPERTY, oldValue, this.getPrescale());
+    }
+
+    /**
+     * Set the processing stage which determines which event processing stages are executed.
+     *
+     * @param processingStage the processing stage to execute
+     */
+    public void setProcessingStage(final String processingStage) {
+        final ProcessingStage oldValue = this.getProcessingStage();
+        this.configuration.set(PROCESSING_STAGE_PROPERTY, ProcessingStage.valueOf(processingStage));
+        this.firePropertyChange(PROCESSING_STAGE_PROPERTY, oldValue, this.getProcessingStage());
+    }
+
+    /**
+     * Set the ET queue size.
+     *
+     * @param queueSize the ET queue size
+     */
+    public void setQueueSize(final Integer queueSize) {
+        final Integer oldValue = this.getQueueSize();
+        this.configuration.set(QUEUE_SIZE_PROPERTY, queueSize);
+        this.firePropertyChange(QUEUE_SIZE_PROPERTY, oldValue, this.getQueueSize());
+    }
+
+    /**
+     * Set the recent files list, which is a list of "\n" delimited file paths.
+     *
+     * @param recentFiles the recent files list as a string
+     */
+    public void setRecentFiles(final String recentFiles) {
+        String oldValue = null;
+        if (this.configuration.checkKey(RECENT_FILES_PROPERTY)) {
+            oldValue = this.configuration.get(RECENT_FILES_PROPERTY);
+        }
+        this.configuration.set(RECENT_FILES_PROPERTY, recentFiles);
+        this.firePropertyChange(RECENT_FILES_PROPERTY, oldValue, this.configuration.get(RECENT_FILES_PROPERTY));
+    }
+
+    /**
+     * Set the recent files list.
+     * <p>
+     * This method is not part of the public API and is only used internally.
+     *
+     * @param recentFilesList the recent files list
+     */
+    private void setRecentFilesList(final List<String> recentFilesList) {
+        final StringBuffer sb = new StringBuffer();
+        for (final String recentFile : recentFilesList) {
+            sb.append(recentFile + "\n");
+        }
+        sb.setLength(sb.length() - 2);
+        this.configuration.set(RECENT_FILES_PROPERTY, sb.toString());
+    }
+
+    /**
+     * Set the ET station name.
+     *
+     * @param stationName the ET station name
+     */
+    public void setStationName(final String stationName) {
+        final String oldValue = this.getStationName();
+        this.configuration.set(STATION_NAME_PROPERTY, stationName);
+        this.firePropertyChange(STATION_NAME_PROPERTY, oldValue, this.getStationName());
+    }
+
+    /**
+     * Set the ET station position.
+     *
+     * @param stationPosition the ET station position
+     */
+    public void setStationPosition(final Integer stationPosition) {
+        final Integer oldValue = this.getStationPosition();
+        this.configuration.set(STATION_POSITION_PROPERTY, stationPosition);
+        this.firePropertyChange(STATION_POSITION_PROPERTY, oldValue, this.getStationPosition());
+    }
+
+    /**
+     * Set the steering file path.
+     *
+     * @param steeringFile the steering file path
+     */
+    public void setSteeringFile(final String steeringFile) {
+        final String oldValue = this.getSteeringFile();
+        this.configuration.set(STEERING_FILE_PROPERTY, steeringFile);
+        this.firePropertyChange(STEERING_FILE_PROPERTY, oldValue, this.getSteeringFile());
+    }
+
+    /**
+     * Set the steering file resource.
+     *
+     * @param steeringResource the steering file resource
+     */
+    public void setSteeringResource(final String steeringResource) {
+        final String oldValue = this.getSteeringResource();
+        this.configuration.set(STEERING_RESOURCE_PROPERTY, steeringResource);
+        this.firePropertyChange(STEERING_RESOURCE_PROPERTY, oldValue, steeringResource);
+    }
+
+    /**
+     * Set the steering type (file or resource).
+     *
+     * @param steeringType the steering type
+     * @see SteeringType
+     */
+    public void setSteeringType(final String steeringType) {
+        final SteeringType oldValue = this.getSteeringType();
+        this.configuration.set(STEERING_TYPE_PROPERTY, SteeringType.valueOf(steeringType));
+        this.firePropertyChange(STEERING_TYPE_PROPERTY, oldValue, this.getSteeringType());
+    }
+
+    /**
+     * Set a user run number which will be used to initialize the conditions system.
+     * <p>
+     * This should most likely be used with {@link #setFreezeConditions(Boolean)} or it is likely to be later overridden
+     * by run numbers from the data.
+     *
+     * @param userRunNumber the user run number
+     */
+    public void setUserRunNumber(final Integer userRunNumber) {
+        Integer oldValue = null;
+        if (this.hasPropertyKey(USER_RUN_NUMBER_PROPERTY)) {
+            oldValue = this.getUserRunNumber();
+        }
+        this.configuration.set(USER_RUN_NUMBER_PROPERTY, userRunNumber);
+        this.firePropertyChange(USER_RUN_NUMBER_PROPERTY, oldValue, this.getUserRunNumber());
+    }
+
+    /**
+     * Set verbose mode for the ET system.
+     *
+     * @param verbose the ET verbose flag
+     */
+    public void setVerbose(final Boolean verbose) {
+        final Boolean oldValue = this.getVerbose();
+        this.configuration.set(VERBOSE_PROPERTY, verbose);
+        this.firePropertyChange(VERBOSE_PROPERTY, oldValue, this.getVerbose());
+    }
+
+    /**
+     * Set the ET wait mode (timed, asynchronous or wait).
+     *
+     * @param waitMode the ET wait mode
+     */
+    public void setWaitMode(final String waitMode) {
+        final Mode oldValue = this.getWaitMode();
+        this.configuration.set(WAIT_MODE_PROPERTY, Mode.valueOf(waitMode));
+        this.firePropertyChange(WAIT_MODE_PROPERTY, oldValue, this.getWaitMode());
+    }
+
+    /**
+     * Set the ET wait time, which is ignored if wait mode is not timed.
+     *
+     * @param waitTime the ET wait time
+     */
+    public void setWaitTime(final Integer waitTime) {
+        final Integer oldValue = this.getWaitTime();
+        this.configuration.set(WAIT_TIME_PROPERTY, waitTime);
+        this.firePropertyChange(WAIT_TIME_PROPERTY, oldValue, this.getWaitTime());
     }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java	Tue Apr 21 14:48:39 2015
@@ -3,23 +3,46 @@
 import java.awt.Color;
 
 /**
- * This is the status of the connection to the ET server from the monitoring client,
- * and it includes a color that should be displayed in the GUI for the associated
- * text.
+ * This is the status of the connection to the ET server from the monitoring client, and it includes a color that should
+ * be displayed in the GUI for the associated text.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 public enum ConnectionStatus {
 
+    /**
+     * This is the state when the session is connected to event processing.
+     */
+    CONNECTED(Color.GREEN),
+    /**
+     * This is the disconnected state when event processing is not occurring.
+     */
     DISCONNECTED(Color.RED),
-    DISCONNECTING(Color.YELLOW),
-    CONNECTED(Color.GREEN);
-    
-    Color color;    
-    
-    ConnectionStatus(Color color) {
+    /**
+     * This is the state when the session is being torn down.
+     */
+    DISCONNECTING(Color.YELLOW);
+
+    /**
+     * The color that should be displayed in the GUI component for this state.
+     */
+    private Color color;
+
+    /**
+     * Class constructor.
+     *
+     * @param color the color to display for this state
+     */
+    private ConnectionStatus(final Color color) {
         this.color = color;
     }
-    
+
+    /**
+     * Get the color to display for this state.
+     *
+     * @return the color to display for this state
+     */
     public Color getColor() {
-        return color;
+        return this.color;
     }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java	Tue Apr 21 14:48:39 2015
@@ -4,62 +4,117 @@
 import java.beans.PropertyChangeListener;
 
 /**
- * This model updates listeners when the connection status changes from disconnected
- * to connected or vice versa.  It will also notify when the event processing is 
- * paused.
- * 
- * @author Jeremy McCormick <[log in to unmask]>
+ * This model updates listeners when the connection status changes from disconnected to connected or vice versa. It will
+ * also notify listeners when the event processing has been paused.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 public final class ConnectionStatusModel extends AbstractModel {
-    
+
+    /**
+     * The connection status property.
+     */
     public static final String CONNECTION_STATUS_PROPERTY = "ConnectionStatus";
+
+    /**
+     * The paused property.
+     */
     public static final String PAUSED_PROPERTY = "Paused";
-    
-    static final String[] propertyNames = new String[] { 
-        CONNECTION_STATUS_PROPERTY, 
-        PAUSED_PROPERTY 
-    };
 
-    ConnectionStatus connectionStatus = ConnectionStatus.DISCONNECTED;
-    boolean paused = false;
-    
+    /**
+     * The property names of this class.
+     */
+    private static final String[] PROPERTY_NAMES = new String[] {CONNECTION_STATUS_PROPERTY, PAUSED_PROPERTY};
+
+    /**
+     * The current connection status.
+     */
+    private ConnectionStatus connectionStatus = ConnectionStatus.DISCONNECTED;
+
+    /**
+     * Flag which is <code>true</code> when event processing is in the paused state.
+     */
+    private boolean paused = false;
+
+    /**
+     * Get the current connection status.
+     *
+     * @return the current connection status
+     */
+    public ConnectionStatus getConnectionStatus() {
+        return this.connectionStatus;
+    }
+
+    /**
+     * Return <code>true</code> if the event processing is currently paused.
+     *
+     * @return <code>true</code> if event processing is currently paused
+     */
+    public boolean getPaused() {
+        return this.paused;
+    }
+
+    /**
+     * Get the property names for this class.
+     *
+     * @return the property names for this class
+     */
+    @Override
     public String[] getPropertyNames() {
-        return propertyNames;
+        return PROPERTY_NAMES;
     }
-    
-    public ConnectionStatus getConnectionStatus() {
-        return connectionStatus;
+
+    /**
+     * Return <code>true</code> if the status is <code>CONNECTED</code>.
+     *
+     * @return <code>true</code> if status is <code>CONNECTED</code>
+     */
+    public boolean isConnected() {
+        return this.connectionStatus == ConnectionStatus.CONNECTED;
     }
-    
-    public void setConnectionStatus(ConnectionStatus connectionStatus) {
-        ConnectionStatus oldValue = connectionStatus;
+
+    /**
+     * Return <code>true</code> if the status is <code>DISCONNECTED</code>.
+     *
+     * @return <code>true</code> if the status is <code>DISCONNECTED</code>
+     */
+    public boolean isDisconnected() {
+        return this.connectionStatus == ConnectionStatus.DISCONNECTED;
+    }
+
+    /**
+     * Return <code>true</code> if the status is <code>DISCONNECTING</code>.
+     *
+     * @return <code>true</code> if the status is <code>DISCONNECTING</code>
+     */
+    public boolean isDisconnecting() {
+        return this.connectionStatus == ConnectionStatus.DISCONNECTING;
+    }
+
+    /**
+     * Set the connection status.
+     *
+     * @param connectionStatus the new connection status
+     */
+    public void setConnectionStatus(final ConnectionStatus connectionStatus) {
+        final ConnectionStatus oldValue = connectionStatus;
         this.connectionStatus = connectionStatus;
-        for (PropertyChangeListener listener : propertyChangeSupport.getPropertyChangeListeners()) {
-            listener.propertyChange(new PropertyChangeEvent(this, CONNECTION_STATUS_PROPERTY, oldValue, this.connectionStatus));
+        for (final PropertyChangeListener listener : this.getPropertyChangeSupport().getPropertyChangeListeners()) {
+            listener.propertyChange(new PropertyChangeEvent(this, CONNECTION_STATUS_PROPERTY, oldValue,
+                    this.connectionStatus));
         }
-    }        
-    
-    public boolean getPaused() {
-        return paused;
     }
-    
-    public void setPaused(boolean paused) {
-        boolean oldValue = this.paused;
+
+    /**
+     * Set to <code>true</code> if status is paused.
+     *
+     * @param paused <code>true</code> if status is paused
+     */
+    public void setPaused(final boolean paused) {
+        final boolean oldValue = this.paused;
         this.paused = paused;
-        for (PropertyChangeListener listener : propertyChangeSupport.getPropertyChangeListeners()) {
+        for (final PropertyChangeListener listener : this.getPropertyChangeSupport().getPropertyChangeListeners()) {
             listener.propertyChange(new PropertyChangeEvent(this, PAUSED_PROPERTY, oldValue, this.paused));
         }
     }
-    
-    public boolean isConnected() {
-        return this.connectionStatus == ConnectionStatus.CONNECTED;
-    }
-    
-    public boolean isDisconnected() {
-        return this.connectionStatus == ConnectionStatus.DISCONNECTED;
-    }
-    
-    public boolean isDisconnecting() {
-        return this.connectionStatus == ConnectionStatus.DISCONNECTING;
-    }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/HasConfigurationModel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/HasConfigurationModel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/HasConfigurationModel.java	Tue Apr 21 14:48:39 2015
@@ -2,18 +2,22 @@
 
 /**
  * Mix-in interface for classes that have an associated {@link ConfigurationModel}.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 public interface HasConfigurationModel {
 
     /**
-     * Set the ConfigurationModel of the object.
-     * @param configurationModel The ConfigurationModel.
+     * Get the current {@link ConfigurationModel} of the object.
+     *
+     * @return the associated {@link ConfigurationModel}
+     */
+    ConfigurationModel getConfigurationModel();
+
+    /**
+     * Set the {@link ConfigurationModel} of the object.
+     *
+     * @param configurationModel the new {@link ConfigurationModel}
      */
     void setConfigurationModel(ConfigurationModel configurationModel);
-
-    /**
-     * Get the current ConfigurationModel of the object.
-     * @return The ConfigurationModel.
-     */
-    ConfigurationModel getConfigurationModel();
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/RunModel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/RunModel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/RunModel.java	Tue Apr 21 14:48:39 2015
@@ -4,117 +4,258 @@
 
 /**
  * Backing model for run information that shows in the {@link org.hps.monitoring.application.EventDashboard}.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 public final class RunModel extends AbstractModel {
 
-    public final static String RUN_NUMBER_PROPERTY = "RunNumber";
-    public final static String START_DATE_PROPERTY = "StartDate";
-    public final static String END_DATE_PROPERTY = "EndDate";
-    public final static String RUN_LENGTH_PROPERTY = "RunLength"; // set at end, in seconds
-    public final static String TOTAL_EVENTS_PROPERTY = "TotalEvents"; // only set at end
-    public final static String EVENTS_RECEIVED_PROPERTY = "EventsReceived"; // events received so far
-    public final static String ELAPSED_TIME_PROPERTY = "ElapsedTime"; // updated on the fly, in seconds
-    public final static String DATA_RECEIVED_PROPERTY = "DataReceived"; // updated on the fly, in bytes
-    public final static String EVENT_NUMBER_PROPERTY = "EventNumber"; // current event number
-    public final static String DATA_RATE_PROPERTY = "DataRate"; // data rate in megabytes per second
-    public final static String EVENT_RATE_PROPERTY = "EventRate"; // event rate per second
-
-    static final String[] RUN_PROPERTIES = AbstractModel.getPropertyNames(RunModel.class);
-    
-    Integer runNumber;
-    Date startDate;
-    Date endDate;
-    Integer runLength;
-    Integer totalEvents;
-    Integer eventsReceived;
-    Integer elapsedTime;
-    Double dataReceived;
-    Integer eventNumber;
-    Double dataRate;
-    Double eventRate;
-
+    /**
+     * The data rate in megabytes per second.
+     */
+    public static final String DATA_RATE_PROPERTY = "DataRate";
+
+    /**
+     * The amount of data received in bytes since the last timer tick.
+     */
+    public static final String DATA_RECEIVED_PROPERTY = "DataReceived";
+
+    /**
+     * The total elapsed time in the session.
+     */
+    public static final String ELAPSED_TIME_PROPERTY = "ElapsedTime";
+
+    /**
+     * The end date of the run which comes from the EVIO END record.
+     */
+    public static final String END_DATE_PROPERTY = "EndDate";
+
+    /**
+     * The event number currently being processed which usually comes from the EVIO or LCIO records.
+     */
+    public static final String EVENT_NUMBER_PROPERTY = "EventNumber";
+
+    /**
+     * The event rate in Hertz.
+     */
+    public static final String EVENT_RATE_PROPERTY = "EventRate";
+
+    /**
+     * The total number of events received in the session.
+     */
+    public static final String EVENTS_RECEIVED_PROPERTY = "EventsReceived";
+
+    /**
+     * The total length of the run which is set from the EVIO END record.
+     */
+    public static final String RUN_LENGTH_PROPERTY = "RunLength";
+
+    /**
+     * The run number which comes from the EVIO control data.
+     */
+    public static final String RUN_NUMBER_PROPERTY = "RunNumber";
+
+    /**
+     * The properties of this model.
+     */
+    private static final String[] RUN_PROPERTIES = AbstractModel.getPropertyNames(RunModel.class);
+
+    /**
+     * The start date of the run which comes from the EVIO PRESTART event.
+     */
+    public static final String START_DATE_PROPERTY = "StartDate";
+
+    /**
+     * The total events in the run which comes from the EVIO END event.
+     */
+    public static final String TOTAL_EVENTS_PROPERTY = "TotalEvents";
+
+    /**
+     * The data rate in MB/s.
+     */
+    private Double dataRate;
+
+    /**
+     * The data received in bytes.
+     */
+    private Double dataReceived;
+
+    /**
+     * The elapsed time in seconds.
+     */
+    private Integer elapsedTime;
+
+    /**
+     * The end date of the run.
+     */
+    private Date endDate;
+
+    /**
+     * The current event number.
+     */
+    private Integer eventNumber;
+
+    /**
+     * The event rate in Hertz.
+     */
+    private Double eventRate;
+
+    /**
+     * The number of events received.
+     */
+    private Integer eventsReceived;
+
+    /**
+     * The length of the run.
+     */
+    private Integer runLength;
+
+    /**
+     * The run number.
+     */
+    private Integer runNumber;
+
+    /**
+     * The run start date.
+     */
+    private Date startDate;
+
+    /**
+     * The total events received in the run.
+     */
+    private Integer totalEvents;
+
+    /**
+     * Add data received in bytes.
+     *
+     * @param addDataReceived the amount of data received in bytes
+     */
+    public void addDataReceived(final double addDataReceived) {
+        this.setDataReceived(this.dataReceived + addDataReceived);
+    }
+
+    /**
+     * Compute the run length from the start and end date and set its value in the GUI.
+     */
+    public void computeRunLength() {
+        if (this.startDate != null && this.endDate != null) {
+            final long elapsedMillis = this.endDate.getTime() - this.startDate.getTime();
+            final int elapsedSeconds = (int) (elapsedMillis / 1000.);
+            this.setRunLength(elapsedSeconds);
+        }
+    }
+
+    /**
+     * Get the data rate in MB/s.
+     *
+     * @return the data rate in MB/s
+     */
+    public double getDataRate() {
+        return this.dataRate;
+    }
+
+    /**
+     * Get the data received in bytes.
+     *
+     * @return the data received in bytes
+     */
+    public double getDataReceived() {
+        return this.dataReceived;
+    }
+
+    /**
+     * Get the elapsed time in seconds.
+     *
+     * @return the elapsed time in seconds
+     */
+    public int getElapsedTime() {
+        return this.elapsedTime;
+    }
+
+    /**
+     * Get the run end date.
+     *
+     * @return the run end date
+     */
+    public Date getEndDate() {
+        return this.endDate;
+    }
+
+    /**
+     * Get the current event number.
+     *
+     * @return the current event number
+     */
+    public int getEventNumber() {
+        return this.eventNumber;
+    }
+
+    /**
+     * Get the event rate in Hertz.
+     *
+     * @return the event rate in Hertz
+     */
+    public double getEventRate() {
+        return this.eventRate;
+    }
+
+    /**
+     * Get the number of events received in the session.
+     *
+     * @return the number of events received
+     */
+    public int getEventsReceived() {
+        return this.eventsReceived;
+    }
+
+    /**
+     * Get the property names for this model.
+     *
+     * @return the property names for this model
+     */
+    @Override
     public String[] getPropertyNames() {
         return RUN_PROPERTIES;
     }
 
-    public void setRunNumber(int runNumber) {
-        Integer oldValue = this.runNumber;
-        this.runNumber = runNumber;
-        this.firePropertyChange(RUN_NUMBER_PROPERTY, oldValue, this.runNumber);
-    }
-
-    public void setStartDate(Date startDate) {
-        Date oldValue = this.startDate;
-        this.startDate = startDate;
-        this.firePropertyChange(START_DATE_PROPERTY, oldValue, this.startDate);
-    }
-
-    public void setEndDate(Date endDate) {
-        Date oldValue = this.endDate;
-        this.endDate = endDate;
-        this.firePropertyChange(END_DATE_PROPERTY, oldValue, this.endDate);
-    }
-
-    public void setRunLength(int runLength) {
-        Integer oldValue = this.runLength;
-        this.runLength = runLength;
-        this.firePropertyChange(RUN_LENGTH_PROPERTY, oldValue, this.runLength);
-    }
-
-    public void computeRunLength() {
-        if (startDate != null && endDate != null) {
-            long elapsedMillis = endDate.getTime() - startDate.getTime();
-            int elapsedSeconds = (int) ((double) elapsedMillis / 1000.);
-            this.setRunLength(elapsedSeconds);
-        }
-    }
-
-    public void setTotalEvents(int totalEvents) {
-        Integer oldValue = this.totalEvents;
-        this.totalEvents = totalEvents;
-        this.firePropertyChange(TOTAL_EVENTS_PROPERTY, oldValue, this.totalEvents);
-    }
-
-    public void setEventsReceived(int eventsReceived) {
-        Integer oldValue = this.eventsReceived;
-        this.eventsReceived = eventsReceived;
-        this.firePropertyChange(EVENTS_RECEIVED_PROPERTY, oldValue, this.eventsReceived);
-    }
-
-    public void setElapsedTime(int elapsedTime) {
-        Integer oldValue = this.elapsedTime;
-        this.elapsedTime = elapsedTime;
-        this.firePropertyChange(ELAPSED_TIME_PROPERTY, oldValue, this.elapsedTime);
-    }
-
-    public void setDataReceived(double dataReceived) {
-        Double oldValue = this.dataReceived;
-        this.dataReceived = dataReceived;
-        this.firePropertyChange(DATA_RECEIVED_PROPERTY, oldValue, this.dataReceived);
-    }
-
-    public void addDataReceived(double addDataReceived) {
-        this.setDataReceived(dataReceived + addDataReceived);
-    }
-
-    public void setEventNumber(int eventNumber) {
-        Integer oldValue = this.eventNumber;
-        this.eventNumber = eventNumber;
-        this.firePropertyChange(EVENT_NUMBER_PROPERTY, oldValue, this.eventNumber);
-    }
-    
-    public void setDataRate(double dataRate) {
-        Double oldValue = this.dataRate;
-        this.dataRate = dataRate;
-        this.firePropertyChange(DATA_RATE_PROPERTY, oldValue, this.dataRate);
-    }
-        
-    public void setEventRate(double eventRate) {
-        Double oldValue = this.eventRate;
-        this.eventRate = eventRate;
-        this.firePropertyChange(EVENT_RATE_PROPERTY, oldValue, this.eventRate);
-    }
-    
+    /**
+     * Get the run length in seconds.
+     *
+     * @return the run length in seconds
+     */
+    public int getRunLength() {
+        return this.runLength;
+    }
+
+    /**
+     * Get the run number.
+     *
+     * @return the run number
+     */
+    public int getRunNumber() {
+        return this.runNumber;
+    }
+
+    /**
+     * Get the start date.
+     *
+     * @return the start date
+     */
+    public Date getStartDate() {
+        return this.startDate;
+    }
+
+    /**
+     * Get the total events in the run.
+     *
+     * @return the total events in the run
+     */
+    public int getTotalEvents() {
+        return this.totalEvents;
+    }
+
+    /**
+     * Reset the model for new run.
+     */
     public void reset() {
         setDataReceived(0);
         setElapsedTime(0);
@@ -125,4 +266,125 @@
         setStartDate(null);
         setTotalEvents(0);
     }
-}
+
+    /**
+     * Set the data rate in MB/s.
+     *
+     * @param dataRate the data rate in MB/s
+     */
+    public void setDataRate(final double dataRate) {
+        final Double oldValue = this.dataRate;
+        this.dataRate = dataRate;
+        this.firePropertyChange(DATA_RATE_PROPERTY, oldValue, this.dataRate);
+    }
+
+    /**
+     * Set the data received in bytes.
+     *
+     * @param dataReceived the data received in bytes
+     */
+    public void setDataReceived(final double dataReceived) {
+        final Double oldValue = this.dataReceived;
+        this.dataReceived = dataReceived;
+        this.firePropertyChange(DATA_RECEIVED_PROPERTY, oldValue, this.dataReceived);
+    }
+
+    /**
+     * Set the elapsed time in seconds.
+     *
+     * @param elapsedTime the elapsed time in seconds
+     */
+    public void setElapsedTime(final int elapsedTime) {
+        final Integer oldValue = this.elapsedTime;
+        this.elapsedTime = elapsedTime;
+        this.firePropertyChange(ELAPSED_TIME_PROPERTY, oldValue, this.elapsedTime);
+    }
+
+    /**
+     * Set the run end date.
+     *
+     * @param endDate the run end date
+     */
+    public void setEndDate(final Date endDate) {
+        final Date oldValue = this.endDate;
+        this.endDate = endDate;
+        this.firePropertyChange(END_DATE_PROPERTY, oldValue, this.endDate);
+    }
+
+    /**
+     * Set the current event number.
+     *
+     * @param eventNumber the current event number
+     */
+    public void setEventNumber(final int eventNumber) {
+        final Integer oldValue = this.eventNumber;
+        this.eventNumber = eventNumber;
+        this.firePropertyChange(EVENT_NUMBER_PROPERTY, oldValue, this.eventNumber);
+    }
+
+    /**
+     * Set the event rate in Hertz.
+     *
+     * @param eventRate the event rate in Hertz
+     */
+    public void setEventRate(final double eventRate) {
+        final Double oldValue = this.eventRate;
+        this.eventRate = eventRate;
+        this.firePropertyChange(EVENT_RATE_PROPERTY, oldValue, this.eventRate);
+    }
+
+    /**
+     * Set the number of events received.
+     *
+     * @param eventsReceived the number of events received
+     */
+    public void setEventsReceived(final int eventsReceived) {
+        final Integer oldValue = this.eventsReceived;
+        this.eventsReceived = eventsReceived;
+        this.firePropertyChange(EVENTS_RECEIVED_PROPERTY, oldValue, this.eventsReceived);
+    }
+
+    /**
+     * Set the length of the run in seconds.
+     *
+     * @param runLength the length of the run in seconds
+     */
+    public void setRunLength(final int runLength) {
+        final Integer oldValue = this.runLength;
+        this.runLength = runLength;
+        this.firePropertyChange(RUN_LENGTH_PROPERTY, oldValue, this.runLength);
+    }
+
+    /**
+     * Set the run number.
+     *
+     * @param runNumber the run number
+     */
+    public void setRunNumber(final int runNumber) {
+        final Integer oldValue = this.runNumber;
+        this.runNumber = runNumber;
+        this.firePropertyChange(RUN_NUMBER_PROPERTY, oldValue, this.runNumber);
+    }
+
+    /**
+     * Set the start date.
+     *
+     * @param startDate the start date
+     */
+    public void setStartDate(final Date startDate) {
+        final Date oldValue = this.startDate;
+        this.startDate = startDate;
+        this.firePropertyChange(START_DATE_PROPERTY, oldValue, this.startDate);
+    }
+
+    /**
+     * Set the total number of events in the run.
+     *
+     * @param totalEvents the total number of events in the run
+     */
+    public void setTotalEvents(final int totalEvents) {
+        final Integer oldValue = this.totalEvents;
+        this.totalEvents = totalEvents;
+        this.firePropertyChange(TOTAL_EVENTS_PROPERTY, oldValue, this.totalEvents);
+    }
+}

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SteeringType.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SteeringType.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SteeringType.java	Tue Apr 21 14:48:39 2015
@@ -2,8 +2,16 @@
 
 /**
  * The type of steering to use for event processing.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 public enum SteeringType {
-    RESOURCE,
-    FILE;
+    /**
+     * Steering from local file on disk.
+     */
+    FILE,
+    /**
+     * Steering from resource in jar file.
+     */
+    RESOURCE;
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SystemStatusTableModel.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SystemStatusTableModel.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/model/SystemStatusTableModel.java	Tue Apr 21 14:48:39 2015
@@ -2,7 +2,6 @@
 
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -16,74 +15,164 @@
 
 /**
  * A <code>JTableModel</code> that has a list of {@link org.hps.monitoring.subsys.SystemStatus} objects.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
+@SuppressWarnings("serial")
 public final class SystemStatusTableModel extends AbstractTableModel implements SystemStatusListener {
 
-    public static final int RESET_COL = 0;
-    public static final int ACTIVE_COL = 1;
-    public static final int STATUS_COL = 2;
-    public static final int SYSTEM_COL = 3;
-    public static final int DESCRIPTION_COL = 4;
-    public static final int MESSAGE_COL = 5;
-    public static final int LAST_CHANGED_COL = 6;
-    public static final int CLEARABLE_COL = 7;
-
-    static final String[] columnNames = { "Reset", "Active", "Status", "System", "Description", "Message", "Last Changed", "Clearable" };
-
-    List<SystemStatus> statuses = new ArrayList<SystemStatus>();
-    final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS");
-
-    public void addSystemStatus(SystemStatus status) {
-        statuses.add(status);
+    /**
+     * Active field column index.
+     */
+    public static final int ACTIVE_COLUMN_INDEX = 1;
+
+    /**
+     * Clearable field column index.
+     */
+    public static final int CLEARABLE_COLUMN_INDEX = 7;
+
+    /**
+     * The names of the columns.
+     */
+    private static final String[] COLUMN_NAMES = {"Reset", "Active", "Status", "System", "Description", "Message",
+            "Last Changed", "Clearable"};
+
+    /**
+     * Description column index.
+     */
+    public static final int DESCRIPTION_COLUMN_INDEX = 4;
+
+    /**
+     * Last changed field column index.
+     */
+    public static final int LAST_CHANGED_COLUMN_INDEX = 6;
+
+    /**
+     * Message field column index.
+     */
+    public static final int MESSAGE_COLUMN_INDEX = 5;
+
+    /**
+     * Reset field column index.
+     */
+    public static final int RESET_COLUMN_INDEX = 0;
+
+    /**
+     * Status field column index.
+     */
+    public static final int STATUS_COLUMN_INDEX = 2;
+
+    /**
+     * System field column index.
+     */
+    public static final int SYSTEM_COLUMN_INDEX = 3;
+
+    /**
+     * The list of system status objects that back the model.
+     */
+    private final List<SystemStatus> statuses = new ArrayList<SystemStatus>();
+
+    /**
+     * Add a system status to the model.
+     *
+     * @param status the system status to add to the model
+     */
+    public void addSystemStatus(final SystemStatus status) {
+        this.statuses.add(status);
         status.addListener(this);
         fireTableDataChanged();
     }
 
+    /**
+     * Clear all the data in the model.
+     */
+    public void clear() {
+        this.statuses.clear();
+        fireTableDataChanged();
+    }
+
+    /**
+     * Get the class of the column.
+     *
+     * @param columnIndex the index of the column
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    @Override
+    public Class getColumnClass(final int columnIndex) {
+        switch (columnIndex) {
+        case ACTIVE_COLUMN_INDEX:
+            return Boolean.class;
+        case LAST_CHANGED_COLUMN_INDEX:
+            return Date.class;
+        default:
+            return String.class;
+        }
+    }
+
+    /**
+     * Get the column count.
+     *
+     * @return the column count
+     */
+    @Override
+    public int getColumnCount() {
+        return COLUMN_NAMES.length;
+    }
+
+    /**
+     * Get the column name.
+     *
+     * @param columnIndex the column index
+     */
+    @Override
+    public String getColumnName(final int columnIndex) {
+        return COLUMN_NAMES[columnIndex];
+    }
+
+    /**
+     * Get the row count.
+     *
+     * @return the row count
+     */
     @Override
     public int getRowCount() {
-        return statuses.size();
-    }
-
-    @Override
-    public int getColumnCount() {
-        return columnNames.length;
-    }
-
-    @Override
-    public String getColumnName(int col) {
-        return columnNames[col];
-    }
-
+        return this.statuses.size();
+    }
+
+    /**
+     * Get a table cell value.
+     *
+     * @param rowIndex the row index
+     * @param columnIndex the column index
+     */
     @Override
     public Object getValueAt(final int rowIndex, final int columnIndex) {
-        SystemStatus status = statuses.get(rowIndex);
+        final SystemStatus status = this.statuses.get(rowIndex);
         switch (columnIndex) {
-        case ACTIVE_COL:
+        case ACTIVE_COLUMN_INDEX:
             return status.isActive();
-        case STATUS_COL:
+        case STATUS_COLUMN_INDEX:
             return status.getStatusCode().name();
-        case SYSTEM_COL:
+        case SYSTEM_COLUMN_INDEX:
             return status.getSubsystem().name();
-        case DESCRIPTION_COL:
+        case DESCRIPTION_COLUMN_INDEX:
             return status.getDescription();
-        case MESSAGE_COL:
+        case MESSAGE_COLUMN_INDEX:
             return status.getMessage();
-        case LAST_CHANGED_COL:
+        case LAST_CHANGED_COLUMN_INDEX:
             return new Date(status.getLastChangedMillis());
-        case RESET_COL:
-            // If the status is clearable, then it has a button that can be used to
-            // manually set the state to CLEARED. If the status is not clearable,
+        case RESET_COLUMN_INDEX:
+            // If the status is clear-able, then the cell has a button which can be used to
+            // manually set the state to CLEARED. If the status cannot be cleared,
             // then nothing is rendered in this cell.
             if (status.isClearable()) {
                 final JButton button = new JButton();
                 button.addActionListener(new ActionListener() {
-                    public void actionPerformed(ActionEvent e) {
-                        SystemStatus status = statuses.get(rowIndex);
-                        // Only clearable statuses can have this state set. Check for this
-                        // just to be safe, even though no button is available for non-clearable
-                        // statuses.
+                    @Override
+                    public void actionPerformed(final ActionEvent e) {
+                        final SystemStatus status = SystemStatusTableModel.this.statuses.get(rowIndex);
                         if (status.isClearable()) {
-                            StatusCode oldStatusCode = status.getStatusCode();
+                            final StatusCode oldStatusCode = status.getStatusCode();
                             status.setStatus(StatusCode.CLEARED, "Cleared from " + oldStatusCode.name() + " state.");
                         }
                     }
@@ -92,48 +181,45 @@
             } else {
                 return null;
             }
-        case CLEARABLE_COL:
+        case CLEARABLE_COLUMN_INDEX:
             return status.isClearable();
         default:
             return null;
         }
     }
 
-    @Override
-    public Class getColumnClass(int column) {
-        switch (column) {
-        case ACTIVE_COL:
-            return Boolean.class;
-        case LAST_CHANGED_COL:
-            return Date.class;
-        default:
-            return String.class;
+    /**
+     * Return <code>true</code> if cell is editable.
+     *
+     * @return <code>true</code> if cell is editable
+     */
+    @Override
+    public boolean isCellEditable(final int rowIndex, final int columnIndex) {
+        return columnIndex == ACTIVE_COLUMN_INDEX;
+    }
+
+    /**
+     * Set the table cell value.
+     *
+     * @param value the new value
+     * @param rowIndex the row index
+     * @param columnIndex the column index
+     */
+    @Override
+    public void setValueAt(final Object value, final int rowIndex, final int columnIndex) {
+        if (columnIndex == ACTIVE_COLUMN_INDEX) {
+            this.statuses.get(rowIndex).setActive((Boolean) value);
         }
     }
 
-    @Override
-    public boolean isCellEditable(int row, int col) {
-        if (col == ACTIVE_COL)
-            return true;
-        else
-            return false;
-    }
-
-    @Override
-    public void statusChanged(SystemStatus status) {
-        int rowNumber = statuses.indexOf(status);
+    /**
+     * Notify of system status changed.
+     *
+     * @param status the system status that changed
+     */
+    @Override
+    public void statusChanged(final SystemStatus status) {
+        final int rowNumber = this.statuses.indexOf(status);
         fireTableRowsUpdated(rowNumber, rowNumber);
     }
-
-    public void clear() {
-        statuses.clear();
-        fireTableDataChanged();
-    }
-
-    @Override
-    public void setValueAt(Object value, int row, int col) {
-        if (col == ACTIVE_COL) {
-            statuses.get(row).setActive((Boolean) value);
-        }
-    }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/package-info.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/package-info.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/package-info.java	Tue Apr 21 14:48:39 2015
@@ -1,22 +1,20 @@
 /**
- * The Monitoring Application is a flexible framework for monitoring the 
- * event processing chain of the HPS experiment.  It implements the conversion
- * of ET byte buffers to EVIO and then the building of LCIO events from the 
- * raw EVIO data.
- * <p>  
- * It provides three primary GUI components: 
+ * The Monitoring Application is a flexible framework for monitoring the event processing chain of the HPS experiment in
+ * an online environment. It implements the conversion of ET byte buffers to EVIO and then the building of LCIO events
+ * from the raw EVIO data.
+ * <p>
+ * It provides three primary GUI components:
  * <ul>
  * <li>run dashboard showing basic information about data received</li>
- * <li>system status monitor that can monitor the status of specific subsystems</li>
+ * <li>tab panel showing various information panels</li>
  * <li>plotting window that displays any plots generated through the AIDA API</li>
  * </ul>
  * <p>
- * The FreeHep framework is used extensively for the record processing.  Every part
- * of the event processing chain uses the
- * <a href="http://java.freehep.org/freehep-record/">freehep-record</a>
- * module to manage the flow of records and activate any processors that are listening
- * on the record loops.
+ * The FreeHep framework is used extensively for the record processing. Every part of the event processing chain uses
+ * the <a href="http://java.freehep.org/freehep-record/">freehep-record</a> module to manage the flow of records and
+ * activate any processors that are listening on the record loops.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
+ */
+package org.hps.monitoring.application;
 
- * @author Jeremy McCormick <[log in to unmask]>
- */
-package org.hps.monitoring.application;

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/AIDAServer.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/AIDAServer.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/AIDAServer.java	Tue Apr 21 14:48:39 2015
@@ -11,69 +11,90 @@
 
 /**
  * AIDA RMI server wrapper.
- * @author Jeremy McCormick <[log in to unmask]>
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
-public class AIDAServer {
-    
-    RmiServerImpl server;
-    String name;
-    boolean connected = false;
-   
+public final class AIDAServer {
+
     /**
-     * Class constructor. 
-     * @param name The name of the AIDA server.
+     * Connected flag.
      */
-    public AIDAServer(String name) {
+    private boolean connected = false;
+
+    /**
+     * The name of the server.
+     */
+    private String name;
+
+    /**
+     * The RMI server object.
+     */
+    private RmiServerImpl server;
+
+    /**
+     * Class constructor.
+     *
+     * @param name the name of the AIDA server
+     */
+    public AIDAServer(final String name) {
         this.name = name;
     }
-    
+
+    /**
+     * Return <code>true</code> if connected.
+     *
+     * @return <code>true</code> if connected to server
+     */
+    public boolean connected() {
+        return this.connected;
+    }
+
+    /**
+     * Close the server down by disconnecting it.
+     */
+    public void disconnect() {
+        this.server.disconnect();
+        this.connected = false;
+    }
+
+    /**
+     * Get the server name as a string.
+     *
+     * @return the server name
+     */
+    public String getName() {
+        try {
+            return InetAddress.getLocalHost().getCanonicalHostName() + this.server.getBindName() + ":"
+                    + RmiRemoteUtils.port;
+        } catch (final Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
     /**
      * Set the name that will be used for the path part of the URL.
+     *
      * @param name The server's name.
      */
-    public void setName(String name) {
+    public void setName(final String name) {
         this.name = name;
     }
 
     /**
      * Start the remote AIDA server.
-     * @return True if server started successfully; false if an error occurred during initialization.
+     *
+     * @return <code>true</code> if server started successfully; false if an error occurred during initialization.
      */
     public boolean start() {
-        RemoteServer treeServer = new RemoteServer((IDevTree) AIDA.defaultInstance().tree());
+        final RemoteServer treeServer = new RemoteServer((IDevTree) AIDA.defaultInstance().tree());
         try {
-            server = new RmiServerImpl(treeServer, "/" + name);
-            connected = true;
+            this.server = new RmiServerImpl(treeServer, "/" + this.name);
+            this.connected = true;
+        } catch (final Exception e) {
+            e.printStackTrace();
+            this.connected = false;
         }
-        catch (Exception e) {
-            e.printStackTrace();
-            connected = false;
-        }
-        return connected;
-    }
-    
-    /** 
-     * Close the server down by disconnecting it.
-     */
-    public void disconnect() {
-        server.disconnect();
-        connected = false;
-    }
-    
-    /**
-     * True if connected.
-     * @return True if connected to server.
-     */
-    public boolean connected() {
-        return connected;
-    }    
-    
-    public String getName() {
-        try {
-            return InetAddress.getLocalHost().getCanonicalHostName() + server.getBindName() + ":" + RmiRemoteUtils.port;
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-        return null;
+        return this.connected;
     }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/DialogUtil.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/DialogUtil.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/DialogUtil.java	Tue Apr 21 14:48:39 2015
@@ -7,27 +7,102 @@
 import javax.swing.JDialog;
 import javax.swing.JOptionPane;
 import javax.swing.SwingUtilities;
+import javax.swing.WindowConstants;
 
+/**
+ * This is a set of utility methods for creating Swing dialog windows.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
+ */
 public final class DialogUtil {
 
     /**
-     * 
-     * @param parentComponent
-     * @param title
-     * @param message
-     * @return
+     * Show a confirmation dialog.
+     *
+     * @param parent the parent component
+     * @param message the message
+     * @param title the title of the dialog
+     * @return the result from the user's dialog selection
      */
-    public static JDialog showStatusDialog(final Component parentComponent, String title, String message) {
-        final JOptionPane optionPane = new JOptionPane(message, JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION, null, new Object[] {}, null);
+    public static int showConfirmationDialog(final Component parent, final String title, final String message) {
+        final Object[] options = { "Yes", "No", "Cancel" };
+        final int result = JOptionPane.showOptionDialog(parent, message, title, JOptionPane.YES_NO_CANCEL_OPTION,
+                JOptionPane.QUESTION_MESSAGE, null, options, options[2]);
+        return result;
+    }
+
+    /**
+     * Show an error dialog.
+     *
+     * @param component the parent component
+     * @param error the error message
+     * @param title the title of the dialog
+     */
+    public static void showErrorDialog(final Component component, final String title, final String message) {
+        final Runnable runnable = new Runnable() {
+            @Override
+            public void run() {
+                JOptionPane.showMessageDialog(component, message, title, JOptionPane.ERROR_MESSAGE);
+            }
+        };
+        SwingUtilities.invokeLater(runnable);
+    }
+
+    /**
+     * Show an error dialog with an associated thrown object.
+     *
+     * @param component the parent component
+     * @param error the <code>Throwable</code> error
+     * @param title the title of the dialog
+     */
+    public static void showErrorDialog(final Component component, final Throwable error, final String title) {
+        final Runnable runnable = new Runnable() {
+            @Override
+            public void run() {
+                JOptionPane.showMessageDialog(component, error.getMessage(), title, JOptionPane.ERROR_MESSAGE);
+            }
+        };
+        SwingUtilities.invokeLater(runnable);
+    }
+
+    /**
+     * Show an information dialog.
+     *
+     * @param component the parent component
+     * @param title the title of the dialog
+     * @param message the message
+     */
+    public static void showInfoDialog(final Component component, final String title, final String message) {
+        final Runnable runnable = new Runnable() {
+            @Override
+            public void run() {
+                JOptionPane.showMessageDialog(component, message, title, JOptionPane.INFORMATION_MESSAGE);
+            }
+        };
+        SwingUtilities.invokeLater(runnable);
+    }
+
+    /**
+     * Show a status dialog which will block GUI interaction.
+     *
+     * @param parentComponent the parent component
+     * @param title the title of the dialog
+     * @param message the message
+     * @return the dialog window component
+     */
+    public static JDialog showStatusDialog(final Component parentComponent, final String title, final String message) {
+        final JOptionPane optionPane = new JOptionPane(message, JOptionPane.INFORMATION_MESSAGE,
+                JOptionPane.DEFAULT_OPTION, null, new Object[] {}, null);
         final JDialog dialog = new JDialog();
         dialog.setContentPane(optionPane);
         dialog.setTitle(title);
         dialog.setAlwaysOnTop(true);
         dialog.setLocationRelativeTo(null);
-        dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+        dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
         dialog.pack();
         dialog.addWindowListener(new WindowAdapter() {
-            public void windowClosing(WindowEvent e) {
+            @Override
+            public void windowClosing(final WindowEvent e) {
                 dialog.setVisible(false);
                 dialog.dispose();
                 parentComponent.setEnabled(true);
@@ -40,68 +115,9 @@
     }
 
     /**
-     * 
-     * @param component
-     * @param error
-     * @param title
+     * Do not allow class instantiation.
      */
-    public static void showErrorDialog(final Component component, final Throwable error, final String title) {
-        final Runnable runnable = new Runnable() {
-            public void run() {
-                JOptionPane.showMessageDialog(component, error.getMessage(), title, JOptionPane.ERROR_MESSAGE);
-            }
-        };
-        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);
-    }
-
-    /**
-     * 
-     * @param component
-     * @param title
-     * @param message
-     */
-    public static void showInfoDialog(final Component component, final String title, final String message) {
-        final Runnable runnable = new Runnable() {
-            public void run() {
-                JOptionPane.showMessageDialog(component, message, title, JOptionPane.INFORMATION_MESSAGE);
-            }
-        };
-        SwingUtilities.invokeLater(runnable);
-    }
-    
-    /**
-     * 
-     * @param parent
-     * @param message
-     * @param title
-     * @return
-     */
-    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, 
-                JOptionPane.YES_NO_CANCEL_OPTION, 
-                JOptionPane.QUESTION_MESSAGE, 
-                null, 
-                options, 
-                options[2]);
-        return result;
+    private DialogUtil() {
+        throw new UnsupportedOperationException("Do not instantiate this class.");
     }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ErrorHandler.java	Tue Apr 21 14:48:39 2015
@@ -8,10 +8,9 @@
 import javax.swing.SwingUtilities;
 
 /**
+ * An error handling class which is able to do any of the following, depending on how the users wants to handle the
+ * error.
  * <p>
- * An error handling class which is able to do any of the following, depending on how the users
- * wants to handle the error.
- * </p>
  * <ul>
  * <li>Print a message</li>
  * <li>Print the stack trace</li>
@@ -20,97 +19,130 @@
  * <li>Raise an exception</li>
  * <li>Exit the application</li>
  * </ul>
- * </p> It mostly uses the "builder" pattern so that the various handling methods can be easily
- * chained, where appropriate. Some methods are not available for chaining when it doesn't make
- * sense. </p>
+ * <p>
+ * It mostly uses the "builder" pattern so that the various handling methods can be easily chained, where appropriate.
+ * Some methods are not available for chaining when it doesn't make sense.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 public final class ErrorHandler {
 
-    Logger logger;
-    Component component;
-    Throwable error;
-    String message;
+    /**
+     * The component used for showing dialog windows.
+     */
+    private final Component component;
 
     /**
-     * Constructor.
+     * The thrown error.
+     */
+    private Throwable error;
+
+    /**
+     * A logger for reporting error messages.
+     */
+    private final Logger logger;
+
+    /**
+     * The error message.
+     */
+    private String message;
+
+    /**
+     * Class constructor.
+     *
      * @param component The GUI component to which this object is assigned.
      * @param logger The logger to which messages will be written.
      */
-    public ErrorHandler(Component component, Logger logger) {
+    public ErrorHandler(final Component component, final Logger logger) {
         this.logger = logger;
         this.component = component;
     }
 
     /**
-     * Set the error that occurred. This should always be called first in a method chain.
-     * @param error The error which is a <code>Throwable</code>.
+     * Exit the application.
+     * <p>
+     * This is not a chain-able method for obvious reasons.
+     */
+    public void exit() {
+        System.err.println("Fatal error.  Application will exit.");
+        System.exit(1);
+    }
+
+    /**
+     * Log the error message to the <code>Logger</code>.
+     *
+     * @return this object
+     */
+    public ErrorHandler log() {
+        this.logger.log(Level.SEVERE, this.message, this.error);
+        return this;
+    }
+
+    /**
+     * Print the error message to System.err.
+     *
      * @return This object.
      */
-    public ErrorHandler setError(Throwable error) {
+    public ErrorHandler printMessage() {
+        System.err.println(this.message);
+        return this;
+    }
+
+    /**
+     * Print the full stack trace of the error to System.err.
+     *
+     * @return this object
+     */
+    public ErrorHandler printStackTrace() {
+        this.error.printStackTrace();
+        return this;
+    }
+
+    /**
+     * Immediately re-throw the error as a <code>RuntimeException</code>.
+     * <p>
+     * Additional methods cannot be chained to this as they would not be executed.
+     */
+    public void raiseException() {
+        throw new RuntimeException(this.message, this.error);
+    }
+
+    /**
+     * Set the error that occurred.
+     * <p>
+     * This should always be called first when method chaining.
+     *
+     * @param error the error which is any type of <code>Throwable</code>
+     * @return this object
+     */
+    public ErrorHandler setError(final Throwable error) {
         this.error = error;
         this.message = error.getMessage();
         return this;
     }
 
     /**
-     * Set the error message if it differs from the exception's message.
-     * @param message The erro message.
-     * @return This object.
+     * Set the error message, if it differs from the exception's message.
+     *
+     * @param message the error message
+     * @return this object
      */
-    public ErrorHandler setMessage(String message) {
+    public ErrorHandler setMessage(final String message) {
         this.message = message;
         return this;
     }
 
     /**
-     * Print the full stack trace of the error to System.err.
-     * @return This object.
-     */
-    public ErrorHandler printStackTrace() {
-        error.printStackTrace();
-        return this;
-    }
-
-    /**
-     * Print the error message to System.err.
-     * @return This object.
-     */
-    public ErrorHandler printMessage() {
-        System.err.println(message);
-        return this;
-    }
-
-    /**
-     * Log the error message to the <code>Logger</code>.
-     * @return This object.
-     */
-    public ErrorHandler log() {
-        logger.log(Level.SEVERE, message, error);
-        return this;
-    }
-
-    /**
      * Show an error dialog with the message.
-     * @return This object.
+     *
+     * @return this object
      */
     public ErrorHandler showErrorDialog() {
         final Runnable runnable = new Runnable() {
+            @Override
             public void run() {
-                JOptionPane.showMessageDialog(component, error.getMessage(), "Application Error", JOptionPane.ERROR_MESSAGE);
-            }
-        };
-        SwingUtilities.invokeLater(runnable);
-        return this;
-    }
-    
-    /**
-     * Show an error dialog with a custom message and title.
-     * @return This object.
-     */
-    public ErrorHandler showErrorDialog(final String message, final String title) {
-        final Runnable runnable = new Runnable() {
-            public void run() {
-                JOptionPane.showMessageDialog(component, message, title, JOptionPane.ERROR_MESSAGE);
+                JOptionPane.showMessageDialog(ErrorHandler.this.component, ErrorHandler.this.error.getMessage(),
+                        "Application Error", JOptionPane.ERROR_MESSAGE);
             }
         };
         SwingUtilities.invokeLater(runnable);
@@ -118,18 +150,20 @@
     }
 
     /**
-     * Rethrow the error as a <code>RuntimeException</code>. Additional methods cannot be chained to
-     * this as they would not be executed.
+     * Show an error dialog with a custom message and title.
+     *
+     * @param message the error message
+     * @param title the title of the dialog window
+     * @return this object
      */
-    public void raiseException() {
-        throw new RuntimeException(message, error);
-    }
-
-    /**
-     * Exit the application. This is not chainable for obvious reasons.
-     */
-    public void exit() {
-        System.err.println("Fatal error.  Application will exit.");
-        System.exit(1);
+    public ErrorHandler showErrorDialog(final String message, final String title) {
+        final Runnable runnable = new Runnable() {
+            @Override
+            public void run() {
+                JOptionPane.showMessageDialog(ErrorHandler.this.component, message, title, JOptionPane.ERROR_MESSAGE);
+            }
+        };
+        SwingUtilities.invokeLater(runnable);
+        return this;
     }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EtSystemUtil.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EtSystemUtil.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EtSystemUtil.java	Tue Apr 21 14:48:39 2015
@@ -6,28 +6,39 @@
 import org.hps.record.et.EtConnection;
 import org.jlab.coda.et.EtConstants;
 
+/**
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
+ */
 public final class EtSystemUtil {
 
-    private EtSystemUtil() {        
+    /**
+     * Create an {@link org.hps.record.et.EtConnection} from the settings in a
+     * {@link org.hps.monitoring.application.model.ConfigurationModel}.
+     *
+     * @param config the {@link org.hps.monitoring.application.model.ConfigurationModel} with the connection settings
+     * @return the new {@link org.hps.record.et.EtConnection}
+     */
+    public static EtConnection createEtConnection(final ConfigurationModel config) {
+        return EtConnection.createConnection(config.getEtName(), config.getHost(), config.getPort(),
+                config.getBlocking(), config.getQueueSize(), config.getPrescale(), config.getStationName(),
+                config.getStationPosition(), config.getWaitMode(), config.getWaitTime(), config.getChunkSize());
     }
-    
-    public static EtConnection createEtConnection(ConfigurationModel config) {
-        return EtConnection.createConnection(config.getEtName(), 
-                config.getHost(), 
-                config.getPort(), 
-                config.getBlocking(), 
-                config.getQueueSize(), 
-                config.getPrescale(), 
-                config.getStationName(), 
-                config.getStationPosition(), 
-                config.getWaitMode(), 
-                config.getWaitTime(), 
-                config.getChunkSize());
+
+    /**
+     * Create an event selection array (with size 6).
+     *
+     * @return the event selection array
+     */
+    public static int[] createSelectArray() {
+        final int select[] = new int[EtConstants.stationSelectInts];
+        Arrays.fill(select, -1);
+        return select;
     }
-    
-    public static int[] createSelectArray() {
-        int select[] = new int[EtConstants.stationSelectInts];
-        Arrays.fill(select, -1);
-        return select;   
-    }    
+
+    /**
+     * Do not allow class instantiation.
+     */
+    private EtSystemUtil() {
+        throw new UnsupportedOperationException("Do not instantiate this class.");
+    }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EvioFileFilter.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EvioFileFilter.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EvioFileFilter.java	Tue Apr 21 14:48:39 2015
@@ -5,24 +5,39 @@
 import javax.swing.filechooser.FileFilter;
 
 /**
- * This is a simple file filter that will accept files with ".evio" anywhere in their name. 
+ * This is a file filter that will accept files with ".evio" anywhere in their name.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 public final class EvioFileFilter extends FileFilter {
 
-    public EvioFileFilter() {            
+    /**
+     * Class constructor.
+     */
+    public EvioFileFilter() {
     }
-    
+
+    /**
+     * Return <code>true</code> if path should be accepted.
+     *
+     * @return <code>true</code> to accept the path
+     */
     @Override
-    public boolean accept(File pathname) {
-        if (pathname.getName().contains(".evio") || pathname.isDirectory()) {
+    public boolean accept(final File path) {
+        if (path.getName().contains(".evio") || path.isDirectory()) {
             return true;
         } else {
             return false;
         }
     }
-    
+
+    /**
+     * Get the description of the file filter.
+     *
+     * @return the description of the file filter
+     */
     @Override
     public String getDescription() {
         return "EVIO files";
-    }        
+    }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/ResourceUtil.java	Tue Apr 21 14:48:39 2015
@@ -19,106 +19,120 @@
 import org.reflections.Reflections;
 
 /**
- * 
- * @author Jeremy McCormick <[log in to unmask]>
+ * This is a set of utility methods for getting jar resources at runtime.
  *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 public final class ResourceUtil {
 
-    private ResourceUtil() {        
-    }
-    
-    /**
-     * Get the files with extension 'lcsim' from all loaded jar files.
-     * @param packageName The package name for filtering the resources.
-     * @return A list of embedded steering file resources.
-     */
-    public static String[] findSteeringResources(String packageName) {
-        List<String> resources = new ArrayList<String>();
-        URL url = ResourceUtil.class.getResource("ResourceUtil.class");
-        String scheme = url.getProtocol();
-        if (!"jar".equals(scheme)) {
-            throw new RuntimeException("Unsupported URL protocol: " + url.getProtocol());
-        }
-        try {
-            JarURLConnection con = (JarURLConnection) url.openConnection();
-            JarFile archive = con.getJarFile();
-            Enumeration<JarEntry> entries = archive.entries();
-            while (entries.hasMoreElements()) {
-                JarEntry entry = entries.nextElement();
-                if (entry.getName().endsWith(".lcsim") && entry.getName().contains(packageName)) {
-                    resources.add(entry.getName());
-                }
-            }
-            archive.close();
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-        java.util.Collections.sort(resources);
-        String[] arr = new String[resources.size()];
-        for (int i = 0; i < arr.length; i++) {
-            arr[i] = resources.get(i);
-        }
-        return arr;
-    }
-    
-    /**
-     * Find all classes that implement {@link org.hps.record.LCSimEventBuilder} and return
-     * a list of their canonical names.
-     * @return The list of classes implementing LCSimEventBuilder.
-     */
-    public static String[] findEventBuilderClassNames() {
-        Reflections reflections = new Reflections("org.hps");
-        Set<Class<? extends LCSimEventBuilder>> subTypes = reflections.getSubTypesOf(LCSimEventBuilder.class);
-        Set<String> classNames = new HashSet<String>();
-        for (Class<? extends LCSimEventBuilder> type : subTypes) {
-            classNames.add(type.getCanonicalName());
-        }
-        return classNames.toArray(new String[classNames.size()]);        
-    }
- 
     /**
      * Find a list of available detector names.
-     * Only those detectors that have names starting with "HPS" in their
-     * detector.properties files will be returned.
-     * @return The list of available detector names.
+     * <p>
+     * Only those detectors that have names starting with "HPS" in their <code>detector.properties</code> files will be
+     * returned.
+     *
+     * @return the list of available HPS detector names
      */
     public static String[] findDetectorNames() {
-        ClassLoader classLoader = ResourceUtil.class.getClassLoader();
-        List<String> detectorNames = new ArrayList<String>();
-        URL url = ResourceUtil.class.getResource("ResourceUtil.class");
-        String protocol = url.getProtocol();
+        final ClassLoader classLoader = ResourceUtil.class.getClassLoader();
+        final List<String> detectorNames = new ArrayList<String>();
+        final URL url = ResourceUtil.class.getResource("ResourceUtil.class");
+        final String protocol = url.getProtocol();
         if (!"jar".equals(protocol)) {
             throw new RuntimeException("Unsupported URL protocol: " + url.getProtocol());
         }
         try {
-            JarURLConnection con = (JarURLConnection) url.openConnection();
-            JarFile archive = con.getJarFile();
-            Enumeration<JarEntry> entries = archive.entries();
+            final JarURLConnection con = (JarURLConnection) url.openConnection();
+            final JarFile archive = con.getJarFile();
+            final Enumeration<JarEntry> entries = archive.entries();
             while (entries.hasMoreElements()) {
-                JarEntry entry = entries.nextElement();
+                final JarEntry entry = entries.nextElement();
                 if (entry.getName().endsWith("detector.properties")) {
-                    InputStream inputStream = classLoader.getResourceAsStream(entry.getName());
+                    final InputStream inputStream = classLoader.getResourceAsStream(entry.getName());
                     if (inputStream == null) {
                         throw new RuntimeException("Failed to load jar entry: " + entry.getName());
                     }
-                    Properties properties = new Properties();
+                    final Properties properties = new Properties();
                     properties.load(inputStream);
-                    String detectorName = properties.getProperty("name");
+                    final String detectorName = properties.getProperty("name");
                     if (detectorName.startsWith("HPS")) {
                         detectorNames.add(detectorName);
                     }
                 }
             }
             archive.close();
-        } catch (IOException e) {
+        } catch (final IOException e) {
             throw new RuntimeException(e);
         }
         Collections.sort(detectorNames);
         return detectorNames.toArray(new String[detectorNames.size()]);
-    }        
-    
+    }
+
+    /**
+     * Find all classes that implement {@link org.hps.record.LCSimEventBuilder} and return a list of their canonical
+     * names.
+     *
+     * @return the list of fully qualified class names that implement LCSimEventBuilder
+     */
+    public static String[] findEventBuilderClassNames() {
+        final Reflections reflections = new Reflections("org.hps");
+        final Set<Class<? extends LCSimEventBuilder>> subTypes = reflections.getSubTypesOf(LCSimEventBuilder.class);
+        final Set<String> classNames = new HashSet<String>();
+        for (final Class<? extends LCSimEventBuilder> type : subTypes) {
+            classNames.add(type.getCanonicalName());
+        }
+        return classNames.toArray(new String[classNames.size()]);
+    }
+
+    /**
+     * Get all of the files with the extension "lcsim" which are in a certain package.
+     *
+     * @param packageName the package name for filtering the list of resources
+     * @return a list of embedded steering file resources
+     */
+    public static String[] findSteeringResources(final String packageName) {
+        final List<String> resources = new ArrayList<String>();
+        final URL url = ResourceUtil.class.getResource("ResourceUtil.class");
+        final String scheme = url.getProtocol();
+        if (!"jar".equals(scheme)) {
+            throw new RuntimeException("Unsupported URL protocol: " + url.getProtocol());
+        }
+        try {
+            final JarURLConnection con = (JarURLConnection) url.openConnection();
+            final JarFile archive = con.getJarFile();
+            final Enumeration<JarEntry> entries = archive.entries();
+            while (entries.hasMoreElements()) {
+                final JarEntry entry = entries.nextElement();
+                if (entry.getName().endsWith(".lcsim") && entry.getName().contains(packageName)) {
+                    resources.add(entry.getName());
+                }
+            }
+            archive.close();
+        } catch (final IOException e) {
+            throw new RuntimeException(e);
+        }
+        java.util.Collections.sort(resources);
+        final String[] arr = new String[resources.size()];
+        for (int i = 0; i < arr.length; i++) {
+            arr[i] = resources.get(i);
+        }
+        return arr;
+    }
+
+    /**
+     * Get the list of available conditions tags from the conditions system.
+     *
+     * @return the list of available conditions tags
+     */
+    // FIXME: This method probably does not belong in this class.
     public static String[] getConditionsTags() {
         return DatabaseConditionsManager.getInstance().getTags().toArray(new String[] {});
     }
+
+    /**
+     * Do not allow class instantiation.
+     */
+    private ResourceUtil() {
+        throw new UnsupportedOperationException("Do not instantiate this class.");
+    }
 }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/SyncEventProcessor.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/SyncEventProcessor.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/SyncEventProcessor.java	Tue Apr 21 14:48:39 2015
@@ -15,20 +15,32 @@
 import org.lcsim.event.base.BaseLCSimEvent;
 
 /**
- * This is an ET event processor that will load DAQ configuration into the global manager 
- * from EVIO physics SYNC events, which have an event type in which bits 6 and 7 are set to 1.
- * 
- * @author Jeremy McCormick <[log in to unmask]>
- * 
+ * This is an ET event processor that will load DAQ configuration into the global manager from EVIO physics SYNC events,
+ * which have an event type in which bits 6 and 7 are set to 1.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  * @see org.hps.recon.ecal.daqconfig.ConfigurationManager
  * @see org.hps.recon.ecal.daqconfig.EvioDAQParser
  */
-public class SyncEventProcessor extends EtEventProcessor {
+// FIXME: This class is currently unused.
+public final class SyncEventProcessor extends EtEventProcessor {
 
+    /**
+     * The name of the trigger configuration collection.
+     */
     private static final String TRIGGER_CONFIG = "TriggerConfig";
-    TriggerConfigEvioReader configReader = new TriggerConfigEvioReader();
 
-    public void process(EtEvent event) {
+    /**
+     * The trigger configuration reader.
+     */
+    private final TriggerConfigEvioReader configReader = new TriggerConfigEvioReader();
+
+    /**
+     * Process an ET event and if there is a trigger configuration present, parse it and update the configuration in the
+     * global manager.
+     */
+    @Override
+    public void process(final EtEvent event) {
         EvioEvent evioEvent = null;
         try {
             evioEvent = new EvioReader(event.getDataBuffer()).parseNextEvent();
@@ -37,20 +49,20 @@
         }
         try {
             // Create a dummy LCIO event to satisfy the configuration reader's interface.
-            BaseLCSimEvent dummyLcsimEvent = 
-                    new BaseLCSimEvent(EvioEventUtilities.getRunNumber(evioEvent), evioEvent.getEventNumber(), "DUMMY", 0, false);
-            
+            final BaseLCSimEvent dummyLcsimEvent = new BaseLCSimEvent(EvioEventUtilities.getRunNumber(evioEvent),
+                    evioEvent.getEventNumber(), "DUMMY", 0, false);
+
             // Create the DAQ configuration object in the LCIO event.
-            configReader.getDAQConfig(evioEvent, dummyLcsimEvent);
-            
+            this.configReader.getDAQConfig(evioEvent, dummyLcsimEvent);
+
             // Update the global configuration if a configuration was created.
             if (dummyLcsimEvent.hasCollection(EvioDAQParser.class, TRIGGER_CONFIG)) {
-                List<EvioDAQParser> configList = dummyLcsimEvent.get(EvioDAQParser.class, TRIGGER_CONFIG);
+                final List<EvioDAQParser> configList = dummyLcsimEvent.get(EvioDAQParser.class, TRIGGER_CONFIG);
                 if (!configList.isEmpty()) {
                     ConfigurationManager.updateConfiguration(configList.get(0));
                 }
             }
-        } catch (Exception e) {
+        } catch (final Exception e) {
             System.err.println("Failed to load DAQ config from sync event ...");
             e.printStackTrace();
         }

Modified: java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/TableExporter.java
 =============================================================================
--- java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/TableExporter.java	(original)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/TableExporter.java	Tue Apr 21 14:48:39 2015
@@ -9,54 +9,60 @@
 
 /**
  * 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]>
+ * <p>
+ * Non-numeric fields such as strings are delimited by double quotes.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
  */
 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.
+     *
+     * @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();
-        
+    public static void export(final JTable table, final String path, final char fieldDelimiter) throws IOException {
+
+        final StringBuffer buffer = new StringBuffer();
+        final TableModel model = table.getModel();
+        final int rowCount = model.getRowCount();
+        final 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);
+                final 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));
+        final BufferedWriter out = new BufferedWriter(new FileWriter(path));
         out.write(buffer.toString());
         out.flush();
         out.close();
-    }    
+    }
+
+    /**
+     * Do not allow class instantiation.
+     */
+    private TableExporter() {
+        throw new UnsupportedOperationException("Do not instantiate this class.");
+    }
 }