java/trunk/monitoring-app/src/main/java/org/hps/monitoring/gui
--- 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);