LISTSERV mailing list manager LISTSERV 16.5

Help for HPS-SVN Archives


HPS-SVN Archives

HPS-SVN Archives


HPS-SVN@LISTSERV.SLAC.STANFORD.EDU


View:

Message:

[

First

|

Previous

|

Next

|

Last

]

By Topic:

[

First

|

Previous

|

Next

|

Last

]

By Author:

[

First

|

Previous

|

Next

|

Last

]

Font:

Proportional Font

LISTSERV Archives

LISTSERV Archives

HPS-SVN Home

HPS-SVN Home

HPS-SVN  April 2015

HPS-SVN April 2015

Subject:

r2772 - in /java/branches/monitoring-app-dev: ./ src/main/java/org/hps/monitoring/application/ src/main/java/org/hps/monitoring/application/model/ src/main/java/org/hps/monitoring/application/util/

From:

[log in to unmask]

Reply-To:

Notification of commits to the hps svn repository <[log in to unmask]>

Date:

Tue, 21 Apr 2015 21:48:53 -0000

Content-Type:

text/plain

Parts/Attachments:

Parts/Attachments

text/plain (15176 lines)

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.");
+    }
 }

Top of Message | Previous Page | Permalink

Advanced Options


Options

Log In

Log In

Get Password

Get Password


Search Archives

Search Archives


Subscribe or Unsubscribe

Subscribe or Unsubscribe


Archives

November 2017
August 2017
July 2017
January 2017
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
December 2013
November 2013

ATOM RSS1 RSS2



LISTSERV.SLAC.STANFORD.EDU

Secured by F-Secure Anti-Virus CataList Email List Search Powered by the LISTSERV Email List Manager

Privacy Notice, Security Notice and Terms of Use