Print

Print


Commit in java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui on MAIN
PlotInfoWindow.java+168-351152 -> 1153
Updates from jfreechart-aida and add support for additional AIDA types

java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui
PlotInfoWindow.java 1152 -> 1153
--- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/PlotInfoWindow.java	2014-10-07 23:32:01 UTC (rev 1152)
+++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui/PlotInfoWindow.java	2014-10-07 23:32:57 UTC (rev 1153)
@@ -2,9 +2,12 @@
 
 import hep.aida.IAxis;
 import hep.aida.IBaseHistogram;
+import hep.aida.ICloud1D;
+import hep.aida.ICloud2D;
 import hep.aida.IDataPointSet;
 import hep.aida.IFunction;
 import hep.aida.IHistogram1D;
+import hep.aida.IHistogram2D;
 import hep.aida.jfree.plotter.ObjectStyle;
 import hep.aida.jfree.plotter.PlotterRegion;
 import hep.aida.ref.event.AIDAListener;
@@ -18,9 +21,11 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.EventObject;
+import java.util.List;
 import java.util.Timer;
 import java.util.TimerTask;
 
+import javax.swing.BorderFactory;
 import javax.swing.JComboBox;
 import javax.swing.JFrame;
 import javax.swing.JList;
@@ -32,12 +37,14 @@
 
 /**
  * <p>
- * Window for showing the statistics and other information about a plot.
+ * This is a GUI component for showing the statistics and other information about an AIDA plot.
  * <p>
- * This information will be dynamically updating using the <code>AIDAObserver</code> API
- * on the AIDA object.
+ * This information is updated dynamically via the <code>AIDAObserver</code> API on the AIDA object.
  */ 
-// FIXME: Add addRows for all types of AIDA objects (only Histogram1D implemented so far).
+// FIXME: Add addRows for all types of AIDA objects (only Histogram1D implemented so far). 
+// FIXME: Columns disappear when rebuilding table.
+// TODO: Add sorting of info table.
+// TODO: Probably this should be moved out of monitoring application as it is generically applicable to AIDA objects.
 public class PlotInfoWindow extends JFrame implements AIDAListener, ActionListener {
 
     JComboBox<Object> plotComboBox;
@@ -46,16 +53,23 @@
     JPanel contentPane = new JPanel();
     PlotterRegion currentRegion;
     Object currentObject;
-    static int INSET_SIZE = 5;
+    static final int INSET_SIZE = 5;
+    static final int BORDER_SIZE = 10;
 
     static final String[] COLUMN_NAMES = { "Field", "Value" };
 
     static final String PLOT_SELECTED = "PLOT_SELECTED";
+    
+    Timer timer = new Timer();
            
+    /**
+     * Class constructor, which will setup the GUI components.
+     */
     @SuppressWarnings("unchecked")
     PlotInfoWindow() {
         
         contentPane.setLayout(new GridBagLayout());
+        contentPane.setBorder(BorderFactory.createEmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
         
         GridBagConstraints c;
         
@@ -75,62 +89,72 @@
                 return this;
             }
         });        
+        plotComboBox.addActionListener(this);
         c = new GridBagConstraints();
         c.gridx = 0;
         c.gridy = 0;
         c.fill = GridBagConstraints.HORIZONTAL;
-        c.insets = new Insets(INSET_SIZE, INSET_SIZE, INSET_SIZE, INSET_SIZE); 
+        c.insets = new Insets(0, 0, INSET_SIZE, 0);
         contentPane.add(plotComboBox, c);
 
         String data[][] = new String[0][0];
         model = new DefaultTableModel(data, COLUMN_NAMES);
         infoTable.setModel(model);
-        infoTable.getColumn("Field").setMinWidth(20);
+        
+        // FIXME: Are these adequate column size settings?  Could prob be bigger...
+        infoTable.getColumn("Field").setMinWidth(25);
         infoTable.getColumn("Value").setMinWidth(20);
+        
         c = new GridBagConstraints();
         c.gridx = 0;
         c.gridy = 1;
         c.fill = GridBagConstraints.BOTH;
-        c.insets = new Insets(0, 0, INSET_SIZE, 0);
         contentPane.add(infoTable, c);
         
         setContentPane(contentPane);        
         setAlwaysOnTop(true);
-        //this.setResizable(false);
+        setResizable(false);
         this.pack();
     }
     
     /**
-     * This method will be called when the backing AIDA object is updated,
-     * so the information in the table should be changed to reflect its new state.
+     * This method will be called when the backing AIDA object is updated and a 
+     * state change is fired via the <code>AIDAObservable</code> API.  The table
+     * is updated to reflect the new state of the object.
      * @param evt The EventObject pointing to the backing AIDA object.
      */
     @Override
-    public void stateChanged(final EventObject evt) {        
+    public void stateChanged(final EventObject evt) {
+        
+        // Make a timer task for running the update.
         TimerTask task = new TimerTask() {
             public void run() {
-                // Is this object connected to the correct AIDA observable?
+                // Is the state change from the current AIDAObservable?
                 if (evt.getSource() != PlotInfoWindow.this.currentObject) {
-                    // This should not ever happen but throw an error here just in case.
-                    throw new RuntimeException("The AIDAObservable is not attached to the right object!");
+                    // Assume this means that a different AIDAObservable was selected in the GUI.
+                    return;
                 }
                 
-                // Run the method to update the table with new plot information on the EDT.
+                // Update the table values on the Swing EDT.
                 runUpdateTable();
                 
-                // Set the observable to valid so we receive subsequent state changes.
+                // Set the observable to valid so subsequent state changes are received.
                 ((AIDAObservable) currentObject).setValid((AIDAListener) PlotInfoWindow.this);
             }
-        };
+        };        
         
         /* 
-         * Schedule the task to run in ~0.5 seconds.  If this is run immediately, somehow the
-         * observable state gets permanently set to invalid and we we will stop receiving any
-         * state changes! 
+         * Schedule the task to run in ~0.5 seconds.  If the Runnable runs immediately, somehow the
+         * observable state gets permanently set to invalid and additional state changes will not
+         * be received! 
          */
-        new Timer().schedule(task, 500);
+        timer.schedule(task, 500);
     }
 
+    /**
+     * Implementation of <code>actionPerformed</code> to handle the selection of
+     * a new object from the combo box. 
+     */
     @Override
     public void actionPerformed(ActionEvent e) {
         // Was a new item selected in the combo box?
@@ -142,6 +166,13 @@
         }
     }        
     
+    /**
+     * Get the title of an AIDA object.  Unfortunately there is 
+     * not base type with this information.
+     * @param object The AIDA object.
+     * @return The title of the object from its title method 
+     *          or value of its toString method, if none exists.
+     */
     String getObjectTitle(Object object) {
         if (object instanceof IBaseHistogram) {
             return ((IBaseHistogram)object).title();
@@ -154,7 +185,11 @@
         }
     }
 
-    void setCurrentRegion(PlotterRegion region) {        
+    /**
+     * Set the current plotter region, which will rebuild the GUI accordingly.
+     * @param region The current plotter region.
+     */
+    synchronized void setCurrentRegion(PlotterRegion region) {        
         if (region != currentRegion) {            
             currentRegion = region;
             if (currentRegion.title() != null)
@@ -165,15 +200,14 @@
         }
     }
 
-    void setupContentPane() {           
-        
+    /**
+     * Configure the frame's content panel from current component settings.
+     */
+    void setupContentPane() {                   
         plotComboBox.setSize(plotComboBox.getPreferredSize());
         infoTable.setSize(infoTable.getPreferredSize());
-        int width = plotComboBox.getPreferredSize().width + INSET_SIZE * 2;
-        int height = plotComboBox.getPreferredSize().height + infoTable.getPreferredSize().height + INSET_SIZE * 3;
-        //System.out.println("contentPane");
-        //System.out.println("  w: " + width);
-        //System.out.println("  h: " + height);
+        int width = plotComboBox.getPreferredSize().width;
+        int height = plotComboBox.getPreferredSize().height + INSET_SIZE + infoTable.getPreferredSize().height;
         contentPane.setPreferredSize(
                 new Dimension(
                         width,
@@ -185,14 +219,28 @@
         setVisible(true);      
     }
         
+    /**
+     * Update the info table from the state of the current AIDA object.
+     */
     void updateTable() {
         model.setRowCount(0);
         model.setColumnIdentifiers(COLUMN_NAMES);                
         if (currentObject instanceof IHistogram1D) {            
             addRows((IHistogram1D)currentObject);
+        } else if (currentObject instanceof IHistogram2D) {
+            addRows((IHistogram2D)currentObject);
+        } else if (currentObject instanceof ICloud2D) {
+            addRows((ICloud2D)currentObject);
+        } else if (currentObject instanceof ICloud1D) {
+            if (((ICloud1D)currentObject).isConverted()) {
+                addRows(((ICloud1D)currentObject).histogram());
+            }
         }
     }
     
+    /**
+     * Run the {@link #updateTable()} method on the Swing EDT.
+     */
     void runUpdateTable() {
         SwingUtilities.invokeLater(new Runnable() { 
             public void run() {
@@ -201,16 +249,33 @@
         });
     }
     
+    /**
+     * Update the combo box contents with the plots from the current region.
+     */
     void updateComboBox() {
         plotComboBox.removeAllItems();
-        for (ObjectStyle objectStyle : currentRegion.getObjectStyles()) {
-            Object object = objectStyle.object();
-            if (object instanceof IBaseHistogram) {
+        List<Object> objects = currentRegion.getPlottedObjects();        
+        for (Object object : objects) {
+            if (isValidObject(object)) {
                 this.plotComboBox.addItem(object);
             }
         }        
     }
+    
+    boolean isValidObject(Object object) {
+        if (object == null)
+            return false;
+        if (object instanceof IBaseHistogram || object instanceof IFunction || object instanceof IDataPointSet) {
+            return true;
+        } else {
+            return false;
+        }
+    }
 
+    /**
+     * Add rows to the info table from the state of a 1D histogram.
+     * @param histogram The AIDA object.
+     */
     void addRows(IHistogram1D histogram) {
         addRow("title", histogram.title());
         addRow("bins", histogram.axis().bins());
@@ -222,30 +287,98 @@
         addRow("overflow entries", histogram.binEntries(IAxis.OVERFLOW_BIN));
         addRow("underflow entries", histogram.binEntries(IAxis.UNDERFLOW_BIN));
     }
+    
+    /**
+     * Add rows to the info table from the state of a 2D histogram.
+     * @param histogram The AIDA object.
+     */
+    void addRows(IHistogram2D histogram) {
+        addRow("title", histogram.title());
+        addRow("x bins", histogram.xAxis().bins());
+        addRow("y bins", histogram.yAxis().bins());
+        addRow("entries", histogram.entries());
+        addRow("x mean", String.format("%.10f%n", histogram.meanX()));
+        addRow("y mean", String.format("%.10f%n", histogram.meanY()));
+        addRow("x rms", String.format("%.10f%n", histogram.rmsX()));
+        addRow("y rms", String.format("%.10f%n", histogram.rmsY()));
+        addRow("sum bin heights", histogram.sumBinHeights());
+        addRow("max bin height", histogram.maxBinHeight());
+        addRow("x overflow entries", histogram.binEntriesX(IAxis.OVERFLOW_BIN));
+        addRow("y overflow entries", histogram.binEntriesY(IAxis.OVERFLOW_BIN));
+        addRow("x underflow entries", histogram.binEntriesX(IAxis.UNDERFLOW_BIN));
+        addRow("y underflow entries", histogram.binEntriesY(IAxis.UNDERFLOW_BIN));
+    }
+    
+    /**
+     * Add rows to the info table from the state of a 2D cloud.
+     * @param cloud The AIDA object.
+     */
+    void addRows(ICloud2D cloud) {        
+        addRow("title", cloud.title());
+        addRow("entries", cloud.entries());
+        addRow("max entries", cloud.maxEntries());
+        addRow("x lower edge", cloud.lowerEdgeX());
+        addRow("x upper edge", cloud.upperEdgeX());
+        addRow("y lower edge", cloud.lowerEdgeY());        
+        addRow("y upper edge", cloud.upperEdgeY());
+        addRow("x mean", String.format("%.10f%n", cloud.meanX()));
+        addRow("y mean", String.format("%.10f%n", cloud.meanY()));
+        addRow("x rms", String.format("%.10f%n", cloud.rmsX()));
+        addRow("y rms", String.format("%.10f%n", cloud.rmsY()));
+    }
 
+    /**
+     * Add a row to the info table.
+     * @param field The field name.
+     * @param value The field value.
+     */
     void addRow(String field, Object value) {
         model.insertRow(infoTable.getRowCount(), new Object[] { field, value });
     }
     
-    void setCurrentObject(Object object) { 
+    /**
+     * Set the current AIDA object that backs this GUI, i.e. an IHistogram1D etc.
+     * @param object The backing AIDA object.
+     */
+    synchronized void setCurrentObject(Object object) {
+                        
         if (object == null)
             throw new IllegalArgumentException("The object arg is null!");       
+
         if (object == currentObject)
-            return;        
+            return;
+       
+        // Remove the AIDAListener from the previous object.
         removeListener();
+                              
+        // Set the current object reference.
         currentObject = object;        
+        
+        // Update the table immediately with information from the current object.
+        // We need to wait for this the first time, so we know the preferred size 
+        // of the table GUI component when resizing the content pane.
         updateTable();
+        
+        // Add an AIDAListener to the AIDA object via the AIDAObservable API.
         addListener();
     }
     
+    /**
+     * Remove this object as an <code>AIDAListener</code> on the current <code>AIDAObservable</code>.
+     */
     void removeListener() {
         if (currentObject != null) {
+            // Remove this object as a listener on the current observable.
             ((AIDAObservable)currentObject).removeListener(this);
         }
     }
     
+    /**
+     * Add this object as an <code>AIDAListener</code> on the current <code>AIDAObservable</code>.
+     */
     void addListener() {        
         if (currentObject instanceof AIDAObservable) {
+            // Setup a listener on the current AIDA object.
             AIDAObservable observable = (AIDAObservable)currentObject;
             observable.addListener(this);
             observable.setValid(this);
SVNspam 0.1