Print

Print


Commit in java/trunk/monitoring-app/src/main/java/org/hps/monitoring on MAIN
MonitoringApplicationMain.java+24-15757 -> 758
gui/ConnectionPanel.java+6-1757 -> 758
   /ConnectionStatusPanel.java+1-1757 -> 758
   /JobPanel.java+14-14757 -> 758
   /MonitoringApplication.java+407-327757 -> 758
   /PlotFrame.java+30added 758
   /RunPanel.java+1-1757 -> 758
   /ScreenUtil.java+64added 758
   /SettingsDialog.java-1757 -> 758
record/EventProcessingChain.java+20-20757 -> 758
      /EventProcessingThread.java+3-1757 -> 758
      /EvioProcessingStep.java+1-1757 -> 758
record/composite/CompositeRecordLoop.java+14757 -> 758
                /CompositeRecordLoopAdapter.java+11-8757 -> 758
record/etevent/EtConnection.java+3-3757 -> 758
              /EtEventAdapter.java+12757 -> 758
              /EtEventLoop.java+14-2757 -> 758
              /EtEventSource.java+2-2757 -> 758
record/evio/EvioAdapter.java+14-2757 -> 758
           /EvioEventLoop.java+14757 -> 758
           /EvioFileProducer.java-1757 -> 758
subsys/SystemStatisticsImpl.java+7-8757 -> 758
      /SystemStatus.java+19-3757 -> 758
      /SystemStatusImpl.java+13-1757 -> 758
+694-412
2 added + 22 modified, total 24 files
Check in all changes from work on monitoring app.  Plots are now in a seperate frame.  Disconnecting from the ET system does not hang now and properly interrupts the getEvents call if necessary.  Unified error handling in MonitoringApplication class.  Many other things as well.

java/trunk/monitoring-app/src/main/java/org/hps/monitoring
MonitoringApplicationMain.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/MonitoringApplicationMain.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/MonitoringApplicationMain.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -2,6 +2,8 @@
 
 import java.io.File;
 
+import javax.swing.SwingUtilities;
+
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.CommandLineParser;
 import org.apache.commons.cli.HelpFormatter;
@@ -11,6 +13,10 @@
 import org.apache.commons.cli.PosixParser;
 import org.hps.monitoring.gui.MonitoringApplication;
 
+/**
+ * Front-end for running the monitoring app via a {@link #main(String[])} method.
+ * @author Jeremy McCormick <[log in to unmask]>
+ */
 public class MonitoringApplicationMain {
 
     /**
@@ -27,7 +33,7 @@
         CommandLineParser parser = new PosixParser();
 
         // Parse command line arguments.
-        CommandLine cl = null;
+        final CommandLine cl;
         try {
             cl = parser.parse(options, args);
         } catch (ParseException e) {
@@ -36,26 +42,29 @@
 
         // Print help and exit.
         if (cl.hasOption("h")) {
-            System.out.println("MonitoringApplication [options]");
             HelpFormatter help = new HelpFormatter();
             help.printHelp(" ", options);
             System.exit(1);
         }
 
-        // Create the application class.
-        MonitoringApplication app = new MonitoringApplication();
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
+        
+                // Create the application class.
+                MonitoringApplication app = new MonitoringApplication();
 
-        // Load the connection settings.
-        if (cl.hasOption("c")) {
-            app.loadConnectionSettings(new File(cl.getOptionValue("c")));
-        }
+                // Load the connection settings.
+                if (cl.hasOption("c")) {
+                    app.loadConnectionSettings(new File(cl.getOptionValue("c")));
+                }
 
-        // Load the job settings.
-        if (cl.hasOption("j")) {
-            app.loadJobSettings(new File(cl.getOptionValue("j")));
-        }
+                // Load the job settings.
+                if (cl.hasOption("j")) {
+                    app.loadJobSettings(new File(cl.getOptionValue("j")));
+                }
         
-        app.setVisible(true);
-    }
-    
+                app.setVisible(true);
+            }
+        });
+    }    
 }

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui
ConnectionPanel.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/ConnectionPanel.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/ConnectionPanel.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -49,7 +49,6 @@
      */
     ConnectionPanel() {
 
-        //super(new Insets(1, 1, 1, 1), true);
         super(new Insets(5, 5, 5, 5), true);
 
         setLayout(new GridBagLayout());
@@ -79,6 +78,7 @@
      * @return The connection parameters.
      */
     void cache() {
+        //System.out.println("cache ...");
         connectionParameters = new EtConnectionParameters();
         connectionParameters.setBufferName(etNameField.getText());
         connectionParameters.setHost(hostField.getText());
@@ -93,6 +93,7 @@
         connectionParameters.setWaitMode(getWaitMode());
         connectionParameters.setWaitTime(Integer.parseInt(waitTimeField.getText()));
         connectionParameters.setPreScale(Integer.parseInt(prescaleField.getText()));
+        //System.out.println("cache done");
     }
     
     void revert() {
@@ -251,6 +252,7 @@
      * @param file The properties file.
      */
     void loadPropertiesFile(File file) {
+        //System.out.println("loadPropertiesFile ...");
         Properties prop = new Properties();
         try {
             prop.load(new FileInputStream(file));
@@ -268,10 +270,13 @@
             waitTimeField.setText(prop.getProperty("waitTime"));
             prescaleField.setText(prop.getProperty("prescale"));
         } catch (FileNotFoundException e) {
+            e.printStackTrace();
             showErrorDialog(e.getLocalizedMessage());
         } catch (IOException e) {
+            e.printStackTrace();
             showErrorDialog(e.getLocalizedMessage());
         }
         cache();
+        //System.out.println("done with loadPropertiesFile");
     }
 }
\ No newline at end of file

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui
ConnectionStatusPanel.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/ConnectionStatusPanel.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/ConnectionStatusPanel.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -104,7 +104,7 @@
         add(new JSeparator(SwingConstants.HORIZONTAL), c);
         
         // Set default status.
-        setStatus(ConnectionStatus.DISCONNECTED);
+        //setStatus(ConnectionStatus.DISCONNECTED);
     }
 
     /**

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui
JobPanel.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/JobPanel.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/JobPanel.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -30,7 +30,7 @@
 class JobPanel extends FieldsPanel {
 
     private JTextField detectorNameField;
-    private JCheckBox disconnectOnErrorCheckBox;
+    //private JCheckBox disconnectOnErrorCheckBox;
     private JTextField eventBuilderField;
     private JComboBox<?> steeringTypeComboBox;
     private JTextField steeringFileField;
@@ -75,7 +75,7 @@
         setLayout(new GridBagLayout());
 
         pauseModeCheckBox = addCheckBox("Pause mode", false, true);
-        disconnectOnErrorCheckBox = addCheckBox("Disconnect on error", false, true);
+        //disconnectOnErrorCheckBox = addCheckBox("Disconnect on error", false, true);
         logLevelComboBox = addComboBox("Log Level", this.logLevels);
         logLevelComboBox.setActionCommand(MonitoringCommands.SET_LOG_LEVEL);
         steeringTypeComboBox = addComboBox("Steering Type", steeringTypes);  
@@ -330,9 +330,9 @@
      * Get the disconnect on error setting from the check box.
      * @return The disconnect on error setting.
      */
-    boolean disconnectOnError() {
-        return disconnectOnErrorCheckBox.isSelected();
-    }
+    //boolean disconnectOnError() {
+    //    return disconnectOnErrorCheckBox.isSelected();
+    //}
         
     /**
      * Get the log to file setting.
@@ -370,13 +370,13 @@
      * Set whether to disconnect if errors occur.
      * @param b The disconnect on error setting.
      */
-    private void setDisconnectOnError(final boolean b) {
-        SwingUtilities.invokeLater(new Runnable() {
-            public void run() {
-                disconnectOnErrorCheckBox.setSelected(b);
-            }
-        });        
-    }
+    //private void setDisconnectOnError(final boolean b) {
+    //    SwingUtilities.invokeLater(new Runnable() {
+    //        public void run() {
+    //            disconnectOnErrorCheckBox.setSelected(b);
+    //        }
+    //    });        
+    //}
         
     /**
      * Set the steering type.
@@ -492,7 +492,7 @@
     void cache() {
         settings = new JobSettings();
         settings.pauseMode = pauseMode();
-        settings.disconnectOnError = disconnectOnError();
+        //settings.disconnectOnError = disconnectOnError();
         settings.logLevel = getLogLevel();
         settings.steeringType = getSteeringType();
         settings.steeringFile = getSteeringFile();
@@ -519,7 +519,7 @@
     void setJobSettings(JobSettings settings) {
         this.settings = settings;
         enablePauseMode(settings.pauseMode);
-        setDisconnectOnError(settings.disconnectOnError);
+        //setDisconnectOnError(settings.disconnectOnError);
         setLogLevel(settings.logLevel);
         setSteeringType(settings.steeringType);
         setSteeringFile(settings.steeringFile);

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui
MonitoringApplication.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/MonitoringApplication.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/MonitoringApplication.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -25,8 +25,6 @@
 import static org.hps.monitoring.gui.MonitoringCommands.SET_STEERING_RESOURCE;
 import static org.hps.monitoring.gui.MonitoringCommands.SHOW_SETTINGS;
 
-import java.awt.AWTException;
-import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.GraphicsDevice;
 import java.awt.GraphicsEnvironment;
@@ -39,6 +37,8 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
 import java.awt.image.BufferedImage;
 import java.io.BufferedWriter;
 import java.io.File;
@@ -58,6 +58,7 @@
 import java.util.logging.Logger;
 
 import javax.imageio.ImageIO;
+import javax.swing.JDialog;
 import javax.swing.JFileChooser;
 import javax.swing.JFrame;
 import javax.swing.JMenu;
@@ -66,7 +67,6 @@
 import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
-import javax.swing.JTabbedPane;
 import javax.swing.JTable;
 import javax.swing.SwingUtilities;
 import javax.swing.table.DefaultTableModel;
@@ -84,25 +84,27 @@
 import org.lcsim.util.aida.AIDA;
 
 /**
- * Monitoring application for HPS Test Run, which can run LCSim steering files on data converted
- * from the ET ring. This class is accessible to users by calling its main() method.
+ * Monitoring application for HPS, which can run LCSim steering files on data converted
+ * from the ET server.
  * @author Jeremy McCormick <[log in to unmask]>
  * @version $Id: MonitoringApplication.java,v 1.61 2013/12/10 07:36:40 jeremy Exp $
  */
+// TODO: Review GUI size settings.
+// FIXME: Review use of the watchdog thread for automatic disconnect.  It may be overcomplicated.
+// FIXME: Add back configuration to continue if event processing errors occur.  Certain other types of errors
+// like the ET system being unavailable should still cause an automatic disconnect.
 public class MonitoringApplication extends JFrame implements ActionListener {
 
     // Top-level Swing components.
     private JPanel mainPanel;
-    private JPanel leftPanel;
-    private JPanel rightPanel;
     private EventButtonsPanel buttonsPanel;
     private ConnectionStatusPanel connectionStatusPanel;
     private RunPanel runPanel;
-    private JTabbedPane plotPane;
     private JMenuBar menuBar;
     private SettingsDialog settingsDialog;
+    private PlotFrame plotFrame;
 
-    // References to menu items that will be enabled/disabled depending on application state.
+    // References to menu items that will be toggled depending on application state.
     private JMenuItem connectItem;
     private JMenuItem disconnectItem;
     private JMenuItem resetConnectionItem;
@@ -127,8 +129,8 @@
     // Event processing objects.
     private JobControlManager jobManager;
     private LCSimEventBuilder eventBuilder;
-    private EventProcessingThread eventProcessingThread;    
-    private Thread sessionThread;
+    private EventProcessingThread eventProcessingThread;
+    private Thread sessionWatchdogThread;
 
     // Logging objects.
     private static Logger logger;
@@ -136,7 +138,7 @@
     private DefaultTableModel logTableModel;
     static final String[] logTableColumns = { "Message", "Date", "Level" };
     private JTable logTable;
-    private Level defaultLogMessageLevel = Level.INFO;
+    private static Level DEFAULT_LOG_LEVEL = Level.INFO;
 
     // Some default GUI size parameters.
     private final int logTableWidth = 700;
@@ -147,50 +149,90 @@
 
     // Format of date field for log.
     private final SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM-dd-yyyy HH:mm:ss.SSS");
-    private static final String LCSIM_FAIL_MESSAGE = "Failed to setup LCSim.";
 
     // Screen resolution.
     static GraphicsDevice graphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
     private static final int screenWidth = graphicsDevice.getDisplayMode().getWidth();
     private static final int screenHeight = graphicsDevice.getDisplayMode().getHeight();
-    
+
     // GUI size settings.
-    private static final int leftPanelWidth = (int) (screenWidth * 0.33);
-    private static final int rightPanelWidth = (int) (screenWidth * 0.40);
+    private static final int leftPanelWidth = (int) (screenWidth * 0.5);
     private static final int connectionStatusPanelHeight = 50;
     private static final int connectionStatusPanelWidth = 400;
 
     EventProcessingChain eventProcessing;
 
     /**
-     * Constructor for the monitoring application. 
+     * Constructor for the monitoring application.
      */
     public MonitoringApplication() {
 
         // Create and configure the logger.
         setupLogger();
-        
+
         // Setup the application menus.
-        createMenu();
+        createApplicationMenu();
 
-        // Create the GUI panels.
-        createPanels();
+        // Create the main GUI panel.
+        createMainPanel();
 
         // Create the log table GUI component.
         createLogTable();
 
+        // Configuration of window for showing plots.
+        configPlotFrame();
+
         // Setup AIDA.
         setupAida();
 
-        // Configure the application's frame.
-        configFrame();
+        // Configure the application's primary JFrame.
+        configMainFrame();
+
+        // Configuration of settings window.
+        configSettingsWindow();
+
+        // Log that the application started successfully.
+        log("Application initialized successfully.");        
+    }
+    
+    // TODO: Add similar method that takes an Exception object instead of message.
+    private void handleError(String message, boolean showDialog, boolean throwException) {
         
-        // Configuration of settings window.
+        // Print to the screen or log file.
+        System.err.println(message);
+        
+        // Add the error message to the application's log table. 
+        log(Level.SEVERE, message);
+        
+        // Show a dialog (optional).
+        if (showDialog)
+            showMessageDialog(message);
+        
+        // Raise an exception (optional).
+        if (throwException) {
+            throw new RuntimeException(message);
+        }
+    }
+        
+    private void configSettingsWindow() {
         settingsDialog = new SettingsDialog();
         getJobPanel().addActionListener(this);
+    }
+
+    private void configPlotFrame() {
+        plotFrame = new PlotFrame();        
+        plotFrame.setSize(screenWidth - 650, screenHeight);
+        plotFrame.setLocation(
+                (int)(ScreenUtil.getGraphicsDevice(0).getDefaultConfiguration().getBounds().getX() + 650), 
+                plotFrame.getY());
+    }
+    
+    public void setVisible(boolean visible) {
+        super.setVisible(true);
         
-        // Log that the application started successfully.
-        log("Application initialized successfully.");
+        // HACK: I guess this initial setting of status must be here for some mysterious 
+        // reason that I don't understand.  Otherwise, the main JFrame may fail to display at all!
+        this.connectionStatusPanel.setStatus(ConnectionStatus.DISCONNECTED);
     }
 
     /**
@@ -199,31 +241,22 @@
     private void setupAida() {
         MonitoringAnalysisFactory.register();
         MonitoringAnalysisFactory.configure();
-        MonitoringPlotFactory.setRootPane(plotPane);
+        MonitoringPlotFactory.setRootPane(this.plotFrame.getPlotPane());
     }
 
     /**
-     * Creates all the JPanels for the monitoring GUI.
+     * Create the left panel.
      */
-    private void createPanels() {
+    private void createMainPanel() {
+        
+        // Main panel setup.
         mainPanel = new JPanel();
+        mainPanel.setMinimumSize(new Dimension(leftPanelWidth, screenHeight - 30));
         mainPanel.setLayout(new GridBagLayout());
-        createLeftPanel();
-        createRightPanel();
-    }
 
-    /**
-     * Create the left panel.
-     */
-    private void createLeftPanel() {
+        // This is used for ref to layout for each sub-component.
+        GridBagConstraints c;
 
-        // Lefthand panel containing the three application tabs.
-        leftPanel = new JPanel();
-        leftPanel.setMinimumSize(new Dimension(leftPanelWidth, screenHeight - 30));
-        leftPanel.setLayout(new GridBagLayout());
-
-        GridBagConstraints c;
-        
         // Event processing buttons.
         c = new GridBagConstraints();
         c.gridx = 0;
@@ -232,7 +265,7 @@
         c.insets = new Insets(10, 0, 0, 10);
         buttonsPanel = new EventButtonsPanel();
         buttonsPanel.addActionListener(this);
-        leftPanel.add(buttonsPanel, c);
+        mainPanel.add(buttonsPanel, c);
 
         // Connection status panel.
         c = new GridBagConstraints();
@@ -243,7 +276,7 @@
         c.insets = new Insets(10, 0, 5, 0);
         connectionStatusPanel = new ConnectionStatusPanel();
         connectionStatusPanel.setMinimumSize(new Dimension(connectionStatusPanelWidth, connectionStatusPanelHeight));
-        leftPanel.add(connectionStatusPanel, c);
+        mainPanel.add(connectionStatusPanel, c);
 
         // Run status panel.
         runPanel = new RunPanel();
@@ -252,59 +285,22 @@
         c.fill = GridBagConstraints.BOTH;
         c.gridx = 0;
         c.gridy = 2;
-        leftPanel.add(runPanel, c);
-                        
-        // Layout attributes for the entire left panel.
-        c = new GridBagConstraints();
-        c.gridx = 0;
-        c.gridy = 0;
-        c.weightx = 1.0;
-        c.weighty = 1.0;
-        c.fill = GridBagConstraints.BOTH;
-        c.anchor = GridBagConstraints.WEST;
-        c.insets = new Insets(0, 5, 0, 0);
-        mainPanel.add(leftPanel, c);
+        mainPanel.add(runPanel, c);
     }
-
+    
     /**
-     * Create the right panel.
-     */
-    private void createRightPanel() {
-
-        // Create right-hand panel.
-        rightPanel = new JPanel();
-        rightPanel.setPreferredSize(new Dimension(rightPanelWidth, screenHeight - 30));
-        rightPanel.setMinimumSize(new Dimension(rightPanelWidth, screenHeight - 30));
-        rightPanel.setLayout(new BorderLayout());
-
-        // Create plot pane with empty tabs.
-        plotPane = new JTabbedPane();
-        rightPanel.add(plotPane, BorderLayout.CENTER);
-
-        // Set layout of right panel.
-        GridBagConstraints c = new GridBagConstraints();
-        c.gridx = 1;
-        c.gridy = 0;
-        c.fill = GridBagConstraints.BOTH;
-        c.anchor = GridBagConstraints.CENTER;
-        c.weightx = 1.0;
-        c.weighty = 1.0;
-        mainPanel.add(rightPanel, c);
-    }
-
-    /**
      * Create the menu items.
      */
-    private void createMenu() {
+    private void createApplicationMenu() {
 
         menuBar = new JMenuBar();
 
         JMenu applicationMenu = new JMenu("Application");
         applicationMenu.setMnemonic(KeyEvent.VK_A);
-        menuBar.add(applicationMenu);        
+        menuBar.add(applicationMenu);
         addMenuItem("Settings...", KeyEvent.VK_S, SHOW_SETTINGS, true, "Monitoring Application settings", applicationMenu);
         addMenuItem("Exit", KeyEvent.VK_X, EXIT, true, "Exit from the application.", applicationMenu);
-        
+
         JMenu connectionMenu = new JMenu("Connection");
         connectionMenu.setMnemonic(KeyEvent.VK_C);
         menuBar.add(connectionMenu);
@@ -314,7 +310,7 @@
         resetConnectionItem = addMenuItem("Reset Connection Settings", KeyEvent.VK_R, RESET_CONNECTION_SETTINGS, true, "Reset connection settings to defaults.", connectionMenu);
         connectionLoadItem = addMenuItem("Load Connection...", KeyEvent.VK_L, LOAD_CONNECTION, true, "Load connection settings from a saved properties file.", connectionMenu);
         addMenuItem("Save Connection...", KeyEvent.VK_S, SAVE_CONNECTION, true, "Save connection settings to a properties file.", connectionMenu);
-        
+
         JMenu jobMenu = new JMenu("Job");
         jobMenu.setMnemonic(KeyEvent.VK_J);
         menuBar.add(jobMenu);
@@ -322,7 +318,7 @@
         addMenuItem("Save Job Settings...", KeyEvent.VK_J, SAVE_JOB_SETTINGS, true, "Save Job Settings configuration to a properties file.", jobMenu);
 
         // FIXME: Rest of these should be converted to use the addMenuItem() helper method ...
-        
+
         loadJobSettingsItem = new JMenuItem("Load Job Settings...");
         loadJobSettingsItem.setMnemonic(KeyEvent.VK_L);
         loadJobSettingsItem.setActionCommand(LOAD_JOB_SETTINGS);
@@ -392,7 +388,7 @@
         saveLogItem.addActionListener(this);
         saveLogItem.setToolTipText("Save the log records to a tab delimited text file.");
         logMenu.add(saveLogItem);
-        
+
         addMenuItem("Clear log", KeyEvent.VK_C, CLEAR_LOG_TABLE, true, "Clear the log table of all messages.", logMenu);
     }
 
@@ -426,8 +422,8 @@
          * Puts log messages into the application's log table GUI component.
          */
         public void publish(LogRecord record) {
-            Object[] row = new Object[] { /*record.getLoggerName(),*/ // source
-                    record.getMessage(), // message
+            Object[] row = new Object[] { /* record.getLoggerName(), */// source
+            record.getMessage(), // message
                     dateFormat.format(new Date(record.getMillis())), // date
                     record.getLevel() }; // level
             logTableModel.insertRow(logTable.getRowCount(), row);
@@ -460,7 +456,7 @@
         JScrollPane logPane = new JScrollPane(logTable);
         logPane.setPreferredSize(new Dimension(logTableWidth, logTableHeight));
         logPane.setMinimumSize(new Dimension(logTableWidth, logTableHeight));
-        leftPanel.add(logPane, c);
+        mainPanel.add(logPane, c);
     }
 
     /**
@@ -505,9 +501,19 @@
     public void actionPerformed(ActionEvent e) {
         String cmd = e.getActionCommand();
         if (CONNECT.equals(cmd)) {
-            startSession();
+            // Run the method on a seperate thread.
+            new Thread() {
+                public void run() {
+                    startSession();
+                }                
+            }.start();
         } else if (DISCONNECT.equals(cmd)) {
-            stopSession();
+            // Run the method on a seperate thread.
+            new Thread() {
+                public void run() {
+                    stopSession();
+                }
+            }.start();            
         } else if (SAVE_PLOTS.equals(cmd)) {
             savePlots();
         } else if (LOG_TO_FILE.equals(cmd)) {
@@ -554,7 +560,7 @@
             showSettingsWindow();
         }
     }
-    
+
     /**
      * Show the settings window.
      */
@@ -567,7 +573,7 @@
      * are changed to use a resource type.
      */
     private void steeringResourceSelected() {
-        getJobPanel().setSteeringType(getJobPanel().RESOURCE);
+        getJobPanel().setSteeringType(JobPanel.RESOURCE);
     }
 
     /**
@@ -577,17 +583,15 @@
         JFileChooser fc = new JFileChooser();
         fc.setDialogTitle("Save Job Settings");
         fc.setCurrentDirectory(new File("."));
-        int r = fc.showSaveDialog(leftPanel);
+        int r = fc.showSaveDialog(mainPanel);
         if (r == JFileChooser.APPROVE_OPTION) {
             File f = fc.getSelectedFile();
             JobSettings settings = getJobPanel().getJobSettings();
             try {
                 settings.save(f);
-                log(Level.INFO, "Saved Job Settings to properties file <" + f.getPath() + ">.");
+                log(Level.INFO, "Saved Job Settings to properties file: " + f.getPath());
             } catch (IOException e) {
-                e.printStackTrace();
-                log(Level.SEVERE, "Error saving Job Settings to properties file <" + f.getPath() + ">.");
-                showDialog("Error saving Job Settings to properties file.");
+                handleError("Error saving job settings to file: " + f.getPath(), true, false);
             }
         }
     }
@@ -599,20 +603,21 @@
         JFileChooser fc = new JFileChooser();
         fc.setDialogTitle("Load Job Settings");
         fc.setCurrentDirectory(new File("."));
-        int r = fc.showOpenDialog(leftPanel);
+        int r = fc.showOpenDialog(mainPanel);
         if (r == JFileChooser.APPROVE_OPTION) {
             File f = fc.getSelectedFile();
             try {
                 getJobPanel().setJobSettings(new JobSettings(f));
-                log(Level.INFO, "Loaded Job Settings from properties file <" + f.getPath() + ">");
+                log(Level.INFO, "Loaded Job Settings from properties file: " + f.getPath());
             } catch (IOException e) {
-                e.printStackTrace();
-                log(Level.SEVERE, "Error loading Job Settings from properties file <" + f.getPath() + ">");
-                showDialog("Error loading Job Settings from properties file.");
+                handleError("Error loading job settings from file: " + f.getPath(), true, false);
             }
         }
     }
-    
+
+    /**
+     * Save the connection settings to a properties file using a file chooser.
+     */
     void saveConnection() {
         JFileChooser fc = new JFileChooser();
         fc.setCurrentDirectory(new File("."));
@@ -620,7 +625,7 @@
         if (r == JFileChooser.APPROVE_OPTION) {
             File file = fc.getSelectedFile();
             getConnectionPanel().writePropertiesFile(file);
-            log(Level.INFO, "Saved connection properties to <" + file.getPath() + ">");
+            log(Level.INFO, "Saved connection properties to file: " + file.getPath());
         }
     }
 
@@ -632,14 +637,14 @@
         // Redirect System.out and err back to the terminal.
         logToTerminal();
     }
-   
+
     /**
      * Set a new log level for the application and also forward to the event processor.
      */
     private void setLogLevel() {
         Level newLevel = getJobPanel().getLogLevel();
         logger.setLevel(newLevel);
-        log(Level.INFO, "Log Level was changed to <" + getJobPanel().getLogLevel().toString() + ">");
+        log(Level.INFO, "Log Level was changed to " + getJobPanel().getLogLevel().toString());
     }
 
     /**
@@ -649,41 +654,58 @@
     private void setConnectionStatus(int status) {
         connectionStatus = status;
         connectionStatusPanel.setStatus(status);
-        log(Level.FINE, "Connection status changed to <" + ConnectionStatus.toString(status) + ">");
+        log(Level.FINE, "Connection status changed to " + ConnectionStatus.toString(status));
         logHandler.flush();
     }
 
     /**
-     * Get the current connection status.
-     * @return The connection status.
-     */
-    private int getConnectionStatus() {
-        return connectionStatus;
-    }
-
-    /**
      * Pop-up a modal dialog.
-     * @param m The message to display in the dialog box.
+     * @param message The message to display in the dialog box.
      */
-    private void showDialog(String m) {
-        JOptionPane.showMessageDialog(leftPanel, m);
+    private void showMessageDialog(String message) {
+        JOptionPane.showMessageDialog(mainPanel, message);
     }
 
     /**
      * Setup the frame to run the application.
      */
-    private void configFrame() {
-        
+    private void configMainFrame() {
         mainPanel.setOpaque(true);
         setTitle(getApplicationTitle());
         setContentPane(mainPanel);
         setJMenuBar(menuBar);
         setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
-        setPreferredSize(new Dimension(screenWidth, screenHeight));
-        setResizable(true);
-        pack();    
+        setPreferredSize(new Dimension(650, 450));
+        setMinimumSize(new Dimension(650, 450));        
+        setResizable(true);        
+        setLocation(ScreenUtil.getGraphicsDevice(0).getDefaultConfiguration().getBounds().x, getY());
+        pack();
+        
+        // DEBUG: show size of frame when resized
+        /*
+        addComponentListener(new ComponentListener() {
+            public void componentResized(ComponentEvent event) {
+                Component component = (Component) event.getSource();
+                System.out.println("resized main frame to: " + component.getSize().getWidth() 
+                        + " x " + component.getSize().getHeight());
+            }
+
+            @Override
+            public void componentMoved(ComponentEvent e) {
+                
+            }
+
+            @Override
+            public void componentShown(ComponentEvent e) {
+            }
+
+            @Override
+            public void componentHidden(ComponentEvent e) {
+            }
+        });
+        */        
     }
-
+        
     /**
      * Save plots to a selected output file.
      */
@@ -694,9 +716,9 @@
             File fileName = fc.getSelectedFile();
             try {
                 AIDA.defaultInstance().saveAs(fileName);
-                logger.log(Level.INFO, "Plots saved to <" + fileName + ">");
+                logger.log(Level.INFO, "Plots saved to file: " + fileName);
             } catch (IOException e) {
-                e.printStackTrace();
+                this.handleError("Failed to save plots to file: " + fileName, true, false);
             }
         }
     }
@@ -712,12 +734,10 @@
             try {
                 (new JobControlManager()).setup(fileName);
                 getJobPanel().setSteeringFile(fileName.getPath());
-                getJobPanel().setSteeringType(getJobPanel().FILE);
-                log("Steering file set to <" + fileName.getPath() + ">");
+                getJobPanel().setSteeringType(JobPanel.FILE);
+                log("Steering file set to file: " + fileName.getPath());
             } catch (Exception e) {
-                e.printStackTrace();
-                log(Level.SEVERE, "Failed to read steering file <" + fileName.getPath() + ">");
-                showDialog("Failed to read the LCSim XML file.");
+                handleError("Failed to read steering file: " + fileName.getPath(), true, false);
             }
         }
     }
@@ -766,7 +786,7 @@
         if (fcs == JFileChooser.APPROVE_OPTION) {
             final File logFile = fc.getSelectedFile();
             if (logFile.exists()) {
-                showDialog("Log file already exists.");
+                showMessageDialog("Log file already exists.");
             } else {
                 try {
                     if (!logFile.createNewFile()) {
@@ -776,6 +796,7 @@
                     redirectStdOutAndErrToFile(logFile);
 
                     SwingUtilities.invokeLater(new Runnable() {
+
                         public void run() {
                             getJobPanel().setLogToFile(true);
                             getJobPanel().setLogFile(logFile.getPath());
@@ -785,11 +806,9 @@
                         }
                     });
 
-                    log("Redirected System output to file <" + logFile.getPath() + ">");
+                    log("Redirected System output to file: " + logFile.getPath());
                 } catch (IOException e) {
-                    e.printStackTrace();
-                    log(Level.SEVERE, "Error redirecting System output to file <" + logFile.getPath() + ">");
-                    showDialog("Error redirecting System output to log file.");
+                    handleError("Error redirecting System output to file: ", true, false);
                 }
             }
         }
@@ -815,7 +834,6 @@
         System.setOut(sysOut);
         System.setErr(sysErr);
         SwingUtilities.invokeLater(new Runnable() {
-
             public void run() {
                 getJobPanel().setLogFile("");
                 getJobPanel().setLogToFile(false);
@@ -831,59 +849,66 @@
      * menu items.
      */
     private void setDisconnectedGuiState() {
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
 
-        // Enable or disable appropriate menu items.
-        connectItem.setEnabled(true);
-        disconnectItem.setEnabled(false);
-        resetConnectionItem.setEnabled(true);
-        connectionLoadItem.setEnabled(true);
-        savePlotsItem.setEnabled(false);
-        logItem.setEnabled(true);
-        terminalItem.setEnabled(true);
-        steeringItem.setEnabled(true);
+                // Enable or disable appropriate menu items.
+                connectItem.setEnabled(true);
+                disconnectItem.setEnabled(false);
+                resetConnectionItem.setEnabled(true);
+                connectionLoadItem.setEnabled(true);
+                savePlotsItem.setEnabled(false);
+                logItem.setEnabled(true);
+                terminalItem.setEnabled(true);
+                steeringItem.setEnabled(true);
 
-        // Re-enable the ConnectionPanel.   
-        getConnectionPanel().enableConnectionPanel(true);
+                // Re-enable the ConnectionPanel.
+                getConnectionPanel().enableConnectionPanel(true);
 
-        // Re-enable the getJobPanel().
-        getJobPanel().enableJobPanel(true);
+                // Re-enable the getJobPanel().
+                getJobPanel().enableJobPanel(true);
 
-        // Set relevant event panel buttons to disabled.
-        buttonsPanel.enablePauseButton(false);
-        buttonsPanel.enableNextEventsButton(false);
+                // Set relevant event panel buttons to disabled.
+                buttonsPanel.enablePauseButton(false);
+                buttonsPanel.enableNextEventsButton(false);
 
-        // Toggle connection button to proper setting.
-        buttonsPanel.toggleConnectButton();
+                // Toggle connection button to proper setting.
+                buttonsPanel.toggleConnectButton();
+            }
+        });
     }
 
     /**
-     * Set the GUI to connected state, which will enable/disable appropriate components and menu
-     * items.
+     * Set the GUI to connected state, which will enable/disable appropriate components and menu items.
      */
     private void setConnectedGuiState() {
+        SwingUtilities.invokeLater(new Runnable() {
+            public void run() {
 
-        // Disable connection panel.
-        getConnectionPanel().enableConnectionPanel(false);
+                // Disable connection panel.
+                getConnectionPanel().enableConnectionPanel(false);
 
-        // Disable getJobPanel().
-        getJobPanel().enableJobPanel(false);
+                // Disable getJobPanel().
+                getJobPanel().enableJobPanel(false);
 
-        // Enable or disable appropriate menu items.
-        connectItem.setEnabled(false);
-        disconnectItem.setEnabled(true);
-        resetConnectionItem.setEnabled(false);
-        connectionLoadItem.setEnabled(false);
-        savePlotsItem.setEnabled(true);
-        logItem.setEnabled(false);
-        terminalItem.setEnabled(false);
-        steeringItem.setEnabled(false);
+                // Enable or disable appropriate menu items.
+                connectItem.setEnabled(false);
+                disconnectItem.setEnabled(true);
+                resetConnectionItem.setEnabled(false);
+                connectionLoadItem.setEnabled(false);
+                savePlotsItem.setEnabled(true);
+                logItem.setEnabled(false);
+                terminalItem.setEnabled(false);
+                steeringItem.setEnabled(false);
 
-        // Enable relevant event panel buttons.
-        buttonsPanel.enablePauseButton(true);
-        buttonsPanel.setPauseModeState(getJobPanel().pauseMode());
+                // Enable relevant event panel buttons.
+                buttonsPanel.enablePauseButton(true);
+                buttonsPanel.setPauseModeState(getJobPanel().pauseMode());
 
-        // Toggle connection button to proper settings.
-        buttonsPanel.toggleConnectButton();
+                // Toggle connection button to proper settings.
+                buttonsPanel.toggleConnectButton();
+            }
+        });
     }
 
     /**
@@ -893,6 +918,9 @@
         if (connection != null) {
             cleanupEtConnection();
         }
+        if (plotFrame.isVisible())
+            plotFrame.setVisible(false);
+        this.setVisible(false);
         System.exit(0);
     }
 
@@ -911,7 +939,7 @@
                 fileName = fileName + "." + screenshotFormat;
             }
             takeScreenshot(fileName);
-            log("Screenshot saved to <" + fileName + ">");
+            log("Screenshot saved to file: " + fileName);
         }
     }
 
@@ -926,12 +954,8 @@
             Robot robot = new Robot();
             BufferedImage image = robot.createScreenCapture(screenRectangle);
             ImageIO.write(image, screenshotFormat, new File(fileName));
-        } catch (AWTException e) {
-            e.printStackTrace();
-            showDialog(e.getMessage());
-        } catch (IOException e) {
-            e.printStackTrace();
-            showDialog(e.getMessage());
+        } catch (Exception e) {
+            handleError(e.getMessage(), true, false);
         }
     }
 
@@ -953,14 +977,15 @@
     }
 
     /**
-     * Execute a monitoring session. This should be executed in a separate thread so as not to block the
-     * GUI or other threads during a monitoring session.
+     * Start a new monitoring session. This is executed in a separate thread from the EDT.
      */
-    synchronized private void startSession() {
+    private void startSession() {
 
         log(Level.INFO, "Starting a new monitoring session.");
-
         try {
+            
+            // Show modal window.
+            JDialog dialog = createModalDialog("Info", "Starting new session ...", true);
 
             // Reset the plot panel and global AIDA state.
             resetPlots();
@@ -968,29 +993,36 @@
             // Setup the LCSim JobControlManager and event builder.
             setupLCSim();
 
-            // Connect to the ET system, which will setup a valid EtConnection object.
+            // Connect to the ET system, which will create a valid EtConnection object.
             connect();
-            
+
             // Setup the EventProcessingChain object using the EtConnection.
             setupEventProcessingChain();
 
-            // Start the event processing thread.
-            eventProcessingThread.start();
-            
-            // Start thread which will trigger disconnect if event processing thread finishes.
-            sessionThread = new SessionThread();
-            sessionThread.start();
-                       
+            // Start thread which will trigger a disconnect if the event processing thread
+            // finishes.
+            startSessionWatchdogThread();
+
             log(Level.INFO, "Successfully started the monitoring session.");
-            
+
+            // Close modal window.
+            dialog.dispatchEvent(new WindowEvent(dialog, WindowEvent.WINDOW_CLOSING));
+
         } catch (Exception e) {
-            e.printStackTrace();
-            log(Level.SEVERE, e.getMessage());
+            handleError(e.getMessage(), false, false);
             disconnect(ConnectionStatus.ERROR);
-        }         
+        }
     }
 
     /**
+     * Start the session watchdog thread.
+     */
+    private void startSessionWatchdogThread() {        
+        sessionWatchdogThread = new SessionWatchdogThread();
+        sessionWatchdogThread.start();
+    }
+
+    /**
      * Connect to the ET system specified in the GUI's connection panel settings.
      */
     private void connect() throws IOException {
@@ -1004,12 +1036,12 @@
 
         // Create a connection to the ET server.
         try {
-            createEtConnection();          
+            createEtConnection();
             log("Successfully connected to ET system.");
         } catch (Exception e) {
             log(e.getMessage());
             throw new IOException(e);
-        }       
+        }
     }
 
     /**
@@ -1039,7 +1071,7 @@
     private ConnectionPanel getConnectionPanel() {
         return settingsDialog.getSettingsPanel().getConnectionPanel();
     }
-    
+
     private JobPanel getJobPanel() {
         return settingsDialog.getSettingsPanel().getJobPanel();
     }
@@ -1048,9 +1080,9 @@
      * Get whether errors in event processing will cause automatic disconnect.
      * @return True if disconnect on event processing error; false to continue.
      */
-    private boolean disconnectOnError() {
-        return getJobPanel().disconnectOnError();
-    }
+    //private boolean disconnectOnError() {
+    //    return getJobPanel().disconnectOnError();
+    //}
 
     private void disconnect() {
         disconnect(ConnectionStatus.DISCONNECTING);
@@ -1062,8 +1094,8 @@
      */
     private void disconnect(int status) {
 
-        log("Disconnecting from the ET system.");
-     
+        log(Level.FINE, "Disconnecting from the ET server.");
+
         // Cleanup the ET connection.
         cleanupEtConnection();
 
@@ -1072,12 +1104,12 @@
 
         // Finally, change application state to fully disconnected.
         setConnectionStatus(ConnectionStatus.DISCONNECTED);
-        
+
         // Set the application status from the caller if an error had occurred.
         if (status == ConnectionStatus.ERROR)
             setConnectionStatus(status);
 
-        log("Successfully disconnected from ET system.");
+        log(Level.INFO, "Disconnected from the ET server.");
     }
 
     /**
@@ -1101,25 +1133,24 @@
         // Get steering resource or file as a String parameter.
         String steering = getSteering();
         int steeringType = getJobPanel().getSteeringType();
-        log(Level.CONFIG, "LCSim steering <" + steering + "> of type <" + (steeringType == getJobPanel().RESOURCE ? "RESOURCE" : "FILE") + ">.");
+        log(Level.CONFIG, "Set LCSim steering to " + steering + " with type " + (steeringType == JobPanel.RESOURCE ? "RESOURCE" : "FILE"));
 
         // Check if the LCSim steering file looks valid.
         if (getJobPanel().checkSteering() == false) {
-            log(Level.SEVERE, "Steering file <" + steering + "> is not valid.");
-            throw new RuntimeException("Invalid LCSim steering file < " + steering + ">");
+            handleError("Steering file is invalid: " + steering, false, true);
         }
 
         try {
             // Create job manager and configure.
             jobManager = new JobControlManager();
             jobManager.setPerformDryRun(true);
-            if (steeringType == getJobPanel().RESOURCE) {
-                log(Level.CONFIG, "Setting up steering resource <" + steering + ">");
+            if (steeringType == JobPanel.RESOURCE) {
+                log(Level.CONFIG, "Setting up steering resource: " + steering);
                 InputStream is = this.getClass().getClassLoader().getResourceAsStream(steering);
                 jobManager.setup(is);
                 is.close();
-            } else if (getSteeringType() == getJobPanel().FILE) {
-                log(Level.CONFIG, "Setting up steering file <" + steering + ">");
+            } else if (getSteeringType() == JobPanel.FILE) {
+                log(Level.CONFIG, "Setting up steering file: " + steering);
                 jobManager.setup(new File(steering));
             }
 
@@ -1128,10 +1159,7 @@
 
             // Catch all other setup exceptions and re-throw them as RuntimeExceptions.
         } catch (Exception e) {
-            e.printStackTrace();
-            log(Level.SEVERE, e.getMessage());
-            log(Level.SEVERE, LCSIM_FAIL_MESSAGE);
-            throw new RuntimeException(LCSIM_FAIL_MESSAGE, e);
+            handleError("Failed to setup LCSim.", false, true);
         }
 
         log(Level.INFO, "LCSim setup was successful.");
@@ -1145,7 +1173,7 @@
         // Setup the EventBuilder class.
         String eventBuilderClassName = getEventBuilderClassName();
 
-        log(Level.CONFIG, "Initializing event builder <" + eventBuilderClassName + ">");
+        log(Level.FINE, "Initializing event builder: " + eventBuilderClassName);
 
         try {
             eventBuilder = (LCSimEventBuilder) Class.forName(eventBuilderClassName).newInstance();
@@ -1156,9 +1184,9 @@
         // Set the detector name on the event builder so it can find conditions data.
         eventBuilder.setDetectorName(getDetectorName());
 
-        log(Level.INFO, "Successfully initialized event builder <" + eventBuilderClassName + ">");
+        log(Level.INFO, "Successfully initialized event builder: " + eventBuilderClassName);
     }
-   
+
     /**
      * Create a connection to an ET system using current parameters from the GUI. If successful,
      * the application's ConnectionStatus is changed to CONNECTED.
@@ -1176,18 +1204,16 @@
             // Set status to connected as there is now a live ET connection.
             setConnectionStatus(ConnectionStatus.CONNECTED);
 
-            log(Level.CONFIG, "Created ET connection to <" + connectionParameters.getBufferName() + ">");
+            log(Level.CONFIG, "Created ET connection: " + connectionParameters.getBufferName());
         } else {
             // Some error occurred and the connection is not valid.
             setConnectionStatus(ConnectionStatus.ERROR);
-            log(Level.SEVERE, "Failed to create ET connection to <" + connectionParameters.getBufferName() + ">");
-            throw new RuntimeException("Failed to create ET connection.");
+            handleError("Failed to create ET connection", false, true);
         }
     }
-    
+
     /**
-     * Save the accumulated log messages to a tab-delimited text file selected using a file
-     * chooser.
+     * Save the log table to a tab-delimited text file selected by a file chooser.
      */
     private void saveLogToFile() {
         JFileChooser fc = new JFileChooser();
@@ -1197,7 +1223,7 @@
         if (fcs == JFileChooser.APPROVE_OPTION) {
             final File logFile = fc.getSelectedFile();
             if (logFile.exists()) {
-                showDialog("The log file already exists.");
+                showMessageDialog("The log file already exists.");
             } else {
                 StringBuffer buf = new StringBuffer();
                 Vector<Vector> rows = logTableModel.getDataVector();
@@ -1208,11 +1234,9 @@
                     BufferedWriter out = new BufferedWriter(new FileWriter(logFile.getPath()));
                     out.write(buf.toString());
                     out.close();
-                    log("Saved log to file <" + logFile.getPath() + ">.");
-                } catch (IOException e) {
-                    e.printStackTrace();
[truncated at 1000 lines; 343 more skipped]

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui
PlotFrame.java added at 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/PlotFrame.java	                        (rev 0)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/PlotFrame.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -0,0 +1,30 @@
+package org.hps.monitoring.gui;
+
+import javax.swing.JFrame;
+import javax.swing.JTabbedPane;
+
+/**
+ * A <code>JFrame</code> where monitoring plots will show.
+ * @author Jeremy McCormick <[log in to unmask]>
+ */
+public class PlotFrame extends JFrame {
+    
+    private JTabbedPane plotPane;
+    
+    PlotFrame() {
+        plotPane = new JTabbedPane();
+        setContentPane(plotPane);
+        setTitle("Monitoring Plots");
+        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+        setResizable(true);
+        pack();           
+    }
+    
+    void reset() {
+        plotPane.removeAll();
+    }       
+    
+    JTabbedPane getPlotPane() {
+        return plotPane;
+    }
+}
\ No newline at end of file

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui
RunPanel.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/RunPanel.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/RunPanel.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -114,7 +114,7 @@
         }
         
         public void endJob() {
-            System.out.println("RunPanelUpdater.endJob");
+            //System.out.println("RunPanelUpdater.endJob");
             timer.cancel();
             timer.purge();
         }

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui
ScreenUtil.java added at 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/ScreenUtil.java	                        (rev 0)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/ScreenUtil.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -0,0 +1,64 @@
+package org.hps.monitoring.gui;
+
+import java.awt.Component;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Rectangle;
+
+import javax.swing.JFrame;
+
+/**
+ * Miscellaneous utility methods for getting information about the graphics environment.
+ * @author Jeremy McCormick <[log in to unmask]>
+ */
+class ScreenUtil {
+
+    static GraphicsDevice graphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
+
+    private ScreenUtil() {
+    }
+
+    static int getScreenWidth() {
+        return graphicsDevice.getDisplayMode().getWidth();
+    }
+
+    static int getScreenHeight() {
+        return graphicsDevice.getDisplayMode().getHeight();
+    }
+
+    static void printGraphicsConfig() {
+        GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        GraphicsDevice[] graphicsDevices = graphicsEnvironment.getScreenDevices();
+        System.out.println("printing graphics config ...");
+        for (GraphicsDevice graphicsDevice : graphicsDevices) {
+            System.out.println(graphicsDevice.getDisplayMode().getWidth() + " x " + graphicsDevice.getDisplayMode().getHeight());
+        }
+    }
+    
+    static void printComponentInfo(Component component) {
+        if (component instanceof JFrame) {
+            System.out.println(((JFrame)component).getTitle());
+        } else {
+            System.out.println(component);
+        }
+        System.out.println("location: " + component.getLocation().getX() + ", " + component.getLocation().getY());
+        System.out.println("size: " + component.getSize().getWidth() + " x " + component.getSize().getHeight());
+        System.out.println();
+    }
+    
+    static GraphicsDevice getGraphicsDevice(int index) {
+        return GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()[index];
+    }
+    
+    static Rectangle getScreenBounds(int index) {
+        return ScreenUtil.getGraphicsDevice(index).getDefaultConfiguration().getBounds();
+    }
+
+    // TODO: Add multi-monitor config ...
+    // http://stackoverflow.com/questions/4627553/java-show-jframe-in-a-specific-screen-in-dual-monitor-configuration
+    // Should put main panel on half of screen #1 and system status panel in right half of same screen.
+    // The plot panel should fill screen #2.
+    
+    // TODO: Add single monitor config.
+    // Should have main panel in upper left, system status panel in lower left, and plots on right.
+}

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui
SettingsDialog.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/SettingsDialog.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/SettingsDialog.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -18,7 +18,6 @@
         setTitle("Settings");
         setContentPane(settingsPanel);
         setResizable(false);
-        setDefaultCloseOperation(HIDE_ON_CLOSE);
         setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
         setModalityType(ModalityType.APPLICATION_MODAL);
         pack();

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record
EventProcessingChain.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/EventProcessingChain.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/EventProcessingChain.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -34,7 +34,6 @@
  * 
  * @author Jeremy McCormick <[log in to unmask]>
  */
-// FIXME: Make sure that end run EVIO events cause the processing to end.
 public class EventProcessingChain extends AbstractLoopListener {
       
     /**
@@ -61,7 +60,7 @@
     private LCSimEventBuilder eventBuilder;
     private int totalEventsProcessed;
     private String detectorName;
-    private Exception lastException;
+    private Throwable lastError;
     private boolean done;
     private boolean paused;
     private boolean wasSetup;
@@ -246,7 +245,7 @@
     public void suspend(LoopEvent loopEvent) {
         if (loopEvent.getException() != null) {
             loopEvent.getException().printStackTrace();
-            lastException = (Exception) loopEvent.getException();
+            lastError = (Exception) loopEvent.getException();
         }
     }
     
@@ -261,25 +260,30 @@
                 try {
                     if (compositeLoop.getState() != State.IDLE)
                         throw new IllegalLoopStateException(compositeLoop.getState());
-                    // Execute GO on the composite loop.
                     compositeLoop.execute(Command.GO, true);
-                } catch (Exception e) {
-                    e.printStackTrace();
-                    // Set the exception.
-                    this.lastException = e;
-                }
+                } catch (RuntimeException exception) {
+                    setLastError(exception);
+                } 
                 
                 // When an exception occurs, which can sometimes just be control flow,
                 // the event processing should stop.
-                if (lastException != null) {
-                    lastException.printStackTrace();
-                    if (!done)
-                        // Call finish manually here as the loop was suspended.
-                        finish(); 
+                if (lastError != null) {
+                    if (!done) {
+                        // Call finish manually here as the loop was suspended.                        
+                        finish();
+                    }
                 } 
             }
         }
     }
+        
+    void setLastError(Throwable error) {
+        this.lastError = error;
+    }
+    
+    public Throwable getLastError() {
+        return lastError;
+    }
 
     /**
      * Pause the event processing.
@@ -295,12 +299,8 @@
      * Finish the event processing.
      */
     public void finish() {
-        // TODO: Add check here for correct loop state.
-        try {
-            compositeLoop.execute(Command.STOP);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
+        // TODO: Add check here for correct loop state.        
+        compositeLoop.execute(Command.STOP);    
         done = true;
     }    
         

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record
EventProcessingThread.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/EventProcessingThread.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/EventProcessingThread.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -7,7 +7,7 @@
 public class EventProcessingThread extends Thread {
     
     EventProcessingChain processing;
-    
+           
     public EventProcessingThread(EventProcessingChain processing) {
         super("EventProcessingThread");
         this.processing = processing;
@@ -22,7 +22,9 @@
         try {
             processing.loop();
         } catch (Exception e) {
+            System.out.println("EventProcessingThread caught exception...");
             e.printStackTrace();
+            return; // DEBUG
         }
     }
 }
\ No newline at end of file

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record
EvioProcessingStep.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/EvioProcessingStep.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/EvioProcessingStep.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -114,7 +114,7 @@
             if (stopOnEndRun)
                 throw new EndRunException("EVIO end event received, and stop on end run is enabled.");
         
-        System.out.println("done with EvioProcessingStep.processEvent");
+        //System.out.println("done with EvioProcessingStep.processEvent");
     }
     
     /**

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/composite
CompositeRecordLoop.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/composite/CompositeRecordLoop.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/composite/CompositeRecordLoop.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -1,5 +1,7 @@
 package org.hps.monitoring.record.composite;
 
+import java.io.IOException;
+
 import org.freehep.record.loop.DefaultRecordLoop;
 import org.freehep.record.source.RecordSource;
 
@@ -37,4 +39,16 @@
     public void addProcessor(CompositeRecordProcessor processor) {
         adapter.addProcessor(processor);
     }
+    
+    protected void handleClientError(Throwable x) {
+        //System.out.println("CompositeRecordLoop.handleClientError - handling error " + x.getClass().getCanonicalName());
+        //x.printStackTrace();
+        throw new RuntimeException("Error during event processing.", x);
+    }
+
+    protected void handleSourceError(Throwable x) {
+        //System.out.println("CompositeRecordLoop.handleSourceError - handling error " + x.getClass().getCanonicalName());        
+        //x.printStackTrace();
+        throw new RuntimeException("Error during event processing.", x);
+    }        
 }

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/composite
CompositeRecordLoopAdapter.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/composite/CompositeRecordLoopAdapter.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/composite/CompositeRecordLoopAdapter.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -20,13 +20,16 @@
      * Callback for loop finish event.
      * @param loopEvent 
      */
+    // FIXME: Should this check if an error occurred?
     public void finish(LoopEvent loopEvent) {
-        if (loopEvent.getException() != null)
-            loopEvent.getException().printStackTrace();
-      
+        
+        //System.out.println("CompositeRecordLoopAdapter.finish");        
+        //if (loopEvent.getException() != null)
+        //    loopEvent.getException().printStackTrace();      
         // Call end job hook on all registered processors, which are 
         // responsible for sending the stop command to their loops, if applicable.
         for (CompositeRecordProcessor processor : processors) {
+            //System.out.println("calling endJob() on " + processor.getClass().getCanonicalName() + "...");
             processor.endJob();
         }
     }
@@ -54,10 +57,10 @@
      * Suspend the loop.
      * @param loopEvent
      */
-    // NOTE: IOExceptions from loop processing show up here!!!
-    public void suspend(LoopEvent loopEvent) {        
-        if (loopEvent.getException() != null)
-            loopEvent.getException().printStackTrace();
+    public void suspend(LoopEvent loopEvent) { 
+        if (loopEvent.getException() != null) {
+            throw new RuntimeException("Error in event processing.", loopEvent.getException());
+        }
     }
 
     /**
@@ -69,7 +72,7 @@
         for (CompositeRecordProcessor processor : processors) {
             try {
                 processor.processEvent((CompositeRecord) record.getRecord());
-            } catch (Exception e) {
+            } catch (Exception e) {                
                 throw new RuntimeException("Error processing CompositeRecord.", e);
             }
         }

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/etevent
EtConnection.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/etevent/EtConnection.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/etevent/EtConnection.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -79,7 +79,7 @@
      * Cleanup the ET connection.
      */
     public void cleanup() {
-        boolean debug = true;
+        boolean debug = false;
         try {
             if (!sys.alive()) {
                 throw new RuntimeException("EtSystem is not alive!");
@@ -160,8 +160,8 @@
     
     /**
      * Read EtEvent objects from the ET ring.  
-     * Preserve all specific Exception types in throws clause so caller
-     * can implement their own error and state handling.
+     * Preserve all specific Exception types in the throws clause so caller
+     * may implement their own error and state handling.
      * @return
      * @throws IOException
      * @throws EtException

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/etevent
EtEventAdapter.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/etevent/EtEventAdapter.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/etevent/EtEventAdapter.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -26,6 +26,18 @@
         }
     }
     
+    // NOTE: This is called between every execution of the GO_N command!!!
+    public void suspend(LoopEvent event) {
+        //System.out.println("EtEventAdapter.suspend");        
+        if (event.getException() != null) {
+            //System.out.println("current error: " + event.getException().getMessage());
+            //System.out.println("ending job from suspend");
+            for (EtEventProcessor processor : processors) {
+                processor.endJob();
+            }
+        }
+    }
+    
     @Override
     public void start(LoopEvent event) {
         for (EtEventProcessor processor : processors) {

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/etevent
EtEventLoop.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/etevent/EtEventLoop.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/etevent/EtEventLoop.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -1,7 +1,5 @@
 package org.hps.monitoring.record.etevent;
 
-import java.io.IOException;
-
 import org.freehep.record.loop.DefaultRecordLoop;
 import org.freehep.record.source.RecordSource;
 import org.jlab.coda.et.EtEvent;
@@ -38,4 +36,18 @@
         }        
         super.setRecordSource(source);
     }
+    
+    protected void handleClientError(Throwable x) {
+        if (x != null) {
+            //x.printStackTrace();
+            throw new RuntimeException(x);
+        }
+    }
+
+    protected void handleSourceError(Throwable x) {
+        if (x != null) {
+            //x.printStackTrace();
+            throw new RuntimeException(x);
+        }
+    }     
 }

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/etevent
EtEventSource.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/etevent/EtEventSource.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/etevent/EtEventSource.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -101,9 +101,9 @@
     void readEtEvents() throws IOException {
         try {
             EtEvent[] mevs = connection.readEtEvents();
-            eventQueue.addAll(Arrays.asList(mevs));
+            eventQueue.addAll(Arrays.asList(mevs));        
         } catch (Exception e) {
-            throw new IOException(e);
+            throw new IOException("Error while reading ET events.", e);
         }
     }
 }
\ No newline at end of file

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/evio
EvioAdapter.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/evio/EvioAdapter.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/evio/EvioAdapter.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -45,13 +45,25 @@
     
     @Override
     public void finish(LoopEvent event) {
-        System.out.println("EvioAdapter.finish");
+        //System.out.println("EvioAdapter.finish");
         for (EvioEventProcessor processor : processors) {
-            System.out.println(processor.getClass().getCanonicalName() + ".endJob");
+            //System.out.println(processor.getClass().getCanonicalName() + ".endJob");
             processor.endJob();
         }
     }    
     
+    // NOTE: This is called between every execution of the GO_N command!!!
+    public void suspend(LoopEvent event) {
+        //System.out.println("EvioAdapter.suspend");        
+        if (event.getException() != null) {
+            //System.out.println("current error: " + event.getException().getMessage());
+            //System.out.println("ending job from suspend");
+            for (EvioEventProcessor processor : processors) {
+                processor.endJob();
+            }
+        }
+    }
+    
     void addEvioEventProcessor(EvioEventProcessor processor) {
         processors.add(processor);
     }

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/evio
EvioEventLoop.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/evio/EvioEventLoop.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/evio/EvioEventLoop.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -45,4 +45,18 @@
             throw (IOException) t;
         return getSupplied();
     }
+    
+    protected void handleClientError(Throwable x) {
+        if (x != null) {
+            x.printStackTrace();
+            throw new RuntimeException(x);
+        }
+    }
+
+    protected void handleSourceError(Throwable x) {
+        if (x != null) {
+            x.printStackTrace();
+            throw new RuntimeException(x);
+        }
+    }
 }

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/evio
EvioFileProducer.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/evio/EvioFileProducer.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/record/evio/EvioFileProducer.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -25,7 +25,6 @@
  *
  */
 // TODO: Add option to set number of events in the put array.
-// TODO: Move to a sub-package.
 public class EvioFileProducer {
 
     private List<File> evioFiles = new ArrayList<File>();

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/subsys
SystemStatisticsImpl.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/subsys/SystemStatisticsImpl.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/subsys/SystemStatisticsImpl.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -150,7 +150,6 @@
 
     @Override
     public void stop() { 
-        System.out.println("SystemStatistics.stop");
         // Kill the Timer.
         if (timer != null)
             timer.cancel();
@@ -162,19 +161,19 @@
     @Override
     public void printSession(PrintStream ps) {
         ps.println("session statistics ...");
-        ps.println("  getTimeElapsedMillis = " + this.getTimeElapsedMillis());
-        ps.println("  getCumulativeEvents = " + this.getCumulativeEvents());
-        ps.println("  getAverageEventsPerSecond = " + this.getAverageEventsPerSecond());
-        ps.println("  getAverageMegaBytesPerSecond = " + this.getAverageMbPerSecond());
+        ps.println("  timeElapsedMillis = " + this.getTimeElapsedMillis());
+        ps.println("  cumulativeEvents = " + this.getCumulativeEvents());
+        ps.println("  averageEventsPerSecond = " + this.getAverageEventsPerSecond());
+        ps.println("  averageMegaBytesPerSecond = " + this.getAverageMbPerSecond());
         
     }
     
     @Override
     public void printTick(PrintStream ps) {
         ps.println("tick statistics ...");
-        ps.println("  getTickElapsedMillis = " + this.getTickElapsedMillis());
-        ps.println("  getEventsSinceTick = " + this.getEventsInTick());
-        ps.println("  getBytesSinceTick = " + this.getBytesInTick());
+        ps.println("  tickElapsedMillis = " + this.getTickElapsedMillis());
+        ps.println("  eventsSinceTick = " + this.getEventsInTick());
+        ps.println("  bytesSinceTick = " + this.getBytesInTick());
     }
     
     @Override

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/subsys
SystemStatus.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/subsys/SystemStatus.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/subsys/SystemStatus.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -2,12 +2,15 @@
 
 /**
  * The <tt>SystemStatus</tt> describes the state of a system, e.g. whether it is okay 
- * or some level of error has occurred.  Listeners can be registered, which will 
- * be notified whenever the status changes, in order to update a GUI, trip an alarm, etc.
+ * or some level of error has occurred.  Listeners can be registered on these objects, 
+ * which will be notified whenever the status changes, in order to update a GUI component, 
+ * trip an alarm, etc.
  * 
  * There is one <tt>SystemStatus</tt> object for each quantity to be monitored
  * on a sub-system.  New objects are not created when the status changes.  Instead,
  * the <tt>StatusCode</tt> is changed with a custom message describing the new state.
+ * Listeners are updated whenever the status is changed.  It is up to the notified
+ * object to determine what to do when the state changes.  
  * 
  * @author Jeremy McCormick <[log in to unmask]>
  */
@@ -18,7 +21,7 @@
      */
     enum StatusCode {
         
-        // Status encodings with a string name and descriptor.
+        /** Status encodings with a string name and descriptor. */
         OKAY   (0, "okay",    "The system appears to be working."),
         UNKNOWN(1, "unknown", "The status is not known."),
         OFFLINE(2, "offline", "The system is currently offline."),               
@@ -106,4 +109,17 @@
      * @param listener The listener object.
      */
     void addListener(SystemStatusListener listener);
+    
+    /**
+     * Set whether this status is masked on or off.  
+     * Listeners will not be notified of state changes when masked
+     * is set to <code>True</code>.     
+     */
+    void setMasked(boolean masked);
+    
+    /**
+     * True if the status has been masked off.
+     * @return True if status is masked off.
+     */
+    boolean isMasked();
 }

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/subsys
SystemStatusImpl.java 757 -> 758
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/subsys/SystemStatusImpl.java	2014-07-03 20:21:06 UTC (rev 757)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/subsys/SystemStatusImpl.java	2014-07-03 23:48:55 UTC (rev 758)
@@ -15,6 +15,7 @@
     List<SystemStatusListener> listeners = new ArrayList<SystemStatusListener>();
     String systemName = "";
     String description = "";
+    boolean masked;
     
     SystemStatusImpl(String systemName, String description) {
         this.systemName = systemName;
@@ -47,7 +48,8 @@
         this.code = code;
         this.message = message;
         setCurrentTime();
-        notifyListeners();
+        if (!isMasked())
+            notifyListeners();
     }
 
     @Override
@@ -72,4 +74,14 @@
     private void setCurrentTime() {
         this.lastChangedMillis = System.currentTimeMillis();
     }
+ 
+    @Override
+    public void setMasked(boolean masked) {
+        this.masked = masked;
+    }
+    
+    @Override
+    public boolean isMasked() {
+        return masked;
+    }
 }
SVNspam 0.1