Print

Print


Author: [log in to unmask]
Date: Mon Mar 30 17:54:19 2015
New Revision: 2631

Log:
Add support for recent files menu.

Added:
    java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ToolbarPanel.java
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/DataSourceComboBox.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/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/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

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	Mon Mar 30 17:54:19 2015
@@ -15,6 +15,7 @@
     // 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";

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	Mon Mar 30 17:54:19 2015
@@ -1,5 +1,6 @@
 package org.hps.monitoring.application;
 
+import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -8,7 +9,10 @@
 import java.io.File;
 
 import javax.swing.DefaultComboBoxModel;
+import javax.swing.DefaultListCellRenderer;
 import javax.swing.JComboBox;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
 
 import org.hps.monitoring.application.DataSourceComboBox.DataSourceItem;
 import org.hps.monitoring.application.model.ConfigurationModel;
@@ -17,13 +21,13 @@
 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 selected a new data source for the new session. 
  * <p>
- * This is a combo box that shows and can be used to select the current data source
- * such as an LCIO file, EVIO file or ET ring.
+ * 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.
  * <p>
- * The way this works is kind of funky because it is not directly connected to an
- * event loop, so it must catch changes to the configuration and update its 
- * items accordingly.
+ * 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]>
  */
@@ -34,15 +38,34 @@
 
     static class DataSourceItem {
 
-        String name;
-        DataSourceType type;
-
-        DataSourceItem(String name, DataSourceType type) {
+        private String name;
+        private String path;
+        private DataSourceType type;
+
+        DataSourceItem(String path, String name, DataSourceType type) {
+            if (path == null) {
+                throw new IllegalArgumentException("path is null");
+            }
+            if (name == null) {
+                throw new IllegalArgumentException("name is null");
+            }
+            if (type == null) {
+                throw new IllegalArgumentException("type is null");
+            }
             this.type = type;
             this.name = name;
+            this.path = path;
         }
 
         public String toString() {
+            return name;
+        }
+        
+        public String getPath() {
+            return path;
+        }
+        
+        public String getName() {
             return name;
         }
 
@@ -51,23 +74,42 @@
                 return false;
             }
             DataSourceItem otherItem = (DataSourceItem) object;
-            if (this.name == otherItem.name && this.type == otherItem.type)
+            if (this.name == otherItem.name && this.path == otherItem.path && this.type == otherItem.type) {
                 return true;
-            return false;
-        }
-    }
-    
+            } else {
+                return false;
+            }
+        }
+    }
+    
+    @SuppressWarnings({ "rawtypes", "serial", "unchecked" })
     DataSourceComboBox(ConfigurationModel configurationModel, ConnectionStatusModel connectionModel) {
         addActionListener(this);
         setActionCommand(Commands.DATA_SOURCE_CHANGED);
-        setPreferredSize(new Dimension(400, this.getPreferredSize().height));
+        setPreferredSize(new Dimension(510, this.getPreferredSize().height));
         setEditable(false);
         this.configurationModel = configurationModel;
         connectionModel.addPropertyChangeListener(this);                
         configurationModel.addPropertyChangeListener(this);
+        
+        ListCellRenderer renderer = new DefaultListCellRenderer() {
+            @Override
+            public Component getListCellRendererComponent(JList<?> list,
+                    Object value, int index, boolean isSelected,
+                    boolean cellHasFocus) {
+                if (value instanceof DataSourceItem) {
+                    setToolTipText(((DataSourceItem)value).getPath());
+                } else {
+                    setToolTipText(null);
+                }
+                return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+            }
+
+        };
+        this.setRenderer(renderer);
     }
             
-    boolean contains(DataSourceItem item) {
+    boolean containsItem(DataSourceItem item) {
         return ((DefaultComboBoxModel<DataSourceItem>) getModel()).getIndexOf(item) != -1;
     }
 
@@ -83,11 +125,11 @@
                     setEnabled(false);
                 }
             } else if (evt.getPropertyName().equals(ConfigurationModel.DATA_SOURCE_PATH_PROPERTY)) {
-                if (configurationModel.hasValidProperty(ConfigurationModel.DATA_SOURCE_TYPE_PROPERTY)) {
+                if (configurationModel.hasValidProperty(ConfigurationModel.DATA_SOURCE_TYPE_PROPERTY)) {                    
                     String path = configurationModel.getDataSourcePath();
-                    DataSourceType type = getDataSourceType(path);
+                    DataSourceType type = DataSourceType.getDataSourceType(path);
                     if (type.isFile()) {
-                        DataSourceItem item = findItem(path, type);
+                        DataSourceItem item = findItem(path);
                         if (item == null) {
                             item = addDataSourceItem(path, type);
                         }
@@ -100,12 +142,12 @@
                 if (configurationModel.getDataSourceType() == DataSourceType.ET_SERVER) {
                     DataSourceItem item = findEtItem();
                     if (item == null) {
-                        item = new DataSourceItem(configurationModel.getEtPath(), DataSourceType.ET_SERVER);
+                        item = new DataSourceItem(configurationModel.getEtPath(), configurationModel.getEtPath(), DataSourceType.ET_SERVER);
                     }
                     setSelectedItem(item);
                 } else {
                     if (configurationModel.hasValidProperty(ConfigurationModel.DATA_SOURCE_PATH_PROPERTY)) {
-                        DataSourceItem item = findItem(configurationModel.getDataSourcePath(), configurationModel.getDataSourceType());
+                        DataSourceItem item = findItem(configurationModel.getDataSourcePath());
                         if (item == null) {
                             item = addDataSourceItem(configurationModel.getDataSourcePath(), configurationModel.getDataSourceType());
                         }
@@ -124,14 +166,10 @@
         }
     }
     
-    static DataSourceType getDataSourceType(String path) {
-        if (path.endsWith(".slcio")) {
-            return DataSourceType.LCIO_FILE;
-        } else if (new File(path).getName().contains(".evio")) {
-            return DataSourceType.EVIO_FILE;
-        } else {
-            return DataSourceType.ET_SERVER;
-        }
+    @Override
+    public void setSelectedItem(Object object) {
+        super.setSelectedItem(object);
+        this.setToolTipText(((DataSourceItem)object).getPath());
     }
 
     public void actionPerformed(ActionEvent evt) {
@@ -143,7 +181,7 @@
                 if (item != null) {
                     configurationModel.setDataSourceType(item.type);
                     if (item.type != DataSourceType.ET_SERVER) {
-                        configurationModel.setDataSourcePath(item.name);
+                        configurationModel.setDataSourcePath(item.getPath());
                     }
                 }
             } finally {
@@ -153,22 +191,20 @@
     }
        
     public void addItem(DataSourceItem item) {
-        // Do not add invalid looking items.
-        if (item.name == null || item.name.length() == 0) { 
+        if (containsItem(item)) {
             return;
         }
-        // Do not add duplicates.
-        if (!contains(item)) {
+        if (findItem(item.getPath()) == null) {
             super.addItem(item);
         }
     }
 
-    DataSourceItem findItem(String path, DataSourceType type) {
+    DataSourceItem findItem(String path) {
         for (int i = 0; i < this.getItemCount(); i++) {
             DataSourceItem item = this.getItemAt(i);
-            if (item.type == type && item.name == path) {
+            if (item.getPath().equals(path)) {
                 return item;
-            }            
+            }
         }
         return null;
     }
@@ -184,7 +220,7 @@
     }
 
     DataSourceItem addDataSourceItem(String path, DataSourceType type) {
-        DataSourceItem newItem = new DataSourceItem(path, type);
+        DataSourceItem newItem = new DataSourceItem(path, new File(path).getName(), type);
         addItem(newItem);
         return newItem;
     }
@@ -192,7 +228,7 @@
     void updateEtItem() {
         DataSourceItem item = findEtItem();
         if (item == null) {
-            item = new DataSourceItem(configurationModel.getEtPath(), DataSourceType.ET_SERVER);
+            item = new DataSourceItem(configurationModel.getEtPath(), configurationModel.getEtPath(), DataSourceType.ET_SERVER);
             addItem(item);
         } else {
             item.name = configurationModel.getEtPath();

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	Mon Mar 30 17:54:19 2015
@@ -219,6 +219,8 @@
      */
     void setupLoop(ConfigurationModel configurationModel) {
 
+        logger.config("setting up record loop ...");
+        
         CompositeLoopConfiguration loopConfig = new CompositeLoopConfiguration()
             .setStopOnEndRun(configurationModel.getDisconnectOnEndRun())
             .setStopOnErrors(configurationModel.getDisconnectOnError())
@@ -227,6 +229,9 @@
             .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());
 
         if (configurationModel.hasValidProperty(ConfigurationModel.MAX_EVENTS_PROPERTY)) {
             long maxEvents = configurationModel.getMaxEvents();
@@ -238,39 +243,41 @@
         // Add all Drivers from the JobManager.
         for (Driver driver : sessionState.jobManager.getDriverExecList()) {
             loopConfig.add(driver);
-            logger.config("added Driver " + driver.getName() + " to job");
+            logger.config("added Driver " + driver.getName());
         }
 
         // Using ET server?
         if (configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER)) {
 
             // ET system monitor.
-            logger.config("added EtSystemMonitor to job");
+            logger.config("added EtSystemMonitor");
             loopConfig.add(new EtSystemMonitor());
 
             // ET system strip charts.
-            logger.config("added EtSystemStripCharts to job");
+            logger.config("added EtSystemStripCharts");
             loopConfig.add(new EtSystemStripCharts());
         }
 
         // Add extra CompositeRecordProcessors to the loop config.
         for (CompositeRecordProcessor processor : sessionState.processors) {
             loopConfig.add(processor);
-            logger.config("added extra processor " + processor.getClass().getSimpleName() + " to job");
+            logger.config("added extra processor " + processor.getClass().getSimpleName());
         }
 
         // Add extra Drivers to the loop config.
         for (Driver driver : sessionState.drivers) {
             loopConfig.add(driver);
-            logger.config("added extra Driver " + driver.getName() + " to job");
+            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());
-        loopConfig.add(new EvioDetectorConditionsProcessor(configurationModel.getDetectorName()));
 
         // Create the CompositeLoop with the configuration.
         sessionState.loop = new CompositeLoop(loopConfig);
+        
+        logger.config("record loop is setup");
     }
 
     /**

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	Mon Mar 30 17:54:19 2015
@@ -5,6 +5,7 @@
 import java.awt.event.KeyEvent;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.util.List;
 
 import javax.swing.JMenu;
 import javax.swing.JMenuBar;
@@ -20,15 +21,33 @@
  * 
  * @author Jeremy McCormick <[log in to unmask]>
  */
+@SuppressWarnings("serial")
 class MenuBar extends JMenuBar implements PropertyChangeListener, ActionListener {
+    
+    ConfigurationModel configurationModel;
     
     JMenuItem closeFileItem;
     JMenuItem openFileItem;    
     JMenu settingsMenu;
     JMenuItem logItem;
     JMenuItem serverItem;
-    ConfigurationModel configurationModel;    
-    
+    JMenu recentFilesMenu;    
+    
+    class RecentFileItem extends JMenuItem {
+        
+        String path;        
+        
+        RecentFileItem(String path, 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;        
@@ -62,6 +81,11 @@
         exitItem.setToolTipText("Exit from the application");
         fileMenu.add(exitItem);
                 
+        recentFilesMenu = new JMenu("RecentFiles");
+        recentFilesMenu.setMnemonic(KeyEvent.VK_R);
+        recentFilesMenu.setToolTipText("List of recent data files");
+        fileMenu.add(recentFilesMenu);
+                
         settingsMenu = new JMenu("Settings");
         settingsMenu.setMnemonic(KeyEvent.VK_S);
         add(settingsMenu);
@@ -127,7 +151,7 @@
         toolsMenu.add(screenshotItem);
         
         logItem = new JMenuItem("Log to File ...");
-        logItem.setMnemonic(KeyEvent.VK_R);
+        logItem.setMnemonic(KeyEvent.VK_L);
         logItem.setActionCommand(Commands.LOG_TO_FILE);
         logItem.addActionListener(listener);
         logItem.setEnabled(true);
@@ -168,7 +192,7 @@
         defaultsItem.addActionListener(listener);
         defaultsItem.setEnabled(true);
         defaultsItem.setToolTipText("Restore the window defaults");
-        windowMenu.add(defaultsItem);
+        windowMenu.add(defaultsItem);               
     }
 
     @Override
@@ -193,7 +217,10 @@
                     logItem.setActionCommand(Commands.LOG_TO_FILE);
                     logItem.setToolTipText("Log messages to a file");
                 }
-            }
+            } else if (evt.getPropertyName().equals(ConfigurationModel.RECENT_FILES_PROPERTY)) {
+                setRecentFiles(configurationModel.getRecentFilesList());
+            } 
+            
         } finally {
             configurationModel.addPropertyChangeListener(this);
         }
@@ -207,8 +234,26 @@
             } 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);
+            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);
+                }
+            });                
+            recentFilesMenu.add(recentFileItem);
+            ++fileMnemonic;
         }        
-    }    
+    }
     
     void startAIDAServer() {
         serverItem.setActionCommand(Commands.STOP_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	Mon Mar 30 17:54:19 2015
@@ -46,9 +46,9 @@
 import org.hps.monitoring.application.util.ErrorHandler;
 import org.hps.monitoring.application.util.EvioFileFilter;
 import org.hps.monitoring.application.util.TableExporter;
+import org.hps.monitoring.plotting.ExportPdf;
 import org.hps.monitoring.plotting.MonitoringAnalysisFactory;
 import org.hps.monitoring.plotting.MonitoringPlotFactory;
-import org.hps.monitoring.plotting.ExportPdf;
 import org.hps.monitoring.subsys.SystemStatus;
 import org.hps.monitoring.subsys.SystemStatusRegistry;
 import org.hps.record.composite.CompositeRecordProcessor;
@@ -56,7 +56,6 @@
 import org.lcsim.conditions.ConditionsListener;
 import org.lcsim.util.Driver;
 import org.lcsim.util.aida.AIDA;
-import org.lcsim.util.aida.PDFWriter;
 import org.lcsim.util.log.DefaultLogFormatter;
 
 /**
@@ -91,10 +90,7 @@
     final RunModel runModel = new RunModel();
     final ConfigurationModel configurationModel = new ConfigurationModel();
     final ConnectionStatusModel connectionModel = new ConnectionStatusModel();
-    
-    // The global configuration settings.
-    Configuration configuration;
-    
+        
     // The default configuration resource embedded in the jar.
     static final String DEFAULT_CONFIGURATION = "/org/hps/monitoring/config/default_config.prop";
 
@@ -206,17 +202,14 @@
                
             // Setup AIDA plotting and connect it to the GUI.
             setupAida();
-        
-            // TODO: Make sure the configuration loading here is working properly!!!
-            
-            // Always load the default configuration first.
-            this.configuration = new Configuration(DEFAULT_CONFIGURATION);
-            loadConfiguration(this.configuration);
-            
-            // Overlay the user configuration if one was specified.
+            
+            // Load the default configuration.
+            loadConfiguration(new Configuration(DEFAULT_CONFIGURATION), false);
+                    
             if (userConfiguration != null) {
-                loadConfiguration(userConfiguration);
-            }
+                // Load user configuration.
+                loadConfiguration(userConfiguration, true);
+            } 
         
             // Enable the GUI now that initialization is complete.
             frame.setEnabled(true);
@@ -357,19 +350,23 @@
      * This method sets the configuration on the model, which fires a change for every property.
      * @param configuration The new configuration.
      */
-    void loadConfiguration(Configuration configuration) {
-        
-        this.configuration = configuration;
-        
-        // HACK: Clear data source combo box for new config.
-        frame.dataSourceComboBox.removeAllItems();
-        
-        // Set the Configuration on the ConfigurationModel which will trigger all the PropertyChangelListeners.
-        configurationModel.setConfiguration(this.configuration);
-        if (this.configuration.getFile() != null)
-            logger.config("loaded config from file " + this.configuration.getFile().getPath());
+    void loadConfiguration(Configuration configuration, boolean merge) {
+                               
+        if (merge) {
+            // This will merge in additional properties so that default or current settings are preserved.
+            configurationModel.merge(configuration);
+        } else {
+            // HACK: Clear data source combo box for clean configuration.
+            frame.toolbarPanel.dataSourceComboBox.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 " + this.configuration.getResourcePath());
+            logger.config("loaded config from resource " + configuration.getResourcePath());
     }
               
     /**
@@ -540,8 +537,7 @@
      * Load default application settings.
      */
     void loadDefaultSettings() {
-        configuration = new Configuration(MonitoringApplication.DEFAULT_CONFIGURATION);
-        configurationModel.setConfiguration(configuration);
+        loadConfiguration(new Configuration(MonitoringApplication.DEFAULT_CONFIGURATION), false);
         DialogUtil.showInfoDialog(frame, "Default Configuration Loaded", "The default configuration was loaded.");
         logger.config("default settings loaded");
     }
@@ -583,6 +579,8 @@
             configurationModel.setDataSourcePath(filePath);
             configurationModel.setDataSourceType(type);
             
+            configurationModel.addRecentFile(filePath);
+            
             logger.config("set new data source " + filePath + " with type " + type);
         }
     }    
@@ -597,7 +595,7 @@
         int r = fc.showSaveDialog(frame);
         if (r == JFileChooser.APPROVE_OPTION) {
             File f = fc.getSelectedFile();
-            configuration.writeToFile(f);
+            configurationModel.getConfiguration().writeToFile(f);
             logger.info("saved configuration to file: " + f.getPath());
             DialogUtil.showInfoDialog(frame, "Settings Saved", "Settings were saved successfully.");
         }
@@ -613,7 +611,7 @@
         int r = fc.showDialog(frame, "Load ...");
         if (r == JFileChooser.APPROVE_OPTION) {
             File f = fc.getSelectedFile();
-            loadConfiguration(new Configuration(f));
+            loadConfiguration(new Configuration(f), true);
             logger.info("loaded configuration from file: " + f.getPath());
             DialogUtil.showInfoDialog(frame, "Settings Loaded", "Settings were loaded successfully.");
         }
@@ -646,9 +644,9 @@
      */
     void closeFile() {
         if (!configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER)) {
-            DataSourceItem item = (DataSourceItem) frame.dataSourceComboBox.getSelectedItem();
-            if (item.name.equals(configurationModel.getDataSourcePath())) {
-                frame.dataSourceComboBox.removeItem(frame.dataSourceComboBox.getSelectedItem());    
+            DataSourceItem item = (DataSourceItem) frame.toolbarPanel.dataSourceComboBox.getSelectedItem();
+            if (item.getPath().equals(configurationModel.getDataSourcePath())) {
+                frame.toolbarPanel.dataSourceComboBox.removeItem(frame.toolbarPanel.dataSourceComboBox.getSelectedItem());    
             }            
         }
     }

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	Mon Mar 30 17:54:19 2015
@@ -2,40 +2,36 @@
 
 import java.awt.BorderLayout;
 import java.awt.Dimension;
-import java.awt.FlowLayout;
 import java.awt.GraphicsEnvironment;
 import java.awt.Rectangle;
 
 import javax.swing.JFrame;
 import javax.swing.JPanel;
-import javax.swing.JSeparator;
 import javax.swing.JSplitPane;
 import javax.swing.JTabbedPane;
-import javax.swing.SwingConstants;
 
 /**
  * This class instantiates the primary GUI components of the monitoring application.
  * 
  * @author Jeremy McCormick <[log in to unmask]>
  */
+@SuppressWarnings("serial")
 class MonitoringApplicationFrame extends JFrame {
             
     EventDashboard dashboardPanel;    
     PlotPanel plotPanel;
     PlotInfoPanel plotInfoPanel;
     LogPanel logPanel;
-    JPanel buttonsPanel;
     TriggerDiagnosticsPanel triggerPanel;
     ConditionsPanel conditionsPanel;
     SystemStatusPanel systemStatusPanel;
+    ToolbarPanel toolbarPanel;
     MenuBar menu; 
     
     JSplitPane mainSplitPane;
     JSplitPane rightSplitPane;
     JSplitPane leftSplitPane;
-    
-    DataSourceComboBox dataSourceComboBox;
-    
+        
     SettingsDialog settingsDialog;
        
     static final Rectangle BOUNDS = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds();
@@ -60,31 +56,9 @@
         contentPanel.setPreferredSize(new Dimension(PIXEL_WIDTH_MAX, PIXEL_HEIGHT_MAX));
                 
         // Create the top panel.
-        JPanel topPanel = new JPanel();
-        topPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 0));
-        contentPanel.add(topPanel, BorderLayout.NORTH);
-                
-        // Create the connection status panel.
-        JPanel connectionPanel = new ConnectionStatusPanel(application.connectionModel);
-        topPanel.add(connectionPanel);
-        
-        // Add vertical separator.
-        JSeparator sep = new JSeparator(SwingConstants.VERTICAL);
-        sep.setPreferredSize(new Dimension(5, topPanel.getPreferredSize().height));
-        topPanel.add(sep);
-        
-        // Create the buttons panel.
-        buttonsPanel = new EventButtonsPanel(application.connectionModel, application);
-        topPanel.add(buttonsPanel);
-        
-        // Add vertical separator.
-        sep = new JSeparator(SwingConstants.VERTICAL);
-        topPanel.add(sep);
-        
-        // Add the data source combo box.
-        dataSourceComboBox = new DataSourceComboBox(application.configurationModel, application.connectionModel);
-        topPanel.add(dataSourceComboBox);
-        
+        toolbarPanel = new ToolbarPanel(application.configurationModel, application.connectionModel, application);        
+        contentPanel.add(toolbarPanel, BorderLayout.NORTH);
+                        
         // Create the bottom panel.
         JPanel bottomPanel = new JPanel();
         bottomPanel.setLayout(new BorderLayout());
@@ -146,7 +120,7 @@
         // Create the menu bar.
         menu = new MenuBar(application.configurationModel, application.connectionModel, application);
         setJMenuBar(menu);
-        dataSourceComboBox.addActionListener(menu);
+        toolbarPanel.dataSourceComboBox.addActionListener(menu);
         
         // Setup the settings dialog box (invisible until activated).
         settingsDialog = new SettingsDialog(application.configurationModel, application);        

Added: 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	(added)
+++ java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ToolbarPanel.java	Mon Mar 30 17:54:19 2015
@@ -0,0 +1,65 @@
+package org.hps.monitoring.application;
+
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionListener;
+
+import javax.swing.JPanel;
+
+import org.hps.monitoring.application.model.ConfigurationModel;
+import org.hps.monitoring.application.model.ConnectionStatusModel;
+
+/**
+ * A GUI component for the top-level toolbar of the monitoring app.
+ * 
+ * @author Jeremy McCormick <[log in to unmask]>
+ */
+public class ToolbarPanel extends JPanel {
+
+    DataSourceComboBox dataSourceComboBox;
+    JPanel buttonsPanel;
+
+    ToolbarPanel(ConfigurationModel configurationModel, ConnectionStatusModel connectionModel, ActionListener listener) {
+
+        setLayout(new FlowLayout(FlowLayout.LEFT));
+        
+        JPanel containerPanel = new JPanel();
+        containerPanel.setLayout(new GridBagLayout());
+        
+        // Create the connection status panel.
+        GridBagConstraints gbs = new GridBagConstraints();
+        gbs.anchor = GridBagConstraints.WEST;
+        gbs.gridx = 0;
+        gbs.gridy = 0;
+        gbs.weightx = 0.5;
+        gbs.fill = GridBagConstraints.BOTH;
+        gbs.insets = new Insets(10, 0, 0, 10);
+        JPanel connectionPanel = new ConnectionStatusPanel(connectionModel);
+        containerPanel.add(connectionPanel, gbs);
+
+        // Create the buttons panel.
+        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);
+
+        // Add the data source combo box.
+        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);
+    }
+
+}

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	Mon Mar 30 17:54:19 2015
@@ -7,6 +7,8 @@
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 
 import javassist.Modifier;
@@ -41,8 +43,8 @@
 
     abstract public String[] getPropertyNames();
 
-    public void fireModelChanged() {
-        propertyLoop: for (String property : 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)) {
@@ -50,6 +52,7 @@
                     break;
                 }
             }
+            //System.out.println(getMethod.getName());
             try {
                 Object value = null;
                 try {
@@ -65,6 +68,7 @@
                         System.err.println("The key " + property + " is not set in the configuration.");
                         continue propertyLoop;
                     } else {
+                        e.printStackTrace();
                         throw new RuntimeException(e);
                     }
                 }
@@ -76,9 +80,14 @@
                     }
                 }
             } catch (IllegalAccessException | IllegalArgumentException e) {
+                e.printStackTrace();
                 throw new RuntimeException(e);
             }
         }
+    }
+    
+    public void fireModelChanged() {
+        firePropertiesChanged(Arrays.asList(getPropertyNames()));
     }
 
     /**

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	Mon Mar 30 17:54:19 2015
@@ -6,6 +6,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Properties;
+import java.util.Set;
 
 /**
  * This class provides a list of key, value pairs backed by a <code>Properties</code> object. The
@@ -193,6 +194,25 @@
      * Convert this object to a string by printing out its properties list.
      */
     public String toString() {
-        return properties.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	Mon Mar 30 17:54:19 2015
@@ -1,5 +1,7 @@
 package org.hps.monitoring.application.model;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.logging.Level;
 
 import org.hps.record.enums.DataSourceType;
@@ -28,6 +30,7 @@
     public static final String LOG_LEVEL_FILTER_PROPERTY = "LogLevelFilter";
     public static final String LOG_TO_FILE_PROPERTY = "LogToFile";
     public static final String MAX_EVENTS_PROPERTY = "MaxEvents";
+    public static final String RECENT_FILES_PROPERTY = "RecentFiles";
     public static final String STEERING_TYPE_PROPERTY = "SteeringType";
     public static final String STEERING_FILE_PROPERTY = "SteeringFile";
     public static final String STEERING_RESOURCE_PROPERTY = "SteeringResource";
@@ -79,7 +82,7 @@
         return Level.parse(configuration.get(LOG_LEVEL_PROPERTY));
     }
 
-    public void setLogLevel(Level level) {
+    public void setLogLevel(Level level) { 
         Level oldValue = getLogLevel();
         configuration.set(LOG_LEVEL_PROPERTY, level.getName());
         firePropertyChange(LOG_LEVEL_PROPERTY, oldValue, getLogLevel());
@@ -199,7 +202,11 @@
     }
 
     public DataSourceType getDataSourceType() {
-        return DataSourceType.valueOf(configuration.get(DATA_SOURCE_TYPE_PROPERTY));
+        if (configuration.checkKey(DATA_SOURCE_TYPE_PROPERTY)) {
+            return DataSourceType.valueOf(configuration.get(DATA_SOURCE_TYPE_PROPERTY));
+        } else {
+            return null;
+        }
     }
 
     public void setDataSourceType(DataSourceType dataSourceType) {
@@ -217,6 +224,14 @@
         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);
+    }
+    */
 
     public ProcessingStage getProcessingStage() {
         if (configuration.get(PROCESSING_STAGE_PROPERTY) == null)
@@ -408,6 +423,52 @@
     
     public String getAIDAServerName() {
         return configuration.get(AIDA_SERVER_NAME_PROPERTY);
+    }
+    
+    public String getRecentFiles() {
+        if (configuration.hasKey(RECENT_FILES_PROPERTY)) {
+            return configuration.get(RECENT_FILES_PROPERTY);
+        } else {
+            return null;
+        }         
+    }
+    
+    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")) {
+                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);
+            }
+        }
+        
+    }
+    
+    public void setRecentFiles(String recentFiles) {
+        String oldValue = null;
+        if (configuration.checkKey(RECENT_FILES_PROPERTY)) {
+            oldValue = configuration.get(RECENT_FILES_PROPERTY);
+        }
+        configuration.set(RECENT_FILES_PROPERTY, recentFiles);
+        firePropertyChange(RECENT_FILES_PROPERTY, oldValue, configuration.get(RECENT_FILES_PROPERTY));
     }
 
     public void remove(String property) {
@@ -432,4 +493,13 @@
     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());
+    }
 }