Author: mccaky Date: Sat Nov 1 02:29:56 2014 New Revision: 1384 Log: Added updated event display GUI and ability to display ecal hardware settings on status panel. Added: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/DataFileViewer.java (with props) java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/PDataEventViewer.java (with props) java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/ResizableFieldPanel.java (with props) java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/util/CrystalDataSet.java (with props) java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/util/EcalWiringManager.java (with props) Modified: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/ActiveViewer.java java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/ClusterViewer.java java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/FileViewer.java java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/OccupancyViewer.java java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/PEventViewer.java java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/POccupancyViewer.java java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/PassiveViewer.java java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/StatusPanel.java java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/Viewer.java Modified: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/ActiveViewer.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/ActiveViewer.java (original) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/ActiveViewer.java Sat Nov 1 02:29:56 2014 @@ -19,50 +19,43 @@ * @author Kyle McCarty */ public abstract class ActiveViewer extends Viewer { - private static final long serialVersionUID = -6107646224627009923L; - // Stores whether the background color is set or not. - private boolean background = false; - // Gets events from some file. - protected final EventManager em; - - /** - * Creates an active-type <code>Viewer</code> window which draws - * events from the indicated data source. - * @param em - The data source event manager. - */ - public ActiveViewer(EventManager em) { this(em, new String[0]); } - - /** + private static final long serialVersionUID = -6107646224627009923L; + // Stores whether the background color is set or not. + private boolean background = false; + // Gets events from some file. + protected final EventManager em; + + /** * Creates an active-type <code>Viewer</code> window which draws * events from the indicated data source with additional status * fields defined by the <code>fieldNames</code> argument. - * @param em - The data source event manager. - * @param fieldNames - An array of additional status fields - * that should be displayed. - */ - public ActiveViewer(EventManager em, String... fieldNames) { - // Pass any additional field values to the super class. - super(fieldNames); - - // Set the data source. - this.em = em; - + * @param em - The data source event manager. + * @param fieldNames - An array of additional status fields + * that should be displayed. + */ + public ActiveViewer(EventManager em) { + // Pass any additional field values to the super class. + super(); + + // Set the data source. + this.em = em; + // Make a key listener to change events. addKeyListener(new EcalKeyListener()); - } - + } + /** * Feeds the calorimeter panel the data from the next event. * @throws IOException Occurs when there is an issue with reading the data file. **/ - public abstract void displayNextEvent() throws IOException; - + public abstract void displayNextEvent() throws IOException; + /** * Feeds the calorimeter panel the data from the previous event. * @throws IOException Occurs when there is an issue with reading the data file. **/ - public abstract void displayPreviousEvent() throws IOException; - + public abstract void displayPreviousEvent() throws IOException; + /** * The <code>EcalListener</code> class binds keys to actions. * Bound actions include: @@ -71,7 +64,7 @@ * b :: Toggle color-mapping for 0 energy crystals * h :: Toggle selected crystal highlighting * l :: Toggle logarithmic versus linear scaling - * s :: Saves the current display to a file + * s :: Saves the current display to a file **/ private class EcalKeyListener implements KeyListener { public void keyPressed(KeyEvent e) { } @@ -97,9 +90,9 @@ // 'b' toggles the default white background. else if(e.getKeyCode() == 66) { - if(background) { ecalPanel.setDefaultCrystalColor(null); } - else { ecalPanel.setDefaultCrystalColor(Color.GRAY); } - background = !background; + if(background) { ecalPanel.setDefaultCrystalColor(null); } + else { ecalPanel.setDefaultCrystalColor(Color.GRAY); } + background = !background; } // 'h' toggles highlighting the crystal under the cursor. @@ -107,45 +100,45 @@ // 'l' toggles linear or logarithmic scaling. else if(e.getKeyCode() == 76) { - if(ecalPanel.isScalingLinear()) { ecalPanel.setScalingLogarithmic(); } - else { ecalPanel.setScalingLinear(); } + if(ecalPanel.isScalingLinear()) { ecalPanel.setScalingLogarithmic(); } + else { ecalPanel.setScalingLinear(); } } // 'x' toggles x-axis mirroring. else if(e.getKeyCode() == 88) { - ecalPanel.setMirrorX(!ecalPanel.isMirroredX()); - updateStatusPanel(); + ecalPanel.setMirrorX(!ecalPanel.isMirroredX()); + updateStatusPanel(); } // 'y' toggles y-axis mirroring. else if(e.getKeyCode() == 89) { - ecalPanel.setMirrorY(!ecalPanel.isMirroredY()); - updateStatusPanel(); + ecalPanel.setMirrorY(!ecalPanel.isMirroredY()); + updateStatusPanel(); } // 's' saves the panel to a file. else if(e.getKeyCode() == 83) { - // Make a new buffered image on which to draw the content pane. - BufferedImage screenshot = new BufferedImage(getContentPane().getWidth(), - getContentPane().getHeight(), BufferedImage.TYPE_INT_ARGB); - - // Paint the content pane to image. - getContentPane().paint(screenshot.getGraphics()); - - // Get the lowest available file name. - int fileNum = 0; - File imageFile = new File("screenshot_" + fileNum + ".png"); - while(imageFile.exists()) { - fileNum++; - imageFile = new File("screenshot_" + fileNum + ".png"); - } - - // Save the image to a PNG file. - try { ImageIO.write(screenshot, "PNG", imageFile); } - catch(IOException ioe) { - System.err.println("Error saving file \"screenshot.png\"."); - } - System.out.println("Screenshot saved to: " + imageFile.getAbsolutePath()); + // Make a new buffered image on which to draw the content pane. + BufferedImage screenshot = new BufferedImage(getContentPane().getWidth(), + getContentPane().getHeight(), BufferedImage.TYPE_INT_ARGB); + + // Paint the content pane to image. + getContentPane().paint(screenshot.getGraphics()); + + // Get the lowest available file name. + int fileNum = 0; + File imageFile = new File("screenshot_" + fileNum + ".png"); + while(imageFile.exists()) { + fileNum++; + imageFile = new File("screenshot_" + fileNum + ".png"); + } + + // Save the image to a PNG file. + try { ImageIO.write(screenshot, "PNG", imageFile); } + catch(IOException ioe) { + System.err.println("Error saving file \"screenshot.png\"."); + } + System.out.println("Screenshot saved to: " + imageFile.getAbsolutePath()); } // Otherwise, print out the key code for the pressed key. Modified: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/ClusterViewer.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/ClusterViewer.java (original) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/ClusterViewer.java Sat Nov 1 02:29:56 2014 @@ -31,10 +31,11 @@ * * @author Kyle McCarty */ +@Deprecated public class ClusterViewer extends ActiveViewer { - private static final long serialVersionUID = 17058336873349781L; - // Stores whether the background color is set or not. - private boolean background = false; + private static final long serialVersionUID = 17058336873349781L; + // Stores whether the background color is set or not. + private boolean background = false; // Store the index in the buffer of the displayed event. private int bufferIndex; // Map cluster location to a cluster object. @@ -50,197 +51,205 @@ // Additional status display field names for this data type. private static final String[] fieldNames = { "Shared Hits", "Component Hits", "Cluster Energy", "Buffer Index" }; - /** - * <b>ClusterViewer</b><br/><br/> + /** + * <b>ClusterViewer</b><br/><br/> * <code>public <b>ClusterViewer</b>()</code><br/><br/> * Constructs a new <code>Viewer</code> for displaying data read * from a file. - * @param dataSource - The <code>EventManager</code> responsible - * for reading data from a file. - * @throws NullPointerException Occurs if the event manager is - * <code>null</code>. - */ - public ClusterViewer(EventManager dataSource, int eventWindow) throws NullPointerException { - // Pass any additional fields required by the event manager - // to the underlying Viewer object to be added to the status - // display panel. - super(dataSource, fieldNames); - - // Define the event window and initialize the event data. - this.eventWindow = eventWindow; - eventEnergyBuffer = new LinkedList<Double[][]>(); - eventHitBuffer = new LinkedList<List<EcalHit>>(); - - // Prepare the event buffer to display the first event. - try { - // Make an empty array. At the start, there are no previous - // events to load. - Double[][] emptyArray = new Double[46][11]; - for(int x = 0; x < 46; x++) { - for(int y = 0; y < 11; y++) { emptyArray[x][y] = new Double(0.0); } - } - - // Populate the eventWindow before section of the buffer - // with the empty events. - for(int i = 0; i <= eventWindow; i++) { - eventEnergyBuffer.addFirst(emptyArray); - eventHitBuffer.addFirst(new ArrayList<EcalHit>()); - } - - // Fill the rest of the array with future events. - for(int i = 0; i < eventWindow; i++) { - em.nextEvent(); - eventEnergyBuffer.addFirst(toEnergyArray(em.getHits())); - eventHitBuffer.addFirst(em.getHits()); - } - } - catch(java.io.IOException e) { System.exit(1); } - + * @param dataSource - The <code>EventManager</code> responsible + * for reading data from a file. + * @throws NullPointerException Occurs if the event manager is + * <code>null</code>. + */ + public ClusterViewer(EventManager dataSource, int eventWindow) throws NullPointerException { + // Initialize the superclass. + super(dataSource); + + // Add the additional fields. + for(String field : fieldNames) { + addStatusField(field); + } + + // Define the event window and initialize the event data. + this.eventWindow = eventWindow; + eventEnergyBuffer = new LinkedList<Double[][]>(); + eventHitBuffer = new LinkedList<List<EcalHit>>(); + + // Prepare the event buffer to display the first event. + try { + // Make an empty array. At the start, there are no previous + // events to load. + Double[][] emptyArray = new Double[46][11]; + for(int x = 0; x < 46; x++) { + for(int y = 0; y < 11; y++) { emptyArray[x][y] = new Double(0.0); } + } + + // Populate the eventWindow before section of the buffer + // with the empty events. + for(int i = 0; i <= eventWindow; i++) { + eventEnergyBuffer.addFirst(emptyArray); + eventHitBuffer.addFirst(new ArrayList<EcalHit>()); + } + + // Fill the rest of the array with future events. + for(int i = 0; i < eventWindow; i++) { + em.nextEvent(); + eventEnergyBuffer.addFirst(toEnergyArray(em.getHits())); + eventHitBuffer.addFirst(em.getHits()); + } + } + catch(java.io.IOException e) { System.exit(1); } + // Make a key listener to change events. addKeyListener(new EcalKeyListener()); - } - - /** - * <b>displayNextEvent</b><br/><br/> - * <code>public void <b>displayNextEvent</b>()</code><br/><br/> + } + + /** * Feeds the calorimeter panel the data from the next event. * @throws IOException Occurs when there is an issue with reading the data file. **/ + @Override public void displayNextEvent() throws IOException { getEvent(true); } /** - * <b>displayPreviousEvent</b><br/><br/> - * <code>public void <b>displayPreviousEvent</b>()</code><br/><br/> * Feeds the calorimeter panel the data from the previous event. * @throws IOException Occurs when there is an issue with reading the data file. **/ + @Override public void displayPreviousEvent() throws IOException { getEvent(false); } - - public List<Cluster> getClusters() { - // Get the set of hits in the middle of the buffer. This is - // the "current" event. - List<EcalHit> activeEvent = eventHitBuffer.get(eventWindow); - - // Store clusters. - ArrayList<Cluster> clusterList = new ArrayList<Cluster>(); - - // For each hit, check if it meets the criteria for a cluster. - for(EcalHit hit : activeEvent) { - // Track whether this hit is a cluster. - boolean isCluster = true; - - // Track the current hit's cluster energy. - double clusterEnergy = 0.0; - - // Convert the current hit to the proper coordinates. - Point hitLoc = toPanelPoint(hit.getLocation()); - - // Track which crystals are part of the cluster. - HashSet<Point> componentSet = new HashSet<Point>(); - - // Get the set of the current hit's neighbors. - Set<Point> neighbors = ecalPanel.getNeighbors(hitLoc); - - // Loop through the buffer and perform comparisons. - for(Double[][] event : eventEnergyBuffer) { - // Increment the cluster energy by the hit's energy at - // the current time in the buffer. - clusterEnergy += event[hitLoc.x][hitLoc.y]; - - // A hit must be larger than itself at all other times - // stored in the buffer. - if(event[hitLoc.x][hitLoc.y] > hit.getEnergy()) { - isCluster = false; - break; - } - - // A hit must be larger than its immediate neighbors - // at all times in the buffer as well. - for(Point neighbor : neighbors) { - // Increment the cluster energy by the neighbor's - // energy at the current time in the buffer. - clusterEnergy += event[neighbor.x][neighbor.y]; - - // Check that the neighbor's energy is not higher - // than the present hit's. - if(event[neighbor.x][neighbor.y] > hit.getEnergy()) { - isCluster = false; - break; - } - - // If this neighbor has a non-zero energy, it is - // a component of the potential cluster. - if(event[neighbor.x][neighbor.y] != 0) { componentSet.add(neighbor); } - } - } - - // If the current hit did not fail any of the preceding - // checks, then it is a cluster and should be added to - // the cluster list. - if(isCluster) { - Cluster cluster = new Cluster(hit.getLocation(), clusterEnergy); - for(Point neighbor : componentSet) { cluster.addComponentHit(toEcalPoint(neighbor)); } - clusterList.add(cluster); - } - } - - // Return the list of clusters. - return clusterList; - } - + + /** + * Generates a list of clusters from the list of hits in the event. + * This was used as a debugging method for the current clustering + * algorithm. + * @return Returns a generated list of clusters. + */ + public List<Cluster> getClusters() { + // Get the set of hits in the middle of the buffer. This is + // the "current" event. + List<EcalHit> activeEvent = eventHitBuffer.get(eventWindow); + + // Store clusters. + ArrayList<Cluster> clusterList = new ArrayList<Cluster>(); + + // For each hit, check if it meets the criteria for a cluster. + for(EcalHit hit : activeEvent) { + // Track whether this hit is a cluster. + boolean isCluster = true; + + // Track the current hit's cluster energy. + double clusterEnergy = 0.0; + + // Convert the current hit to the proper coordinates. + Point hitLoc = toPanelPoint(hit.getLocation()); + + // Track which crystals are part of the cluster. + HashSet<Point> componentSet = new HashSet<Point>(); + + // Get the set of the current hit's neighbors. + Set<Point> neighbors = ecalPanel.getNeighbors(hitLoc); + + // Loop through the buffer and perform comparisons. + for(Double[][] event : eventEnergyBuffer) { + // Increment the cluster energy by the hit's energy at + // the current time in the buffer. + clusterEnergy += event[hitLoc.x][hitLoc.y]; + + // A hit must be larger than itself at all other times + // stored in the buffer. + if(event[hitLoc.x][hitLoc.y] > hit.getEnergy()) { + isCluster = false; + break; + } + + // A hit must be larger than its immediate neighbors + // at all times in the buffer as well. + for(Point neighbor : neighbors) { + // Increment the cluster energy by the neighbor's + // energy at the current time in the buffer. + clusterEnergy += event[neighbor.x][neighbor.y]; + + // Check that the neighbor's energy is not higher + // than the present hit's. + if(event[neighbor.x][neighbor.y] > hit.getEnergy()) { + isCluster = false; + break; + } + + // If this neighbor has a non-zero energy, it is + // a component of the potential cluster. + if(event[neighbor.x][neighbor.y] != 0) { componentSet.add(neighbor); } + } + } + + // If the current hit did not fail any of the preceding + // checks, then it is a cluster and should be added to + // the cluster list. + if(isCluster) { + Cluster cluster = new Cluster(hit.getLocation(), clusterEnergy); + for(Point neighbor : componentSet) { cluster.addComponentHit(toEcalPoint(neighbor)); } + clusterList.add(cluster); + } + } + + // Return the list of clusters. + return clusterList; + } + + @Override protected void updateStatusPanel() { - super.updateStatusPanel(); - - // Get the currently selected crystal. - Point crystal = ecalPanel.getSelectedCrystal(); - - // If the active crystal is not null, see if it is a cluster. - if(crystal != null) { - // Get the cluster associated with this point. - Cluster activeCluster = clusterMap.get(crystal); - - // If the cluster is null, we set everything to undefined. - if(activeCluster == null) { - for(String field : fieldNames) { setStatusField(field, StatusPanel.NULL_VALUE); } - } - - // Otherwise, define the fields based on the cluster. - else { - // Get the shared and component hit counts. - setStatusField(fieldNames[0], Integer.toString(activeCluster.getSharedHitCount())); - setStatusField(fieldNames[1], Integer.toString(activeCluster.getComponentHitCount())); - - // Format the cluster energy, or account for it if it - // doesn't exist. - String energy; - if(activeCluster.getClusterEnergy() != Double.NaN) { - DecimalFormat formatter = new DecimalFormat("0.####E0"); - energy = formatter.format(activeCluster.getClusterEnergy()); - } - else { energy = "---"; } - setStatusField(fieldNames[2], energy); - } - } - // Otherwise, clear the field values. - else { for(String field : fieldNames) { setStatusField(field, StatusPanel.NULL_VALUE); } } - - // Write the current buffer index. - - setStatusField(fieldNames[3], Integer.toString(eventWindow - bufferIndex)); - } - - /** - * <b>displayEvent</b><br/><br/> - * <code>private void <b>displayEvent</b></code><br/><br/> - * Displays the given lists of hits and clusters on the calorimeter - * panel. - * @param hitList - A list of hits for the current event. - * @param clusterList - A list of clusters for the current event. - */ - private void displayEvent(List<EcalHit> hitList, List<Cluster> clusterList) { - // Suppress the calorimeter panel. - ecalPanel.setSuppressRedraw(true); - + super.updateStatusPanel(); + + // Get the currently selected crystal. + Point crystal = ecalPanel.getSelectedCrystal(); + + // If the active crystal is not null, see if it is a cluster. + if(crystal != null) { + // Get the cluster associated with this point. + Cluster activeCluster = clusterMap.get(crystal); + + // If the cluster is null, we set everything to undefined. + if(activeCluster == null) { + for(String field : fieldNames) { setStatusField(field, StatusPanel.NULL_VALUE); } + } + + // Otherwise, define the fields based on the cluster. + else { + // Get the shared and component hit counts. + setStatusField(fieldNames[0], Integer.toString(activeCluster.getSharedHitCount())); + setStatusField(fieldNames[1], Integer.toString(activeCluster.getComponentHitCount())); + + // Format the cluster energy, or account for it if it + // doesn't exist. + String energy; + if(activeCluster.getClusterEnergy() != Double.NaN) { + DecimalFormat formatter = new DecimalFormat("0.####E0"); + energy = formatter.format(activeCluster.getClusterEnergy()); + } + else { energy = "---"; } + setStatusField(fieldNames[2], energy); + } + } + // Otherwise, clear the field values. + else { for(String field : fieldNames) { setStatusField(field, StatusPanel.NULL_VALUE); } } + + // Write the current buffer index. + + setStatusField(fieldNames[3], Integer.toString(eventWindow - bufferIndex)); + } + + /** + * <b>displayEvent</b><br/><br/> + * <code>private void <b>displayEvent</b></code><br/><br/> + * Displays the given lists of hits and clusters on the calorimeter + * panel. + * @param hitList - A list of hits for the current event. + * @param clusterList - A list of clusters for the current event. + */ + private void displayEvent(List<EcalHit> hitList, List<Cluster> clusterList) { + // Suppress the calorimeter panel. + ecalPanel.setSuppressRedraw(true); + // Display the hits. for (EcalHit h : hitList) { int ix = toPanelX(h.getX()); @@ -250,28 +259,28 @@ // Display the clusters. for(Cluster cluster : clusterList) { - Point rawCluster = cluster.getClusterCenter(); - Point clusterCenter = toPanelPoint(rawCluster); + Point rawCluster = cluster.getClusterCenter(); + Point clusterCenter = toPanelPoint(rawCluster); ecalPanel.setCrystalCluster(clusterCenter.x, clusterCenter.y, true); - // Add component hits to the calorimeter panel. - for(Point ch : cluster.getComponentHits()) { - ecalPanel.addAssociation(new Association(clusterCenter, toPanelPoint(ch), HIGHLIGHT_CLUSTER_COMPONENT)); - } - - // Add shared hits to the calorimeter panel. - for(Point sh : cluster.getSharedHits()) { - ecalPanel.addAssociation(new Association(clusterCenter, toPanelPoint(sh), HIGHLIGHT_CLUSTER_SHARED)); - } - } - - // Stop suppressing the panel and order it to redraw. - ecalPanel.setSuppressRedraw(false); - ecalPanel.repaint(); + // Add component hits to the calorimeter panel. + for(Point ch : cluster.getComponentHits()) { + ecalPanel.addAssociation(new Association(clusterCenter, toPanelPoint(ch), HIGHLIGHT_CLUSTER_COMPONENT)); + } + + // Add shared hits to the calorimeter panel. + for(Point sh : cluster.getSharedHits()) { + ecalPanel.addAssociation(new Association(clusterCenter, toPanelPoint(sh), HIGHLIGHT_CLUSTER_SHARED)); + } + } + + // Stop suppressing the panel and order it to redraw. + ecalPanel.setSuppressRedraw(false); + ecalPanel.repaint(); // Update the status panel to account for the new event. updateStatusPanel(); - } + } /** * <b>getEvent</b><br/><br/> @@ -294,16 +303,16 @@ // Remove the last buffer event and add the new one. if(forward) { - eventEnergyBuffer.removeLast(); - eventHitBuffer.removeLast(); - eventEnergyBuffer.addFirst(toEnergyArray(em.getHits())); - eventHitBuffer.addFirst(em.getHits()); + eventEnergyBuffer.removeLast(); + eventHitBuffer.removeLast(); + eventEnergyBuffer.addFirst(toEnergyArray(em.getHits())); + eventHitBuffer.addFirst(em.getHits()); } else { - eventEnergyBuffer.removeFirst(); - eventHitBuffer.removeFirst(); - eventEnergyBuffer.addLast(toEnergyArray(em.getHits())); - eventHitBuffer.addLast(em.getHits()); + eventEnergyBuffer.removeFirst(); + eventHitBuffer.removeFirst(); + eventEnergyBuffer.addLast(toEnergyArray(em.getHits())); + eventHitBuffer.addLast(em.getHits()); } // Determine if any of the hits in the active event are @@ -321,29 +330,36 @@ // Display it. displayEvent(eventHitBuffer.get(eventWindow), eventClusters); } - - private Double[][] toEnergyArray(List<EcalHit> hits) { - // Define the energy array. - Double[][] energy = new Double[46][11]; - for(int x = 0; x < energy.length; x++) { - for(int y = 0; y < energy[x].length; y++) { - energy[x][y] = new Double(0); - } - } - - // For each hit, place its energy in the array. - for(EcalHit hit : hits) { - // Get the converted crystal index. - Point panelLoc = toPanelPoint(hit.getLocation()); - - // Add the energy to the array. - energy[panelLoc.x][panelLoc.y] += hit.getEnergy(); - } - - // Return the resulting array. - return energy; - } - + + /** + * Gets the energy that should be stored in each crystal of the + * calorimeter. + * @param hits - The list of hits for the event. + * @return Returns the energy of each crystal as an array of <code> + * Double</code> objects. + */ + private Double[][] toEnergyArray(List<EcalHit> hits) { + // Define the energy array. + Double[][] energy = new Double[46][11]; + for(int x = 0; x < energy.length; x++) { + for(int y = 0; y < energy[x].length; y++) { + energy[x][y] = new Double(0); + } + } + + // For each hit, place its energy in the array. + for(EcalHit hit : hits) { + // Get the converted crystal index. + Point panelLoc = toPanelPoint(hit.getLocation()); + + // Add the energy to the array. + energy[panelLoc.x][panelLoc.y] += hit.getEnergy(); + } + + // Return the resulting array. + return energy; + } + /** * The <code>EcalListener</code> class binds keys to actions. * Bound actions include: @@ -352,11 +368,13 @@ * b :: Toggle color-mapping for 0 energy crystals * h :: Toggle selected crystal highlighting * l :: Toggle logarithmic versus linear scaling - * s :: Saves the current display to a file + * s :: Saves the current display to a file **/ private class EcalKeyListener implements KeyListener { + @Override public void keyPressed(KeyEvent e) { } + @Override public void keyReleased(KeyEvent e) { // If right-arrow was pressed, go to the next event. if (e.getKeyCode() == 39) { @@ -379,30 +397,30 @@ // If the down-arrow was pressed, move down a time step in // the buffer and display it. else if(e.getKeyCode() == 40) { - if(bufferIndex == eventHitBuffer.size() - 1) { return; } - else { - bufferIndex++; - ecalPanel.clearCrystals(); - displayEvent(eventHitBuffer.get(bufferIndex), eventClusters); - } + if(bufferIndex == eventHitBuffer.size() - 1) { return; } + else { + bufferIndex++; + ecalPanel.clearCrystals(); + displayEvent(eventHitBuffer.get(bufferIndex), eventClusters); + } } // If the up-arrow was pressed, move up a time step in // the buffer and display it. else if(e.getKeyCode() == 38) { - if(bufferIndex == 0) { return; } - else { - bufferIndex--; - ecalPanel.clearCrystals(); - displayEvent(eventHitBuffer.get(bufferIndex), eventClusters); - } + if(bufferIndex == 0) { return; } + else { + bufferIndex--; + ecalPanel.clearCrystals(); + displayEvent(eventHitBuffer.get(bufferIndex), eventClusters); + } } // 'b' toggles the default white background. else if(e.getKeyCode() == 66) { - if(background) { ecalPanel.setDefaultCrystalColor(null); } - else { ecalPanel.setDefaultCrystalColor(Color.GRAY); } - background = !background; + if(background) { ecalPanel.setDefaultCrystalColor(null); } + else { ecalPanel.setDefaultCrystalColor(Color.GRAY); } + background = !background; } // 'h' toggles highlighting the crystal under the cursor. @@ -410,39 +428,40 @@ // 'l' toggles linear or logarithmic scaling. else if(e.getKeyCode() == 76) { - if(ecalPanel.isScalingLinear()) { ecalPanel.setScalingLogarithmic(); } - else { ecalPanel.setScalingLinear(); } + if(ecalPanel.isScalingLinear()) { ecalPanel.setScalingLogarithmic(); } + else { ecalPanel.setScalingLinear(); } } // 's' saves the panel to a file. else if(e.getKeyCode() == 83) { - // Make a new buffered image on which to draw the content pane. - BufferedImage screenshot = new BufferedImage(getContentPane().getWidth(), - getContentPane().getHeight(), BufferedImage.TYPE_INT_ARGB); - - // Paint the content pane to image. - getContentPane().paint(screenshot.getGraphics()); - - // Get the lowest available file name. - int fileNum = 0; - File imageFile = new File("screenshot_" + fileNum + ".png"); - while(imageFile.exists()) { - fileNum++; - imageFile = new File("screenshot_" + fileNum + ".png"); - } - - // Save the image to a PNG file. - try { ImageIO.write(screenshot, "PNG", imageFile); } - catch(IOException ioe) { - System.err.println("Error saving file \"screenshot.png\"."); - } - System.out.println("Screenshot saved to: " + imageFile.getAbsolutePath()); + // Make a new buffered image on which to draw the content pane. + BufferedImage screenshot = new BufferedImage(getContentPane().getWidth(), + getContentPane().getHeight(), BufferedImage.TYPE_INT_ARGB); + + // Paint the content pane to image. + getContentPane().paint(screenshot.getGraphics()); + + // Get the lowest available file name. + int fileNum = 0; + File imageFile = new File("screenshot_" + fileNum + ".png"); + while(imageFile.exists()) { + fileNum++; + imageFile = new File("screenshot_" + fileNum + ".png"); + } + + // Save the image to a PNG file. + try { ImageIO.write(screenshot, "PNG", imageFile); } + catch(IOException ioe) { + System.err.println("Error saving file \"screenshot.png\"."); + } + System.out.println("Screenshot saved to: " + imageFile.getAbsolutePath()); } // Otherwise, print out the key code for the pressed key. else { System.out.printf("Key Code: %d%n", e.getKeyCode()); } } + @Override public void keyTyped(KeyEvent e) { } } } Added: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/DataFileViewer.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/DataFileViewer.java (added) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/DataFileViewer.java Sat Nov 1 02:29:56 2014 @@ -0,0 +1,99 @@ +package org.hps.monitoring.ecal.eventdisplay.ui; + +import java.awt.Point; +import java.io.IOException; + +import org.hps.monitoring.ecal.eventdisplay.io.EventManager; +import org.hps.monitoring.ecal.eventdisplay.util.CrystalDataSet; +import org.hps.monitoring.ecal.eventdisplay.util.EcalWiringManager; + +/** + * Class <code>DataFileViewer</code> is the active variant of a data + * viewer. It displays crystal hardware information read from a given + * data file and displays it along with crystal energy and index data. + * + * @author Kyle McCarty + */ +public class DataFileViewer extends FileViewer { + // Local variables. + private static final long serialVersionUID = 1L; + private final EcalWiringManager ewm; + + // Hardware display fields. + private static final String[] fieldNames = { + "APD Number", "Preamp Number", "LED Channel", "LED Driver", + "FADC Slot", "FADC Channel", "Splitter Number", "HV Group", + "Jout", "MB", "Channel", "Gain" + }; + + // Hardware display field indices. + private static final int FIELD_APD = 0; + private static final int FIELD_PREAMP = 1; + private static final int FIELD_LED_CHANNEL = 2; + private static final int FIELD_LED_DRIVER = 3; + private static final int FIELD_FADC_SLOT = 4; + private static final int FIELD_FADC_CHANNEL = 5; + private static final int FIELD_SPLITTER = 6; + private static final int FIELD_HV_GROUP = 7; + private static final int FIELD_JOUT = 8; + private static final int FIELD_MB = 9; + private static final int FIELD_CHANNEL = 10; + private static final int FIELD_GAIN = 11; + + /** + * Initializes a new <code>DataFileViewer</code> that reads from + * the given event manager for event data and the given hardware + * data file for crystal hardware data readout. + * @param dataSource - The manager for event data. + * @param crystalDataFilePath - The data file for crystal hardware + * information. + * @throws IOException Occurs if there is an error reading from + * either data source. + */ + public DataFileViewer(EventManager dataSource, String crystalDataFilePath) throws IOException { + // Initialize the super class file. + super(dataSource); + + // Load the crystal data mapping. + ewm = new EcalWiringManager(crystalDataFilePath); + + // Add the crystal data fields. + for(String fieldName : fieldNames) { + addStatusField(fieldName); + } + } + + @Override + protected void updateStatusPanel() { + // Run the superclass method. + super.updateStatusPanel(); + + // Get the selected crystal. + Point crystal = ecalPanel.getSelectedCrystal(); + + // If a crystal is selected, display its data set. + if(crystal != null) { + // Get the LCSim coordinate system version of the crystal. + Point lcsimCrystal = Viewer.toEcalPoint(crystal); + + // Get the hardware data set associated with the crystal. + CrystalDataSet cds = ewm.getCrystalData(lcsimCrystal); + + // If the data set exists, update the all the fields. + if(cds != null) { + setStatusField(fieldNames[FIELD_APD], "" + cds.getAPDNumber()); + setStatusField(fieldNames[FIELD_PREAMP], cds.getPreamplifierNumber().toString()); + setStatusField(fieldNames[FIELD_LED_CHANNEL], "" + cds.getLEDChannel()); + setStatusField(fieldNames[FIELD_LED_DRIVER], "" + cds.getLEDDriver()); + setStatusField(fieldNames[FIELD_FADC_SLOT], "" + cds.getFADCSlot()); + setStatusField(fieldNames[FIELD_FADC_CHANNEL], "" + cds.getFADCChannel()); + setStatusField(fieldNames[FIELD_SPLITTER], "" + cds.getSplitterNumber()); + setStatusField(fieldNames[FIELD_HV_GROUP], "" + cds.getHighVoltageGroup()); + setStatusField(fieldNames[FIELD_JOUT], "" + cds.getJout()); + setStatusField(fieldNames[FIELD_MB], "" + cds.getMB()); + setStatusField(fieldNames[FIELD_CHANNEL], "" + cds.getChannel()); + setStatusField(fieldNames[FIELD_GAIN], "" + cds.getGain()); + } + } + } +} Modified: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/FileViewer.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/FileViewer.java (original) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/FileViewer.java Sat Nov 1 02:29:56 2014 @@ -21,7 +21,7 @@ * @author Kyle McCarty */ public class FileViewer extends ActiveViewer { - private static final long serialVersionUID = 17058336873349781L; + private static final long serialVersionUID = 17058336873349781L; // Map cluster location to a cluster object. private HashMap<Point, Cluster> clusterMap = new HashMap<Point, Cluster>(); // Additional status display field names for this data type. @@ -32,80 +32,87 @@ private static final int COMPONENT_HITS = 2; private static final int CLUSTER_ENERGY = 3; - /** - * <b>FileViewer</b><br/><br/> + /** + * <b>FileViewer</b><br/><br/> * <code>public <b>FileViewer</b>()</code><br/><br/> * Constructs a new <code>Viewer</code> for displaying data read * from a file. - * @param dataSource - The <code>EventManager</code> responsible - * for reading data from a file. - * @throws NullPointerException Occurs if the event manager is - * <code>null</code>. - */ - public FileViewer(EventManager dataSource) throws NullPointerException { - // Pass any additional fields required by the event manager - // to the underlying Viewer object to be added to the status - // display panel. - super(dataSource, fieldNames); - } + * @param dataSource - The <code>EventManager</code> responsible + * for reading data from a file. + * @throws NullPointerException Occurs if the event manager is + * <code>null</code>. + */ + public FileViewer(EventManager dataSource) throws NullPointerException { + // Initialize the superclass viewer. + super(dataSource); + + // Add additional fields. + insertStatusField(0, fieldNames[0]); + for(int index = 1; index < fieldNames.length; index++) { + addStatusField(fieldNames[index]); + } + } + @Override public void displayNextEvent() throws IOException { getEvent(true); } + @Override public void displayPreviousEvent() throws IOException { getEvent(false); } + @Override protected void updateStatusPanel() { - // Update the superclass status fields. - super.updateStatusPanel(); - - // Get the currently selected crystal. - Point crystal = ecalPanel.getSelectedCrystal(); - - // If the active crystal is not null, see if it is a cluster. - if(crystal != null) { - // Get the cluster associated with this point. - Cluster activeCluster = clusterMap.get(crystal); - - // If the cluster is null, we set everything to undefined. - if(activeCluster == null) { - for(String field : fieldNames) { setStatusField(field, StatusPanel.NULL_VALUE); } - } - - // Otherwise, define the fields based on the cluster. - else { - // Get the shared and component hit counts. - setStatusField(fieldNames[SHARED_HITS], Integer.toString(activeCluster.getSharedHitCount())); - setStatusField(fieldNames[COMPONENT_HITS], Integer.toString(activeCluster.getComponentHitCount())); - - // Format the cluster energy, or account for it if it - // doesn't exist. - String energy; - if(activeCluster.getClusterEnergy() != Double.NaN) { - DecimalFormat formatter = new DecimalFormat("0.####E0"); - energy = formatter.format(activeCluster.getClusterEnergy()); - } - else { energy = "---"; } - setStatusField(fieldNames[CLUSTER_ENERGY], energy); - } - } - // Otherwise, clear the field values. - else { for(String field : fieldNames) { setStatusField(field, StatusPanel.NULL_VALUE); } } - - // Set the event number. - setStatusField(fieldNames[EVENT_NUMBER], Integer.toString(em.getEventNumber())); + // Update the superclass status fields. + super.updateStatusPanel(); + + // Get the currently selected crystal. + Point crystal = ecalPanel.getSelectedCrystal(); + + // If the active crystal is not null, see if it is a cluster. + if(crystal != null) { + // Get the cluster associated with this point. + Cluster activeCluster = clusterMap.get(crystal); + + // If the cluster is null, we set everything to undefined. + if(activeCluster == null) { + for(String field : fieldNames) { setStatusField(field, ResizableFieldPanel.NULL_VALUE); } + } + + // Otherwise, define the fields based on the cluster. + else { + // Get the shared and component hit counts. + setStatusField(fieldNames[SHARED_HITS], Integer.toString(activeCluster.getSharedHitCount())); + setStatusField(fieldNames[COMPONENT_HITS], Integer.toString(activeCluster.getComponentHitCount())); + + // Format the cluster energy, or account for it if it + // doesn't exist. + String energy; + if(activeCluster.getClusterEnergy() != Double.NaN) { + DecimalFormat formatter = new DecimalFormat("0.####E0"); + energy = formatter.format(activeCluster.getClusterEnergy()); + } + else { energy = "---"; } + setStatusField(fieldNames[CLUSTER_ENERGY], energy); + } + } + // Otherwise, clear the field values. + else { for(String field : fieldNames) { setStatusField(field, ResizableFieldPanel.NULL_VALUE); } } + + // Set the event number. + setStatusField(fieldNames[EVENT_NUMBER], Integer.toString(em.getEventNumber())); } - /** - * <b>displayEvent</b><br/><br/> - * <code>private void <b>displayEvent</b>(List<EcalHit> hitList, List<Cluster> clusterList)</code><br/><br/> - * Displays the given lists of hits and clusters on the calorimeter - * panel. - * @param hitList - A list of hits for the current event. - * @param clusterList - A list of clusters for the current event. - */ - private void displayEvent(List<EcalHit> hitList, List<Cluster> clusterList) { - // Suppress the calorimeter panel's redrawing. - ecalPanel.setSuppressRedraw(true); - + /** + * <b>displayEvent</b><br/><br/> + * <code>private void <b>displayEvent</b>(List<EcalHit> hitList, List<Cluster> clusterList)</code><br/><br/> + * Displays the given lists of hits and clusters on the calorimeter + * panel. + * @param hitList - A list of hits for the current event. + * @param clusterList - A list of clusters for the current event. + */ + private void displayEvent(List<EcalHit> hitList, List<Cluster> clusterList) { + // Suppress the calorimeter panel's redrawing. + ecalPanel.setSuppressRedraw(true); + // Display the hits. for (EcalHit h : hitList) { int ix = toPanelX(h.getX()); @@ -115,19 +122,19 @@ // Display the clusters. for(Cluster cluster : clusterList) { - Point rawCluster = cluster.getClusterCenter(); - Point clusterCenter = toPanelPoint(rawCluster); + Point rawCluster = cluster.getClusterCenter(); + Point clusterCenter = toPanelPoint(rawCluster); ecalPanel.setCrystalCluster(clusterCenter.x, clusterCenter.y, true); - // Add component hits to the calorimeter panel. - for(Point ch : cluster.getComponentHits()) { - ecalPanel.addAssociation(new Association(clusterCenter, toPanelPoint(ch), HIGHLIGHT_CLUSTER_COMPONENT)); - } - - // Add shared hits to the calorimeter panel. - for(Point sh : cluster.getSharedHits()) { - ecalPanel.addAssociation(new Association(clusterCenter, toPanelPoint(sh), HIGHLIGHT_CLUSTER_SHARED)); - } + // Add component hits to the calorimeter panel. + for(Point ch : cluster.getComponentHits()) { + ecalPanel.addAssociation(new Association(clusterCenter, toPanelPoint(ch), HIGHLIGHT_CLUSTER_COMPONENT)); + } + + // Add shared hits to the calorimeter panel. + for(Point sh : cluster.getSharedHits()) { + ecalPanel.addAssociation(new Association(clusterCenter, toPanelPoint(sh), HIGHLIGHT_CLUSTER_SHARED)); + } } // Stop suppressing the redraw and order the panel to update. @@ -136,7 +143,7 @@ // Update the status panel to account for the new event. updateStatusPanel(); - } + } /** * <b>getEvent</b><br/><br/> Modified: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/OccupancyViewer.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/OccupancyViewer.java (original) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/OccupancyViewer.java Sat Nov 1 02:29:56 2014 @@ -17,63 +17,59 @@ * @author Kyle McCarty */ public class OccupancyViewer extends ActiveViewer { - private static final long serialVersionUID = 3712604287904215617L; - // The number of events that have been read so far. - private long events = 0; - // The total number of hits for each crystal position. - private long[][] hits; - - /** - * <b>OccupancyViewer</b><br/><br/> - * <code>public <b>OccupancyViewer</b>(EventManager em)</code><br/><br/> + private static final long serialVersionUID = 3712604287904215617L; + // The number of events that have been read so far. + private long events = 0; + // The total number of hits for each crystal position. + private long[][] hits; + + /** * Creates a new occupancy display that draws event data from the * indicated data source. - * @param em - The data source from which to draw events. - */ - public OccupancyViewer(EventManager em) { - // Initialize the super class. - super(em); - - // Set the title and scale. - setTitle("HPS Calorimeter Occupancies"); - ecalPanel.setScaleMaximum(1.0); - - // Initialize the hit counts array. - Dimension ecalSize = ecalPanel.getCrystalBounds(); - hits = new long[ecalSize.width][ecalSize.height]; - } + * @param em - The data source from which to draw events. + */ + public OccupancyViewer(EventManager em) { + // Initialize the super class. + super(em); + + // Set the title and scale. + setTitle("HPS Calorimeter Occupancies"); + ecalPanel.setScaleMaximum(1.0); + + // Initialize the hit counts array. + Dimension ecalSize = ecalPanel.getCrystalBounds(); + hits = new long[ecalSize.width][ecalSize.height]; + } + @Override public void displayNextEvent() throws IOException { getEvent(true); } + @Override public void displayPreviousEvent() throws IOException { getEvent(false); } /** - * <b>resetOccupancies</b><br/><br/> - * <code>public void <b>resetOccupancies</b>()</code><br/><br/> * Clears the current occupancy data. */ public void resetOccupancies() { - // Clear the crystal hit counts. - for(int x = 0; x < hits.length; x++) { - for(int y = 0; y < hits[0].length; y++) { - hits[x][y] = 0; - } - } - - // Clear the number of events. - events = 0; + // Clear the crystal hit counts. + for(int x = 0; x < hits.length; x++) { + for(int y = 0; y < hits[0].length; y++) { + hits[x][y] = 0; + } + } + + // Clear the number of events. + events = 0; } - /** - * <b>displayEvent</b><br/><br/> - * <code>private void <b>displayEvent</b>(List<EcalHit> hitList)</code><br/><br/> - * Displays the given lists of hits on the calorimeter panel. - * @param hitList - A list of hits for the current event. - */ - private void displayEvent(List<EcalHit> hitList) { - // Suppress the calorimeter panel's redrawing. - ecalPanel.setSuppressRedraw(true); - + /** + * Displays the given lists of hits on the calorimeter panel. + * @param hitList - A list of hits for the current event. + */ + private void displayEvent(List<EcalHit> hitList) { + // Suppress the calorimeter panel's redrawing. + ecalPanel.setSuppressRedraw(true); + // Display the hits. for (EcalHit h : hitList) { ecalPanel.addCrystalEnergy(h.getX(), h.getY(), h.getEnergy()); @@ -85,11 +81,9 @@ // Update the status panel to account for the new event. updateStatusPanel(); - } + } /** - * <b>getEvent</b><br/><br/> - * <code>private void <b>getEvent</b>(boolean forward)</code><br/><br/> * Reads either the next or the previous event from the event manager. * @param forward - Whether the event data should be read forward * or backward. @@ -104,44 +98,44 @@ // Get the next event. if(forward) { - // Get the next event. - em.nextEvent(); - - // Increment the event count. - events++; - - // For each hit, increment the hit count for the relevant - // crystal by one. - for(EcalHit hit : em.getHits()) { - hits[toPanelX(hit.getX())][toPanelY(hit.getY())]++; - } + // Get the next event. + em.nextEvent(); + + // Increment the event count. + events++; + + // For each hit, increment the hit count for the relevant + // crystal by one. + for(EcalHit hit : em.getHits()) { + hits[toPanelX(hit.getX())][toPanelY(hit.getY())]++; + } } else { - // Get the previous event. - em.previousEvent(); - - // Decrement the event count. - events--; - - // For each hit, decrement the hit count for the relevant - // crystal by one. - for(EcalHit hit : em.getHits()) { - hits[toPanelX(hit.getX())][toPanelY(hit.getY())]--; - } + // Get the previous event. + em.previousEvent(); + + // Decrement the event count. + events--; + + // For each hit, decrement the hit count for the relevant + // crystal by one. + for(EcalHit hit : em.getHits()) { + hits[toPanelX(hit.getX())][toPanelY(hit.getY())]--; + } } // Build a "hit list" from the occupancies. ArrayList<EcalHit> occupancyList = new ArrayList<EcalHit>(); for(int x = 0; x < hits.length; x++) { - for(int y = 0; y < hits[0].length; y++) { - if(hits[x][y] != 0) { - // Define the crystal ID and "energy." - Point cid = new Point(x, y); - double occupancy = ((double) hits[x][y]) / events; - EcalHit occupancyHit = new EcalHit(cid, occupancy); - occupancyList.add(occupancyHit); - } - } + for(int y = 0; y < hits[0].length; y++) { + if(hits[x][y] != 0) { + // Define the crystal ID and "energy." + Point cid = new Point(x, y); + double occupancy = ((double) hits[x][y]) / events; + EcalHit occupancyHit = new EcalHit(cid, occupancy); + occupancyList.add(occupancyHit); + } + } } // Display it the occupancies. Added: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/PDataEventViewer.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/PDataEventViewer.java (added) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/PDataEventViewer.java Sat Nov 1 02:29:56 2014 @@ -0,0 +1,98 @@ +package org.hps.monitoring.ecal.eventdisplay.ui; + +import java.awt.Point; +import java.io.IOException; + +import org.hps.monitoring.ecal.eventdisplay.util.CrystalDataSet; +import org.hps.monitoring.ecal.eventdisplay.util.EcalWiringManager; + +/** + * Class <code>PDataEventViewer</code> is the passive variant of a data + * viewer. It displays crystal hardware information read from a given + * data file and displays it along with crystal energy and index data. + * + * @author Kyle McCarty + */ +public class PDataEventViewer extends PEventViewer { + // Local variables. + private static final long serialVersionUID = 1L; + private final EcalWiringManager ewm; + + // Hardware display fields. + private static final String[] fieldNames = { + "APD Number", "Preamp Number", "LED Channel", "LED Driver", + "FADC Slot", "FADC Channel", "Splitter Number", "HV Group", + "Jout", "MB", "Channel", "Gain" + }; + + // Hardware display field indices. + private static final int FIELD_APD = 0; + private static final int FIELD_PREAMP = 1; + private static final int FIELD_LED_CHANNEL = 2; + private static final int FIELD_LED_DRIVER = 3; + private static final int FIELD_FADC_SLOT = 4; + private static final int FIELD_FADC_CHANNEL = 5; + private static final int FIELD_SPLITTER = 6; + private static final int FIELD_HV_GROUP = 7; + private static final int FIELD_JOUT = 8; + private static final int FIELD_MB = 9; + private static final int FIELD_CHANNEL = 10; + private static final int FIELD_GAIN = 11; + + /** + * Initializes a new <code>DataFileViewer</code> that reads from + * the given event manager for event data and the given hardware + * data file for crystal hardware data readout. + * @param dataSource - The manager for event data. + * @param crystalDataFilePath - The data file for crystal hardware + * information. + * @throws IOException Occurs if there is an error reading from + * either data source. + */ + public PDataEventViewer(String crystalDataFilePath) throws IOException { + // Initialize the super class file. + super(); + + // Load the crystal data mapping. + ewm = new EcalWiringManager(crystalDataFilePath); + + // Add the crystal data fields. + for(String fieldName : fieldNames) { + addStatusField(fieldName); + } + } + + @Override + protected void updateStatusPanel() { + // Run the superclass method. + super.updateStatusPanel(); + + // Get the selected crystal. + Point crystal = ecalPanel.getSelectedCrystal(); + + // If a crystal is selected, display its data set. + if(crystal != null) { + // Get the LCSim coordinate system version of the crystal. + Point lcsimCrystal = Viewer.toEcalPoint(crystal); + + // Get the hardware data set associated with the crystal. + CrystalDataSet cds = ewm.getCrystalData(lcsimCrystal); + + // If the data set exists, update the all the fields. + if(cds != null) { + setStatusField(fieldNames[FIELD_APD], "" + cds.getAPDNumber()); + setStatusField(fieldNames[FIELD_PREAMP], cds.getPreamplifierNumber().toString()); + setStatusField(fieldNames[FIELD_LED_CHANNEL], "" + cds.getLEDChannel()); + setStatusField(fieldNames[FIELD_LED_DRIVER], "" + cds.getLEDDriver()); + setStatusField(fieldNames[FIELD_FADC_SLOT], "" + cds.getFADCSlot()); + setStatusField(fieldNames[FIELD_FADC_CHANNEL], "" + cds.getFADCChannel()); + setStatusField(fieldNames[FIELD_SPLITTER], "" + cds.getSplitterNumber()); + setStatusField(fieldNames[FIELD_HV_GROUP], "" + cds.getHighVoltageGroup()); + setStatusField(fieldNames[FIELD_JOUT], "" + cds.getJout()); + setStatusField(fieldNames[FIELD_MB], "" + cds.getMB()); + setStatusField(fieldNames[FIELD_CHANNEL], "" + cds.getChannel()); + setStatusField(fieldNames[FIELD_GAIN], "" + cds.getGain()); + } + } + } +} Modified: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/PEventViewer.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/PEventViewer.java (original) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/PEventViewer.java Sat Nov 1 02:29:56 2014 @@ -22,60 +22,58 @@ * @author Kyle McCarty */ public class PEventViewer extends PassiveViewer { - private static final long serialVersionUID = -7479125553259270894L; - // Stores whether the background color is set or not. - private boolean background = false; - // Stores cluster objects. - protected ArrayList<Cluster> clusterList = new ArrayList<Cluster>(); - // Stores hit objects. - protected ArrayList<EcalHit> hitList = new ArrayList<EcalHit>(); - - /** - * <b>PEventViewer</b><br/><br/> - * <code>public <b>PEventViewer</b>(String... fieldValues)</code><br/><br/> - * Creates a passive viewer for displaying hits and clusters in - * an event. - * @param fieldValues - Any additional status fields to display. - */ - public PEventViewer(String... fieldValues) { - // Pass the field values to the superclass. - super(fieldValues); - - // Set the key bindings. - addKeyListener(new EcalKeyListener()); - } - - public void addHit(EcalHit hit) { hitList.add(hit); } - - public void addCluster(Cluster cluster) { clusterList.add(cluster); } - - /** - * <b>clearHits</b><br/><br/> - * <code>public void <b>clearHits</b>()</code><br/><br/> - * Removes all of the hit data from the viewer. - */ - public void clearHits() { hitList.clear(); } - - /** - * <b>clearClusters</b><br/><br/> - * <code>public void <b>clearClusters</b>()</code><br/><br/> - * Removes all of the cluster data from the viewer. - */ - public void clearClusters() { hitList.clear(); } - - public void resetDisplay() { - // Reset the hit and cluster lists. - hitList.clear(); - clusterList.clear(); - } - - public void updateDisplay() { - // Suppress the calorimeter panel's redrawing. - ecalPanel.setSuppressRedraw(true); - - // Clear the panel data. - ecalPanel.clearCrystals(); - + private static final long serialVersionUID = -7479125553259270894L; + // Stores whether the background color is set or not. + private boolean background = false; + // Stores cluster objects. + protected ArrayList<Cluster> clusterList = new ArrayList<Cluster>(); + // Stores hit objects. + protected ArrayList<EcalHit> hitList = new ArrayList<EcalHit>(); + + /** + * Creates a passive viewer for displaying hits and clusters in + * an event. + * @param fieldValues - Any additional status fields to display. + */ + public PEventViewer() { + // Initialize the superclass. + super(); + + // Set the key bindings. + addKeyListener(new EcalKeyListener()); + } + + @Override + public void addHit(EcalHit hit) { hitList.add(hit); } + + @Override + public void addCluster(Cluster cluster) { clusterList.add(cluster); } + + /** + * Removes all of the hit data from the viewer. + */ + public void clearHits() { hitList.clear(); } + + /** + * Removes all of the cluster data from the viewer. + */ + public void clearClusters() { hitList.clear(); } + + @Override + public void resetDisplay() { + // Reset the hit and cluster lists. + hitList.clear(); + clusterList.clear(); + } + + @Override + public void updateDisplay() { + // Suppress the calorimeter panel's redrawing. + ecalPanel.setSuppressRedraw(true); + + // Clear the panel data. + ecalPanel.clearCrystals(); + // Display the hits. for (EcalHit h : hitList) { int ix = toPanelX(h.getX()); @@ -85,19 +83,19 @@ // Display the clusters. for(Cluster cluster : clusterList) { - Point rawCluster = cluster.getClusterCenter(); - Point clusterCenter = toPanelPoint(rawCluster); + Point rawCluster = cluster.getClusterCenter(); + Point clusterCenter = toPanelPoint(rawCluster); ecalPanel.setCrystalCluster(clusterCenter.x, clusterCenter.y, true); - // Add component hits to the calorimeter panel. - for(Point ch : cluster.getComponentHits()) { - ecalPanel.addAssociation(new Association(clusterCenter, toPanelPoint(ch), HIGHLIGHT_CLUSTER_COMPONENT)); - } - - // Add shared hits to the calorimeter panel. - for(Point sh : cluster.getSharedHits()) { - ecalPanel.addAssociation(new Association(clusterCenter, toPanelPoint(sh), HIGHLIGHT_CLUSTER_SHARED)); - } + // Add component hits to the calorimeter panel. + for(Point ch : cluster.getComponentHits()) { + ecalPanel.addAssociation(new Association(clusterCenter, toPanelPoint(ch), HIGHLIGHT_CLUSTER_COMPONENT)); + } + + // Add shared hits to the calorimeter panel. + for(Point sh : cluster.getSharedHits()) { + ecalPanel.addAssociation(new Association(clusterCenter, toPanelPoint(sh), HIGHLIGHT_CLUSTER_SHARED)); + } } // Stop suppressing the redraw and order the panel to update. @@ -106,25 +104,27 @@ // Update the status panel to account for the new event. updateStatusPanel(); - } - + } + /** * The <code>EcalListener</code> class binds keys to actions. * Bound actions include: * b :: Toggle color-mapping for 0 energy crystals * h :: Toggle selected crystal highlighting * l :: Toggle logarithmic versus linear scaling - * s :: Saves the current display to a file + * s :: Saves the current display to a file **/ private class EcalKeyListener implements KeyListener { + @Override public void keyPressed(KeyEvent e) { } + @Override public void keyReleased(KeyEvent e) { // 'b' toggles the default white background. if(e.getKeyCode() == 66) { - if(background) { ecalPanel.setDefaultCrystalColor(null); } - else { ecalPanel.setDefaultCrystalColor(Color.GRAY); } - background = !background; + if(background) { ecalPanel.setDefaultCrystalColor(null); } + else { ecalPanel.setDefaultCrystalColor(Color.GRAY); } + background = !background; } // 'h' toggles highlighting the crystal under the cursor. @@ -132,39 +132,40 @@ // 'l' toggles linear or logarithmic scaling. else if(e.getKeyCode() == 76) { - if(ecalPanel.isScalingLinear()) { ecalPanel.setScalingLogarithmic(); } - else { ecalPanel.setScalingLinear(); } + if(ecalPanel.isScalingLinear()) { ecalPanel.setScalingLogarithmic(); } + else { ecalPanel.setScalingLinear(); } } // 's' saves the panel to a file. else if(e.getKeyCode() == 83) { - // Make a new buffered image on which to draw the content pane. - BufferedImage screenshot = new BufferedImage(getContentPane().getWidth(), - getContentPane().getHeight(), BufferedImage.TYPE_INT_ARGB); - - // Paint the content pane to image. - getContentPane().paint(screenshot.getGraphics()); - - // Get the lowest available file name. - int fileNum = 0; - File imageFile = new File("screenshot_" + fileNum + ".png"); - while(imageFile.exists()) { - fileNum++; - imageFile = new File("screenshot_" + fileNum + ".png"); - } - - // Save the image to a PNG file. - try { ImageIO.write(screenshot, "PNG", imageFile); } - catch(IOException ioe) { - System.err.println("Error saving file \"screenshot.png\"."); - } - System.out.println("Screenshot saved to: " + imageFile.getAbsolutePath()); + // Make a new buffered image on which to draw the content pane. + BufferedImage screenshot = new BufferedImage(getContentPane().getWidth(), + getContentPane().getHeight(), BufferedImage.TYPE_INT_ARGB); + + // Paint the content pane to image. + getContentPane().paint(screenshot.getGraphics()); + + // Get the lowest available file name. + int fileNum = 0; + File imageFile = new File("screenshot_" + fileNum + ".png"); + while(imageFile.exists()) { + fileNum++; + imageFile = new File("screenshot_" + fileNum + ".png"); + } + + // Save the image to a PNG file. + try { ImageIO.write(screenshot, "PNG", imageFile); } + catch(IOException ioe) { + System.err.println("Error saving file \"screenshot.png\"."); + } + System.out.println("Screenshot saved to: " + imageFile.getAbsolutePath()); } // Otherwise, print out the key code for the pressed key. else { System.out.printf("Key Code: %d%n", e.getKeyCode()); } } + @Override public void keyTyped(KeyEvent e) { } } } Modified: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/POccupancyViewer.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/POccupancyViewer.java (original) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/POccupancyViewer.java Sat Nov 1 02:29:56 2014 @@ -16,100 +16,93 @@ * @author Kyle McCarty */ public class POccupancyViewer extends PassiveViewer { - private static final long serialVersionUID = 3712604287904215617L; - // Store the number of hits for each crystal. - private long[][] hits; - // Store the total number of events read. - private long events = 0; - // Stores hit objects. - protected ArrayList<EcalHit> hitList = new ArrayList<EcalHit>(); - - /** - * <b>POccupancyViewer</b><br/><br/> - * <code>public <b>POccupancyViewer</b>(int updateRate, boolean resetAtUpdate)</code><br/><br/> + private static final long serialVersionUID = 3712604287904215617L; + // Store the number of hits for each crystal. + private long[][] hits; + // Store the total number of events read. + private long events = 0; + // Stores hit objects. + protected ArrayList<EcalHit> hitList = new ArrayList<EcalHit>(); + + /** * Initializes a <code>Viewer</code> window that displays will * occupancies from a data stream. - */ - public POccupancyViewer() { - // Set the title and scale. - setTitle("HPS Calorimeter Occupancies"); - ecalPanel.setScaleMaximum(1.0); - - // Initialize the hit counts array. - Dimension ecalSize = ecalPanel.getCrystalBounds(); - hits = new long[ecalSize.width][ecalSize.height]; - } + */ + public POccupancyViewer() { + // Set the title and scale. + setTitle("HPS Calorimeter Occupancies"); + ecalPanel.setScaleMaximum(1.0); + + // Initialize the hit counts array. + Dimension ecalSize = ecalPanel.getCrystalBounds(); + hits = new long[ecalSize.width][ecalSize.height]; + } - public void addHit(EcalHit hit) { - // Get the panel coordinates of the hit. - int ix = toPanelX(hit.getX()); - int iy = toPanelY(hit.getY()); - - // Increment the hit count at the indicated location. - hits[ix][iy]++; - } - - /** - * <b>addCluster</b><br/><br/> - * <code>public void <b>addCluster</b>(Cluster cluster)</code><br/><br/> - * Adds a new cluster to the display.<br/><br/> - * <b>Note:</b> This operation is not supported for occupancies. - */ - public void addCluster(Cluster cluster) { } - - /** - * <b>removeHit</b><br/><br/> - * <code>public void <b>removeHit</b>(EcalHit hit)</code><br/><br/> - * Removes a hit from the display. - * @param hit - The hit to be removed. - */ - public void removeHit(EcalHit hit) { - // Get the panel coordinates of the hit. - int ix = toPanelX(hit.getX()); - int iy = toPanelY(hit.getY()); - - // Decrement the hit count at the indicated location. - hits[ix][iy]--; - } - - public void resetDisplay() { hitList.clear(); } - - /** - * <b>incrementEventCount</b><br/><br/> - * <code>public void <b>incrementEventCount</b>(int amount)</code><br/><br/> - * Increments the number of events represented by the current data - * set by the indicated amount. Note that this may be negative to - * reduce the number of events. - * @param amount - The number of events to add. - */ - public void incrementEventCount(int amount) { events += amount; } - - /** - * <b>updateDisplay</b><br/><br/> - * <code>public void <b>updateDisplay</b>()</code><br/><br/> - * Displays the hits and clusters added by the <code>addHit</code> - * and <code>addCluster</code> methods. - */ - public void updateDisplay() { + @Override + public void addHit(EcalHit hit) { + // Get the panel coordinates of the hit. + int ix = toPanelX(hit.getX()); + int iy = toPanelY(hit.getY()); + + // Increment the hit count at the indicated location. + hits[ix][iy]++; + } + + /** + * Adds a new cluster to the display.<br/><br/> + * <b>Note:</b> This operation is not supported for occupancies. + */ + public void addCluster(Cluster cluster) { } + + /** + * Removes a hit from the display. + * @param hit - The hit to be removed. + */ + public void removeHit(EcalHit hit) { + // Get the panel coordinates of the hit. + int ix = toPanelX(hit.getX()); + int iy = toPanelY(hit.getY()); + + // Decrement the hit count at the indicated location. + hits[ix][iy]--; + } + + @Override + public void resetDisplay() { hitList.clear(); } + + /** + * Increments the number of events represented by the current data + * set by the indicated amount. Note that this may be negative to + * reduce the number of events. + * @param amount - The number of events to add. + */ + public void incrementEventCount(int amount) { events += amount; } + + /** + * Displays the hits and clusters added by the <code>addHit</code> + * and <code>addCluster</code> methods. + */ + @Override + public void updateDisplay() { // Build a "hit list" from the occupancies. for(int x = 0; x < hits.length; x++) { - for(int y = 0; y < hits[0].length; y++) { - // Don't bother performing calculations or building - // any objects if there are zero hits. - if(hits[x][y] != 0) { - // Define the crystal ID and "energy." - Point cid = new Point(x, y); - double occupancy = ((double) hits[x][y]) / events; - - // Add a "hit" formed from these values. - hitList.add(new EcalHit(cid, occupancy)); - } - } + for(int y = 0; y < hits[0].length; y++) { + // Don't bother performing calculations or building + // any objects if there are zero hits. + if(hits[x][y] != 0) { + // Define the crystal ID and "energy." + Point cid = new Point(x, y); + double occupancy = ((double) hits[x][y]) / events; + + // Add a "hit" formed from these values. + hitList.add(new EcalHit(cid, occupancy)); + } + } } - // Suppress the calorimeter panel's redrawing. - ecalPanel.setSuppressRedraw(true); - + // Suppress the calorimeter panel's redrawing. + ecalPanel.setSuppressRedraw(true); + // Display the hits. for (EcalHit h : hitList) { int ix = toPanelX(h.getX()); @@ -123,5 +116,5 @@ // Update the status panel to account for the new event. updateStatusPanel(); - } + } } Modified: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/PassiveViewer.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/PassiveViewer.java (original) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/PassiveViewer.java Sat Nov 1 02:29:56 2014 @@ -20,94 +20,94 @@ * @author Kyle McCarty */ public abstract class PassiveViewer extends Viewer { - private static final long serialVersionUID = -7479125553259270894L; - // Stores whether the background color is set or not. - private boolean background = false; - - /** - * <b>PassiveViewer</b><br/><br/> - * <code>public <b>PassiveViewer</b>(String... fieldValues)</code><br/><br/> - * @param fieldValues - */ - public PassiveViewer(String... fieldValues) { - // Pass the field values to the superclass. - super(fieldValues); - - // Set the key bindings. - addKeyListener(new EcalKeyListener()); - } - - /** - * <b>addHit</b><br/><br/> - * <code>public void <b>addHit</b>(EcalHit hit)</code><br/><br/> - * Adds a new hit to the display. - * @param hit - The hit to be added. - */ - public abstract void addHit(EcalHit hit); - - /** - * <b>addCluster</b><br/><br/> - * <code>public void <b>addCluster</b>(Cluster cluster)</code><br/><br/> - * Adds a new cluster to the display. - * @param cluster - The cluster to be added. - */ - public abstract void addCluster(Cluster cluster); - - /** - * <b>resetDisplay</b><br/><br/> - * <code>public void <b>resetDisplay</b>()</code><br/><br/> - * Clears any hits or clusters that have been added to the viewer. - * Note that this does not automatically update the displayed panel. - * <code>updateDisplay</code> must be called separately. - */ - public abstract void resetDisplay(); - - /** - * <b>setScale</b><br/><br/> - * <code>public void <b>setScale</b>(int min, int max)</code><br/><br/> - * Sets the upper and lower bounds of for the calorimeter display's - * color mapping scale. - * @param min - The lower bound. - * @param max - The upper bound. - */ - public void setScale(int min, int max) { - ecalPanel.setScaleMinimum(min); - ecalPanel.setScaleMaximum(max); - } - - /** - * <b>setScaleMaximum</b><br/><br/> - * <code>public void <b>setScaleMaximum</b>(int max)</code><br/><br/> - * Sets the upper bound for the calorimeter display's color mapping - * scale. - * @param max - The upper bound. - */ - public void setScaleMaximum(int max) { ecalPanel.setScaleMaximum(max); } - - /** - * <b>setScaleMinimum</b><br/><br/> - * <code>public void <b>setScaleMinimum</b>(int min)</code><br/><br/> - * Sets the lower bound for the calorimeter display's color mapping - * scale. - * @param min - The lower bound. - */ - public void setScaleMinimum(int min) { ecalPanel.setScaleMinimum(min); } - - /** - * <b>updateDisplay</b><br/><br/> - * <code>public void <b>updateDisplay</b>()</code><br/><br/> - * Displays the hits and clusters added by the <code>addHit</code> - * and <code>addCluster</code> methods. - */ - public abstract void updateDisplay(); - + private static final long serialVersionUID = -7479125553259270894L; + // Stores whether the background color is set or not. + private boolean background = false; + + /** + * <b>PassiveViewer</b><br/><br/> + * <code>public <b>PassiveViewer</b>(String... fieldValues)</code><br/><br/> + * @param fieldValues + */ + public PassiveViewer() { + // Initialize the superclass. + super(); + + // Set the key bindings. + addKeyListener(new EcalKeyListener()); + } + + /** + * <b>addHit</b><br/><br/> + * <code>public void <b>addHit</b>(EcalHit hit)</code><br/><br/> + * Adds a new hit to the display. + * @param hit - The hit to be added. + */ + public abstract void addHit(EcalHit hit); + + /** + * <b>addCluster</b><br/><br/> + * <code>public void <b>addCluster</b>(Cluster cluster)</code><br/><br/> + * Adds a new cluster to the display. + * @param cluster - The cluster to be added. + */ + public abstract void addCluster(Cluster cluster); + + /** + * <b>resetDisplay</b><br/><br/> + * <code>public void <b>resetDisplay</b>()</code><br/><br/> + * Clears any hits or clusters that have been added to the viewer. + * Note that this does not automatically update the displayed panel. + * <code>updateDisplay</code> must be called separately. + */ + public abstract void resetDisplay(); + + /** + * <b>setScale</b><br/><br/> + * <code>public void <b>setScale</b>(int min, int max)</code><br/><br/> + * Sets the upper and lower bounds of for the calorimeter display's + * color mapping scale. + * @param min - The lower bound. + * @param max - The upper bound. + */ + public void setScale(int min, int max) { + ecalPanel.setScaleMinimum(min); + ecalPanel.setScaleMaximum(max); + } + + /** + * <b>setScaleMaximum</b><br/><br/> + * <code>public void <b>setScaleMaximum</b>(int max)</code><br/><br/> + * Sets the upper bound for the calorimeter display's color mapping + * scale. + * @param max - The upper bound. + */ + public void setScaleMaximum(int max) { ecalPanel.setScaleMaximum(max); } + + /** + * <b>setScaleMinimum</b><br/><br/> + * <code>public void <b>setScaleMinimum</b>(int min)</code><br/><br/> + * Sets the lower bound for the calorimeter display's color mapping + * scale. + * @param min - The lower bound. + */ + public void setScaleMinimum(int min) { ecalPanel.setScaleMinimum(min); } + + /** + * <b>updateDisplay</b><br/><br/> + * <code>public void <b>updateDisplay</b>()</code><br/><br/> + * Displays the hits and clusters added by the <code>addHit</code> + * and <code>addCluster</code> methods. + */ + public abstract void updateDisplay(); + /** * The <code>EcalListener</code> class binds keys to actions. * Bound actions include: * b :: Toggle color-mapping for 0 energy crystals * h :: Toggle selected crystal highlighting * l :: Toggle logarithmic versus linear scaling - * s :: Saves the current display to a file + * s :: Saves the current display to a file **/ private class EcalKeyListener implements KeyListener { public void keyPressed(KeyEvent e) { } @@ -115,9 +115,9 @@ public void keyReleased(KeyEvent e) { // 'b' toggles the default white background. if(e.getKeyCode() == 66) { - if(background) { ecalPanel.setDefaultCrystalColor(null); } - else { ecalPanel.setDefaultCrystalColor(Color.GRAY); } - background = !background; + if(background) { ecalPanel.setDefaultCrystalColor(null); } + else { ecalPanel.setDefaultCrystalColor(Color.GRAY); } + background = !background; } // 'h' toggles highlighting the crystal under the cursor. @@ -125,33 +125,33 @@ // 'l' toggles linear or logarithmic scaling. else if(e.getKeyCode() == 76) { - if(ecalPanel.isScalingLinear()) { ecalPanel.setScalingLogarithmic(); } - else { ecalPanel.setScalingLinear(); } + if(ecalPanel.isScalingLinear()) { ecalPanel.setScalingLogarithmic(); } + else { ecalPanel.setScalingLinear(); } } // 's' saves the panel to a file. else if(e.getKeyCode() == 83) { - // Make a new buffered image on which to draw the content pane. - BufferedImage screenshot = new BufferedImage(getContentPane().getWidth(), - getContentPane().getHeight(), BufferedImage.TYPE_INT_ARGB); - - // Paint the content pane to image. - getContentPane().paint(screenshot.getGraphics()); - - // Get the lowest available file name. - int fileNum = 0; - File imageFile = new File("screenshot_" + fileNum + ".png"); - while(imageFile.exists()) { - fileNum++; - imageFile = new File("screenshot_" + fileNum + ".png"); - } - - // Save the image to a PNG file. - try { ImageIO.write(screenshot, "PNG", imageFile); } - catch(IOException ioe) { - System.err.println("Error saving file \"screenshot.png\"."); - } - System.out.println("Screenshot saved to: " + imageFile.getAbsolutePath()); + // Make a new buffered image on which to draw the content pane. + BufferedImage screenshot = new BufferedImage(getContentPane().getWidth(), + getContentPane().getHeight(), BufferedImage.TYPE_INT_ARGB); + + // Paint the content pane to image. + getContentPane().paint(screenshot.getGraphics()); + + // Get the lowest available file name. + int fileNum = 0; + File imageFile = new File("screenshot_" + fileNum + ".png"); + while(imageFile.exists()) { + fileNum++; + imageFile = new File("screenshot_" + fileNum + ".png"); + } + + // Save the image to a PNG file. + try { ImageIO.write(screenshot, "PNG", imageFile); } + catch(IOException ioe) { + System.err.println("Error saving file \"screenshot.png\"."); + } + System.out.println("Screenshot saved to: " + imageFile.getAbsolutePath()); } // Otherwise, print out the key code for the pressed key. Added: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/ResizableFieldPanel.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/ResizableFieldPanel.java (added) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/ResizableFieldPanel.java Sat Nov 1 02:29:56 2014 @@ -0,0 +1,515 @@ +package org.hps.monitoring.ecal.eventdisplay.ui; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.LayoutManager; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.swing.JLabel; +import javax.swing.JPanel; + +/** + * Class <code>ResizableFieldPanel</code> is an extension of <code> + * JPanel</code> that contains a series of "fields." Each field is + * composed of a header label that displays its name and a value + * label that displays its value. Field names are constant once set + * but values may be changed.<br/> + * <br/> + * <code>ResizableFieldPanel</code> automatically handles the layout + * of its fields, displaying the header label next to the value label + * and inserting as many in a row as possible before wrapping to the + * next row. <code>ResizableFieldPanel</code> ensures that each field + * in a column is the same size as the other fields in the same column + * and that all fields in the same column are aligned. Individual + * columns may be different widths.<br/> + * <br/> + * The preferred width of a column is set by the preferred size of the + * largest field in that column or a minimum row size, if it is set. + * Fields that exceed the minimum row size are still granted their full + * preferred size. + * + * @author Kyle McCarty + * @see JPanel + */ +public class ResizableFieldPanel extends JPanel { + // Local variables. + private static final long serialVersionUID = 1L; + private Font boldFont = getFont().deriveFont(Font.BOLD); + private static final int horizontal = 10; + private static final int vertical = 10; + private Dimension oldSize = new Dimension(0, 0); + private int oldFieldCount = 0; + private int minDisplayWidth = 0; + private Dimension userPreferred = null; + private Dimension actualPreferred = new Dimension(0, 0); + + // Constituent components. + private List<JLabel> headerList = new ArrayList<JLabel>(); + private List<JLabel> displayList = new ArrayList<JLabel>(); + + // Class variables. + /** The display text for a field with no value. */ + static final String NULL_VALUE = "---"; + + /** + * Instantiates a new <code>ResizableFieldPanel</code> with no + * minimum column width. + */ + public ResizableFieldPanel() { this(0); } + + /** + * Instantiates a new <code>ResizableFieldPanel</code> with the + * indicated minimum column width. + * @param minWidth - The minimum column width. + */ + public ResizableFieldPanel(int minWidth) { + // Component handles constituent component placement manually. + super.setLayout(null); + + // Set the minimum component width. + minDisplayWidth = minWidth >= 0 ? minWidth : 0; + + // Reset the constituent component placement whenever the base + // component changes size. + addComponentListener(new ComponentAdapter() { + @Override + public void componentResized(ComponentEvent e) { + // Issue an order to reset the component layout. + resetLayout(); + } + }); + } + + /** + * Adds a new field to the panel. + * @param fieldName - The name of the field. + * @throws NullPointerException Occurs if the field name is <code> + * null</code>. + */ + public void addField(String fieldName) throws NullPointerException { + addField(fieldName, null); + } + + /** + * Adds a new field to the panel. + * @param fieldName - The name of the field. + * @param fieldValue - The initial value of the field. + * @throws NullPointerException Occurs if the field name is <code> + * null</code>. + */ + public void addField(String fieldName, String fieldValue) throws NullPointerException { + // Require that the field have a non-null name. + if(fieldName == null) { throw new NullPointerException("Field names can not be null."); } + + // Null values default the default value. + if(fieldValue == null) { fieldValue = NULL_VALUE; } + + // Create new labels to populate the component. + JLabel header = new JLabel(fieldName + ":"); + header.setFont(boldFont); + header.setHorizontalAlignment(JLabel.RIGHT); + JLabel display = new JLabel(fieldValue); + display.setFont(getFont()); + + // Add the labels to the list. + headerList.add(header); + displayList.add(display); + + // Add the components to the base panel. + add(header); + add(display); + + // Reset the label layout. + resetLayout(); + } + + /** + * Sets the values of all fields to <code>NULL_VALUE</code>. + */ + public void clearFields() { + for(JLabel display : displayList) { + display.setText(NULL_VALUE); + } + } + + /** + * Gets the number of fields contained in the component. + * @return Returns the number of fields as an <code>int</code> + * primitive. + */ + public int getFieldCount() { return headerList.size(); } + + /** + * Generates a map that links field name to field index. + * @return Returns a <code>Map</code> object linking the <code> + * String</code> field name to the <code>int</code> field index. + */ + public Map<String, Integer> getFieldNameIndexMap() { + // Get the number of fields. + int fields = headerList.size(); + + // Create the map. + Map<String, Integer> fieldMap = new HashMap<String, Integer>(fields); + + // Populate the map. + for(int index = 0; index < fields; index++) { + // Get the header name and remove the colon at the end. + String header = headerList.get(index).getText(); + header = header.substring(0, header.length() - 1); + + // Add it to the map. + fieldMap.put(header, new Integer(index)); + } + + // Return the map. + return fieldMap; + } + + /** + * Gets the list of all field names in order of field index. + * @return Returns the set of field names as an array of <code> + * String</code> objects. + */ + public String[] getFieldNames() { + // Create an array for the field names. + String[] fieldNames = new String[headerList.size()]; + + // Populate the array. + for(int index = 0; index < headerList.size(); index++) { + String fieldName = headerList.get(index).getText(); + fieldNames[index] = fieldName.substring(0, fieldName.length() - 2); + } + + // Return the result. + return fieldNames; + } + + /** + * Gets the value for the field at the indicated index. + * @param fieldIndex - The index of the field. + * @return Returns the field value as a <code>String</code> object. + * @throws IndexOutOfBoundsException Occurs if an invalid field index + * is given. + */ + public String getFieldValue(int fieldIndex) throws IndexOutOfBoundsException { + // Validate the index. + validateFieldIndex(fieldIndex); + + // Return the value of the requested field. + return displayList.get(fieldIndex).getText(); + } + + @Override + public Dimension getPreferredSize() { + if(userPreferred == null) { return actualPreferred; } + else { return userPreferred; } + } + + /** + * Inserts a field at the indicated index, if possible. + * @param index - The index at which to insert the field. + * @param fieldName - The name of the field. + * @throws IndexOutOfBoundsException Occurs if the insertion index + * is not a valid index within the component. + * @throws NullPointerException Occurs if the field name is <code> + * null</code>. + */ + public void insertField(int index, String fieldName) throws IndexOutOfBoundsException, NullPointerException { + insertField(index, fieldName, ""); + } + + /** + * Inserts a field at the indicated index, if possible. + * @param index - The index at which to insert the field. + * @param fieldName - The name of the field. + * @param fieldValue - The initial value of the field. + * @throws IndexOutOfBoundsException Occurs if the insertion index + * is not a valid index within the component. + * @throws NullPointerException Occurs if the field name is <code> + * null</code>. + */ + public void insertField(int index, String fieldName, String fieldValue) throws IndexOutOfBoundsException, NullPointerException { + // Require that the field have a non-null name. + if(fieldName == null) { throw new NullPointerException("Field names can not be null."); } + + // Null values default the default value. + if(fieldValue == null) { fieldValue = NULL_VALUE; } + + // Create new labels to populate the component. + JLabel header = new JLabel(fieldName + ":"); + header.setFont(boldFont); + header.setHorizontalAlignment(JLabel.RIGHT); + JLabel display = new JLabel(fieldValue); + display.setFont(getFont()); + + // Add the labels to the list. + headerList.add(index, header); + displayList.add(index, display); + + // Add the components to the base panel. + add(header); + add(display); + + // Reset the label layout. + resetLayout(); + } + + /** + * Removes the field at the indicated index. + * @param fieldIndex - The index of the field. + * @throws IndexOutOfBoundsException Occurs if an invalid field index + * is given. + */ + public void removeField(int fieldIndex) throws IndexOutOfBoundsException { + // Validate the index. + validateFieldIndex(fieldIndex); + + // Remove the requested field. + remove(headerList.get(fieldIndex)); + remove(displayList.get(fieldIndex)); + headerList.remove(fieldIndex); + displayList.remove(fieldIndex); + + // Reset the layout. + resetLayout(); + } + + /** + * Sets the value of the field at the indicated index. + * @param fieldIndex - The index of the field. + * @param fieldValue - The new value of the field. + * @throws IndexOutOfBoundsException Occurs if an invalid field index + * is given. + */ + public void setFieldValue(int fieldIndex, String fieldValue) throws IndexOutOfBoundsException { + // Validate the index. + validateFieldIndex(fieldIndex); + + // Set the value of the requested field. + displayList.get(fieldIndex).setText(fieldValue); + } + + @Override + public void setFont(Font font) { + // If the superclass font is null, the component is still + // being initialized and needs to just run the superclass + // method. + if(getFont() == null) { super.setFont(font); } + + // Otherwise, set any constituent components to the correct + // font as well. + else { + // If the font is being set to null, use the default + // system font. + if(font == null) { font = new Font(Font.DIALOG, Font.PLAIN, 11); } + + // Set the base panel's font to the indicated value. + super.setFont(font); + + // Create a new bold font. + boldFont = super.getFont().deriveFont(Font.BOLD); + + // Set each display label to the indicated font. + for(JLabel display : displayList) { display.setFont(font); } + + // Set each header label to the bold font. + for(JLabel header : headerList) { header.setFont(boldFont); } + } + } + + @Override + public void setLayout(LayoutManager mgr) { + // ResizableDisplayManager handles its own layout, so do nothing. + return; + } + + @Override + public void setPreferredSize(Dimension preferredSize) { + userPreferred = preferredSize; + } + + /** + * Repositions the fields to the appropriate positions given the + * current width of the component. + */ + private void resetLayout() { + // If the neither the size of the component nor the number of + // fields have changed, there is nothing to do here. + if(headerList.size() == oldFieldCount && oldSize.width == getSize().width + && oldSize.height == getSize().height) { + return; + } + + // Set the last width and field counts. + oldSize = getSize(); + oldFieldCount = headerList.size(); + + // Otherwise, determine the ideal maximum number of fields that + // can be displayed in a single row. + int availableWidth = getWidth() - horizontal; + int max = 0; + idealLoop: + for(int index = 0; index < headerList.size(); index++) { + // Subtract the necessary width for the header label. + availableWidth -= headerList.get(index).getPreferredSize().width; + availableWidth -= horizontal; + + // Subtract the required width for the display label. + int displayWidth = displayList.get(index).getPreferredSize().width; + if(displayWidth < minDisplayWidth) { displayWidth = minDisplayWidth; } + availableWidth -= displayWidth; + availableWidth -= horizontal; + + // Increment the maximum number of displayable headers. + max++; + + // If the available width is depleted, exit the loop. + if(availableWidth <= 0) { break idealLoop; } + } + + // If the maximum displayable number is either 1 or equal to + // actual number, the fields should be displayed with their + // preferred widths. + if(max == 1 || max == headerList.size()) { + // Track the current position on the component. + int curX = horizontal; + int curY = vertical; + + // Add each field. + for(int index = 0; index < headerList.size(); index++) { + // Get the current header and display label. + JLabel header = headerList.get(index); + JLabel display = displayList.get(index); + + // Set the label sizes to the preferred size. + header.setSize(header.getPreferredSize()); + display.setSize(display.getPreferredSize()); + + // Set the label locations to the current correct place. + header.setLocation(curX, curY); + header.setSize(header.getPreferredSize()); + curX += header.getSize().width + horizontal; + display.setLocation(curX, curY); + display.setSize(header.getPreferredSize()); + curX += display.getWidth() + horizontal; + } + + // The process is finished, so return. + return; + } + + // Otherwise, the labels in subsequent rows must be analyzed + // to determine what the actual maximum number of labels per + // row can be used. Try the ideal maximum first and work down + // from there to the minimum of one per row. + else { + // Track the number of columns needed and the proper widths + // of each column. + int columns = 1; + int[] columnWidth = { 0 }; + actualLoop: + for(int actual = max; actual > 0; actual--) { + // Store the actual necessary width for each component in + // each column for the current row size. + int[] actualColWidth = new int[actual + actual]; + + // Track the current column. + int curCol = 0; + + // Iterate over the labels and find the largest necessary + // width for each column. + for(int index = 0; index < headerList.size(); index++) { + // Get the widths needed for the current header and + // display labels. + int headerWidth = headerList.get(index).getPreferredSize().width; + int displayWidth = displayList.get(index).getPreferredSize().width; + if(displayWidth < minDisplayWidth) { displayWidth = minDisplayWidth; } + + // If the needed widths exceed the current maximum, they + // should replace it. + if(actualColWidth[2 * curCol] < headerWidth) { actualColWidth[2 * curCol] = headerWidth; } + if(actualColWidth[(2 * curCol) + 1] < displayWidth) { actualColWidth[(2 * curCol) + 1] = displayWidth; } + + // Increment the current column. + curCol++; + if(curCol == actual) { curCol = 0; } + } + + // Check if the actual needed width is less than the width + // available for the labels. + availableWidth = getWidth() - horizontal; + for(int width : actualColWidth) { + availableWidth -= width; + availableWidth -= horizontal; + } + + // Store the results for this number of columns. + columns = actual; + columnWidth = actualColWidth; + + // If the result is either zero of positive, then there is + // enough space available and the current number of columns + // may be employed. Otherwise, continue to the next smaller + // number of columns. + if(availableWidth >= 0) { break actualLoop; } + } + + // The necessary width for each column and the number of columns + // should now be calculated. Set the constituent component + // positions and sizes to match it. + int curX = horizontal; + int curY = vertical; + int curCol = 0; + for(int index = 0; index < headerList.size(); index++) { + // Get the current header and display label. + JLabel header = headerList.get(index); + JLabel display = displayList.get(index); + + // Set the label sizes to the preferred size. + header.setSize(header.getPreferredSize()); + display.setSize(display.getPreferredSize()); + + // Set the label locations to the current correct place. + header.setLocation(curX, curY); + header.setSize(columnWidth[2 * curCol], header.getPreferredSize().height); + curX += header.getSize().width + horizontal; + display.setLocation(curX, curY); + display.setSize(columnWidth[(2 * curCol) + 1], display.getPreferredSize().height); + curX += display.getWidth() + horizontal; + + // Increment the current column index. + curCol++; + if(curCol == columns) { + curCol = 0; + curY += header.getPreferredSize().height + vertical; + curX = horizontal; + } + } + } + + // Update the preferred size such that the preferred height will + // encompass all of the rows. + JLabel lastHeader = headerList.get(headerList.size() - 1); + int preferredHeight = lastHeader.getY() + lastHeader.getHeight() + vertical; + actualPreferred = new Dimension(getSize().width, preferredHeight); + } + + /** + * Throws an <code>IndexOutOfBoundsException</code> if the argument + * index is not a valid field index. This is used to validate the + * index given in methods requiring one. + * @param index - The index to validate. + * @throws IndexOutOfBoundsException Occurs if the index fails + * to validate. + */ + private void validateFieldIndex(int index) throws IndexOutOfBoundsException { + if(index < 0 || index >= headerList.size()) { + throw new IndexOutOfBoundsException(String.format("Index %d is not a valid field index.", index)); + } + } +} Modified: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/StatusPanel.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/StatusPanel.java (original) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/StatusPanel.java Sat Nov 1 02:29:56 2014 @@ -9,188 +9,180 @@ /** * Class <code>StatusPanel</code> displays text in a set of fields. + * This class is being phased out in favor of <code>ResizableFieldPanel + * </code> and should no longer be used. It will be removed next update. * * @author Kyle McCarty */ +@Deprecated public class StatusPanel extends JPanel { - private static final long serialVersionUID = -8353479383875379010L; - // The panel that displays behind the status field. - private BackPanel background = new BackPanel(); - // The status fields. The first array index represents which status - // field and the second is always of size two, with index 0 mapping - // to the label that displays the field name and index 1 mapping to - // the label displaying the field value. - private JLabel[][] field; - // Spacing variables for panel layout. - private int leftBuffer = 10; - private int upperBuffer = 10; - - /** - * <b>NULL_VALUE</b><br/><br/> - * <code><b>static final String <b>NULL_VALUE</b></code><br/><br/> - * A <code>String</code> representing the default value to be - * displayed on the status panel whenever there is no value for - * that field. - */ - static final String NULL_VALUE = "---"; - - /** - * <b>StatusPanel</b><br/><br/> - * <code>public <b>StatusPanel</b>(String... fieldName)</code><br/><br/> - * Creates a new status panel with display fields with the indicated - * names. They will be assigned a field index in the order that they - * are given starting with zero. - * @param fieldName - The names of the fields to display. - */ - public StatusPanel(String... fieldName) { - // Initialize the component. - super(); - - // Set the layout manager to manual. - setLayout(null); - - // Build the text fields. - int curZ = 0; - field = new JLabel[fieldName.length][2]; - for(int i = 0; i < field.length; i++) { - for(int j = 0; j < field[i].length; j++) { - field[i][j] = new JLabel(); - field[i][j].setOpaque(true); - field[i][j].setBackground(Color.WHITE); - add(field[i][j]); - setComponentZOrder(field[i][j], curZ); - curZ++; - } - field[i][0].setText(fieldName[i] + ": "); - field[i][0].setHorizontalAlignment(JLabel.RIGHT); - } - - // Start the fields as null by default. - clearValues(); - - // Build the background panel. - add(background); - setComponentZOrder(background, curZ); - } - - /** - * <b>clearValues</b><br/><br/> - * <code>public void <b>clearValues</b>()</code><br/><br/> - * Sets all of the fields on the status display to the null value. - */ - public void clearValues() { - for(int i = 0; i < field.length; i++) { - field[i][1].setText(NULL_VALUE); - } - } - - /** - * <b>setFieldValue</b><br/><br/> - * Sets the value of the indicated field. - * @param index - The field's index. - * @param value - The new value to display. - * @throws IndexOutOfBoundsException Occurs when the field index - * is neither more than the existing number of fields or is negative. - */ - public void setFieldValue(int index, String value) throws IndexOutOfBoundsException { - if(index >= 0 && index < field.length) { - if(value == null) { field[index][1].setText(NULL_VALUE); } - else { field[index][1].setText(value); } - } - else { throw new IndexOutOfBoundsException("Invalid field index."); } - } - - public void setSize(int width, int height) { - super.setSize(width, height); - resize(); - } - - public void setSize(Dimension d) { - super.setSize(d); - resize(); - } - - /** - *<b>getNextX</b><br/><br/> - * <code>private int <b>getNextX</b>(Component c)</code><br/><br/> - * Finds the x-coordinate immediately after the component. - * @param c - The component of which to find the end. - * @return Returns the x-coordinate at the end of the component. - */ - private final static int getNextX(Component c) { return getNextX(c, 0); } - - /** - /** - *<b>getNextX</b><br/><br/> - * <code>private int <b>getNextX</b>(Component c, int buffer)</code><br/><br/> - * Finds the x-coordinate after the component with a given buffer. - * @param c - The component of which to find the end. - * @param buffer - The extra space after the component to be included. - * @return Returns the x-coordinate at the end of the component, - * with a buffer length. - */ - private final static int getNextX(Component c, int buffer) { - return c.getX() + c.getWidth() + buffer; - } - - /** - * <b>resize</b><br/><br/> - * <code>private void <b>resize</b>()</code><br/><br/> - * Updates the layout of the component to the panel's current size. - */ - private void resize() { - // Define the width an height as convenience variables. - int width = getWidth(); - int height = getHeight(); - - // Size the background panel. - background.setBounds(0, 0, width, height); - - // Size and place the text labels. - if(field.length != 0) { - int labelHeight = (height - (int)(upperBuffer + 5)) / 3; - int labelRem = (height - upperBuffer - 8) % field.length; - int curX = leftBuffer; - int curY = (int)(upperBuffer + 2); - for(int i = 0; i < field.length; i++) { - // Determine the appropriate field height. - int thisHeight = labelHeight; - if(labelRem > 0) { - thisHeight++; - labelRem--; - } - - // Place the field. - field[i][0].setBounds(curX, curY, 130, thisHeight); - field[i][1].setBounds(getNextX(field[i][0]), curY, 75, thisHeight); - - // If we have written three labels, then start a new column. - if(i % 3 == 2) { - curX = getNextX(field[i][1], 10); - curY = (int)(upperBuffer + 2); - } - - // Otherwise just increment the current height. - else { curY += thisHeight; } - } - } - } - - /** - * Class <code>BackPanel</code> simply renders the background panel - * for the status panel. - */ - private class BackPanel extends JPanel { - private static final long serialVersionUID = 4997805650267243080L; + private static final long serialVersionUID = -8353479383875379010L; + // The panel that displays behind the status field. + private BackPanel background = new BackPanel(); + // The status fields. The first array index represents which status + // field and the second is always of size two, with index 0 mapping + // to the label that displays the field name and index 1 mapping to + // the label displaying the field value. + private JLabel[][] field; + // Spacing variables for panel layout. + private int leftBuffer = 10; + private int upperBuffer = 10; + + /** + * A <code>String</code> representing the default value to be + * displayed on the status panel whenever there is no value for + * that field. + */ + static final String NULL_VALUE = "---"; + + /** + * Creates a new status panel with display fields with the indicated + * names. They will be assigned a field index in the order that they + * are given starting with zero. + * @param fieldName - The names of the fields to display. + */ + public StatusPanel(String... fieldName) { + // Initialize the component. + super(); + + // Set the layout manager to manual. + setLayout(null); + + // Build the text fields. + int curZ = 0; + field = new JLabel[fieldName.length][2]; + for(int i = 0; i < field.length; i++) { + for(int j = 0; j < field[i].length; j++) { + field[i][j] = new JLabel(); + field[i][j].setOpaque(true); + field[i][j].setBackground(Color.WHITE); + add(field[i][j]); + setComponentZOrder(field[i][j], curZ); + curZ++; + } + field[i][0].setText(fieldName[i] + ": "); + field[i][0].setHorizontalAlignment(JLabel.RIGHT); + } + + // Start the fields as null by default. + clearValues(); + + // Build the background panel. + add(background); + setComponentZOrder(background, curZ); + } + + /** + * Sets all of the fields on the status display to the null value. + */ + public void clearValues() { + for(int i = 0; i < field.length; i++) { + field[i][1].setText(NULL_VALUE); + } + } + + /** + * Sets the value of the indicated field. + * @param index - The field's index. + * @param value - The new value to display. + * @throws IndexOutOfBoundsException Occurs when the field index + * is neither more than the existing number of fields or is negative. + */ + public void setFieldValue(int index, String value) throws IndexOutOfBoundsException { + if(index >= 0 && index < field.length) { + if(value == null) { field[index][1].setText(NULL_VALUE); } + else { field[index][1].setText(value); } + } + else { throw new IndexOutOfBoundsException("Invalid field index."); } + } + + @Override + public void setSize(int width, int height) { + super.setSize(width, height); + resize(); + } + + @Override + public void setSize(Dimension d) { + super.setSize(d); + resize(); + } + + /** + * Finds the x-coordinate immediately after the component. + * @param c - The component of which to find the end. + * @return Returns the x-coordinate at the end of the component. + */ + private final static int getNextX(Component c) { return getNextX(c, 0); } + + /** + /** + * Finds the x-coordinate after the component with a given buffer. + * @param c - The component of which to find the end. + * @param buffer - The extra space after the component to be included. + * @return Returns the x-coordinate at the end of the component, + * with a buffer length. + */ + private final static int getNextX(Component c, int buffer) { + return c.getX() + c.getWidth() + buffer; + } + + /** + * Updates the layout of the component to the panel's current size. + */ + private void resize() { + // Define the width an height as convenience variables. + int width = getWidth(); + int height = getHeight(); + + // Size the background panel. + background.setBounds(0, 0, width, height); + + // Size and place the text labels. + if(field.length != 0) { + int labelHeight = (height - (int)(upperBuffer + 5)) / 3; + int labelRem = (height - upperBuffer - 8) % field.length; + int curX = leftBuffer; + int curY = (int)(upperBuffer + 2); + for(int i = 0; i < field.length; i++) { + // Determine the appropriate field height. + int thisHeight = labelHeight; + if(labelRem > 0) { + thisHeight++; + labelRem--; + } + + // Place the field. + field[i][0].setBounds(curX, curY, 130, thisHeight); + field[i][1].setBounds(getNextX(field[i][0]), curY, 75, thisHeight); + + // If we have written three labels, then start a new column. + if(i % 3 == 2) { + curX = getNextX(field[i][1], 10); + curY = (int)(upperBuffer + 2); + } + + // Otherwise just increment the current height. + else { curY += thisHeight; } + } + } + } + + /** + * Class <code>BackPanel</code> simply renders the background panel + * for the status panel. + */ + private class BackPanel extends JPanel { + private static final long serialVersionUID = 4997805650267243080L; - public void paint(Graphics g) { - // Render the panel background. - g.setColor(Color.WHITE); - g.fillRect(0, upperBuffer, getWidth(), getHeight() - upperBuffer); - g.setColor(Color.GRAY); - g.drawRect(0, upperBuffer, getWidth() - 1, getHeight() - upperBuffer - 1); - g.setColor(Color.LIGHT_GRAY); - g.drawRect(1, upperBuffer + 1, getWidth() - 3, getHeight() - upperBuffer - 3); - } - } + public void paint(Graphics g) { + // Render the panel background. + g.setColor(Color.WHITE); + g.fillRect(0, upperBuffer, getWidth(), getHeight() - upperBuffer); + g.setColor(Color.GRAY); + g.drawRect(0, upperBuffer, getWidth() - 1, getHeight() - upperBuffer - 1); + g.setColor(Color.LIGHT_GRAY); + g.drawRect(1, upperBuffer + 1, getWidth() - 3, getHeight() - upperBuffer - 3); + } + } } Modified: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/Viewer.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/Viewer.java (original) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/ui/Viewer.java Sat Nov 1 02:29:56 2014 @@ -11,6 +11,7 @@ import java.text.DecimalFormat; import java.util.ArrayList; import java.util.HashMap; +import java.util.Map; import java.util.NoSuchElementException; import javax.swing.JFrame; @@ -30,7 +31,7 @@ // Java-suggested variable. private static final long serialVersionUID = -2022819652687941812L; // A map of field names to field indices. - private final HashMap<String, Integer> fieldMap = new HashMap<String, Integer>(); + private Map<String, Integer> fieldMap = new HashMap<String, Integer>(); // A list of crystal listeners attached to the viewer. private ArrayList<CrystalListener> listenerList = new ArrayList<CrystalListener>(); // The default field names. @@ -41,33 +42,25 @@ private static final int CELL_VALUE = 2; /** - * <b><statusPanel/b><br/><br/> - * <code>protected final StatusPanel <b>statusPanel</b></code><br/><br/> * The component responsible for displaying status information * about the currently selected crystal. */ - protected final StatusPanel statusPanel; - - /** - * <b>ecalPanel</b><br/><br/> - * <code>protected final CalorimeterPanel <b>ecalPanel</b></code><br/><br/> + protected final ResizableFieldPanel statusPanel; + + /** * The panel displaying the calorimeter crystals and scale. */ protected final CalorimeterPanel ecalPanel = new CalorimeterPanel(46, 11); - - /** - * <b>HIGHLIGHT_CLUSTER_COMPONENT</b><br/><br/> - * <code>public static final Color <b>HIGHLIGHT_CLUSTER_COMPONENT</b></code><br/><br/> + + /** * The default color for highlighting cluster components. */ - public static final Color HIGHLIGHT_CLUSTER_COMPONENT = Color.RED; - - /** - * <b>HIGHLIGHT_CLUSTER_SHARED</b><br/><br/> - * <code>public static final Color <b>HIGHLIGHT_CLUSTER_SHARED</b></code><br/><br/> + public static final Color HIGHLIGHT_CLUSTER_COMPONENT = Color.RED; + + /** * The default color for highlighting cluster shared hits. - */ - public static final Color HIGHLIGHT_CLUSTER_SHARED = Color.YELLOW; + */ + public static final Color HIGHLIGHT_CLUSTER_SHARED = Color.YELLOW; /** * Initializes the viewer window and calorimeter panel. @@ -76,29 +69,20 @@ * @throws NullPointerException Occurs if any of the additional field * arguments are <code>null</code>. **/ - public Viewer(String... statusFields) throws NullPointerException { + public Viewer() throws NullPointerException { // Initialize the underlying JPanel. super(); - // Define the status panel fields and map them to indices. - String[] fields = new String[statusFields.length + defaultFields.length]; - for(int i = 0; i < defaultFields.length; i++) { - fields[i] = defaultFields[i]; - fieldMap.put(defaultFields[i], i); - } - for(int i = 0; i < statusFields.length; i++) { - int index = i + defaultFields.length; - fields[index] = statusFields[i]; - fieldMap.put(statusFields[i], index); - } - // Generate the status panel. - statusPanel = new StatusPanel(fields); + statusPanel = new ResizableFieldPanel(100); + statusPanel.setBackground(Color.WHITE); + + // Add the default fields. + for(String field : defaultFields) { addStatusField(field); } // Set the scaling settings. - ecalPanel.setScaleMinimum(0.00001); - ecalPanel.setScaleMaximum(3); - // ecalPanel.setScalingLogarithmic(); + ecalPanel.setScaleMinimum(0.001); + ecalPanel.setScaleMaximum(3.0); ecalPanel.setScalingLinear(); // Disable the crystals in the calorimeter panel along the beam gap. @@ -137,7 +121,28 @@ * @param cl - The listener to add. */ public void addCrystalListener(CrystalListener cl) { - if(cl != null) { listenerList.add(cl); } + if(cl != null) { listenerList.add(cl); } + } + + /** + * Adds a new field to the status panel. + * @param fieldName - The name to display for the field and that + * links to the field when calling <code>setStatusField</code>. + */ + protected void addStatusField(String fieldName) { + fieldMap.put(fieldName, statusPanel.getFieldCount()); + statusPanel.addField(fieldName); + } + + /** + * Inserts the field at the indicated location on the status panel. + * @param index - The index at which to insert the field. + * @param fieldName - The name to display for the field and that + * links to the field when calling <code>setStatusField</code>. + */ + protected void insertStatusField(int index, String fieldName) { + statusPanel.insertField(index, fieldName); + fieldMap = statusPanel.getFieldNameIndexMap(); } /** @@ -147,14 +152,14 @@ * @return Returns the coordinate pair in LCSim's coordinate system * as an <code>int</code>. **/ - public static final Point toEcalPoint(Point panelPoint) { - // Convert the point coordinates. - int ix = toEcalX(panelPoint.x); - int iy = toEcalY(panelPoint.y); - - // Return the new point. - return new Point(ix, iy); - } + public static final Point toEcalPoint(Point panelPoint) { + // Convert the point coordinates. + int ix = toEcalX(panelPoint.x); + int iy = toEcalY(panelPoint.y); + + // Return the new point. + return new Point(ix, iy); + } /** * Converts the panel x-coordinate to the calorimeter's @@ -164,8 +169,8 @@ * coordinate system as an <code>int</code>. */ public static final int toEcalX(int panelX) { - if(panelX > 22) { return panelX - 22; } - else { return panelX - 23; } + if(panelX > 22) { return panelX - 22; } + else { return panelX - 23; } } /** @@ -184,14 +189,14 @@ * @return Returns the coordinate pair in the calorimeter panel's * coordinate system as an <code>int</code>. **/ - public static final Point toPanelPoint(Point ecalPoint) { - // Convert the point coordinates. - int ix = toPanelX(ecalPoint.x); - int iy = toPanelY(ecalPoint.y); - - // Return the new point. - return new Point(ix, iy); - } + public static final Point toPanelPoint(Point ecalPoint) { + // Convert the point coordinates. + int ix = toPanelX(ecalPoint.x); + int iy = toPanelY(ecalPoint.y); + + // Return the new point. + return new Point(ix, iy); + } /** * Converts the LCSim x-coordinate to the calorimeter panel's @@ -238,7 +243,7 @@ * @param cl - The listener to remove. */ public void removeCrystalListener(CrystalListener cl) { - if(cl != null) { listenerList.remove(cl); } + if(cl != null) { listenerList.remove(cl); } } public void setSize(int width, int height) { @@ -259,44 +264,46 @@ * is provided for argument <code>fieldName</code>. */ public final void setStatusField(String fieldName, String value) throws NoSuchElementException { - // Get the index for the indicated field. - Integer index = fieldMap.get(fieldName); - - // If it is null, the field does not exist. - if(index == null) { throw new NoSuchElementException("Field \"" + fieldName + "\" does not exist."); } - - // Otherwise, set the field. - else { statusPanel.setFieldValue(index, value); } - } - - /** - * Updates the information on the status panel to match that of - * the calorimeter panel's currently selected crystal. - */ - protected void updateStatusPanel() { - // Get the currently selected crystal. - Point crystal = ecalPanel.getSelectedCrystal(); - - // If the crystal is null, there is no selection. - if(crystal == null || ecalPanel.isCrystalDisabled(crystal.x, crystal.y)) { statusPanel.clearValues(); } - - // Otherwise, write the crystal's data to the panel. - else { - setStatusField(defaultFields[X_INDEX], String.valueOf(toEcalX(crystal.x))); - setStatusField(defaultFields[Y_INDEX], String.valueOf(toEcalY(crystal.y))); - DecimalFormat formatter = new DecimalFormat("0.####E0"); - String energy = formatter.format(ecalPanel.getCrystalEnergy(crystal.x, crystal.y)); - setStatusField(defaultFields[CELL_VALUE], energy); - } - } + // Get the index for the indicated field. + Integer index = fieldMap.get(fieldName); + + // If it is null, the field does not exist. + if(index == null) { throw new NoSuchElementException("Field \"" + fieldName + "\" does not exist."); } + + // Otherwise, set the field. + else { statusPanel.setFieldValue(index, value); } + } + + /** + * Updates the information on the status panel to match that of + * the calorimeter panel's currently selected crystal. + */ + protected void updateStatusPanel() { + // Get the currently selected crystal. + Point crystal = ecalPanel.getSelectedCrystal(); + + // If the crystal is null, there is no selection. + if(crystal == null || ecalPanel.isCrystalDisabled(crystal.x, crystal.y)) { + statusPanel.clearFields(); + } + + // Otherwise, write the crystal's data to the panel. + else { + setStatusField(defaultFields[X_INDEX], String.valueOf(toEcalX(crystal.x))); + setStatusField(defaultFields[Y_INDEX], String.valueOf(toEcalY(crystal.y))); + DecimalFormat formatter = new DecimalFormat("0.####E0"); + String energy = formatter.format(ecalPanel.getCrystalEnergy(crystal.x, crystal.y)); + setStatusField(defaultFields[CELL_VALUE], energy); + } + } /** * Handles proper resizing of the window and its components. **/ private void resize() { - // Define the size constants. - int statusHeight = 125; - + // Define the size constants. + int statusHeight = 125; + // Size and position the calorimeter display. ecalPanel.setLocation(0, 0); ecalPanel.setSize(getContentPane().getWidth(), getContentPane().getHeight() - statusHeight); @@ -312,30 +319,30 @@ * It also triggers crystal click events. */ private class EcalMouseListener implements MouseListener { - public void mouseClicked(MouseEvent e) { - // If there is a selected crystal, trigger a crystal click event. - if(ecalPanel.getSelectedCrystal() != null) { - // Get the selected crystal. - Point crystal = ecalPanel.getSelectedCrystal(); - - // Construct a crystal event. - CrystalEvent ce = new CrystalEvent(Viewer.this, crystal); - - // Loop through all the crystal listeners and trigger them. - for(CrystalListener cl : listenerList) { cl.crystalClicked(ce); } - } - } - - public void mouseEntered(MouseEvent e) { } - - public void mouseExited(MouseEvent e) { - ecalPanel.clearSelectedCrystal(); - statusPanel.clearValues(); - } - - public void mousePressed(MouseEvent e) { } - - public void mouseReleased(MouseEvent e) { } + public void mouseClicked(MouseEvent e) { + // If there is a selected crystal, trigger a crystal click event. + if(ecalPanel.getSelectedCrystal() != null) { + // Get the selected crystal. + Point crystal = ecalPanel.getSelectedCrystal(); + + // Construct a crystal event. + CrystalEvent ce = new CrystalEvent(Viewer.this, crystal); + + // Loop through all the crystal listeners and trigger them. + for(CrystalListener cl : listenerList) { cl.crystalClicked(ce); } + } + } + + public void mouseEntered(MouseEvent e) { } + + public void mouseExited(MouseEvent e) { + ecalPanel.clearSelectedCrystal(); + statusPanel.clearFields(); + } + + public void mousePressed(MouseEvent e) { } + + public void mouseReleased(MouseEvent e) { } } /** @@ -344,80 +351,80 @@ * mouse moves over the window. Additionally triggers crystal * activation and deactivation events. */ - private class EcalMouseMotionListener implements MouseMotionListener { - public void mouseDragged(MouseEvent arg0) { } - - public void mouseMoved(MouseEvent e) { - // Get the panel coordinates. - int x = e.getX(); - int y = e.getY(); - - // Get the crystal index for these coordinates. - Point crystal = ecalPanel.getCrystalID(x, y); - - // If either of the crystal indices are negative, then - // the mouse is not in a crystal and the selection should - // be cleared. - boolean validCrystal = (crystal != null); - - // Get the currently selected calorimeter crystal. - Point curCrystal = ecalPanel.getSelectedCrystal(); - - // Perform event comparison checks. - boolean[] nullCrystal = { !validCrystal, curCrystal == null }; - boolean[] disabledCrystal = { true, true }; - if(!nullCrystal[0]) { disabledCrystal[0] = ecalPanel.isCrystalDisabled(crystal); } - if(!nullCrystal[1]) { disabledCrystal[1] = ecalPanel.isCrystalDisabled(curCrystal); } - boolean sameCrystal = true; - if(validCrystal) { sameCrystal = crystal.equals(curCrystal); } - - // If the crystals are the same, there are no events to throw. - if(!sameCrystal) { - // If the new crystal is non-null and enabled, throw an event. - if(!nullCrystal[0] && !disabledCrystal[0]) { throwActivationEvent(crystal); } - - // If the old crystal is non-null and enabled, throw an event. - if(!nullCrystal[1] && !disabledCrystal[1]) { throwDeactivationEvent(curCrystal); } - } - - // If the crystal is valid, then set the selected crystal - // to the current one. - if(validCrystal) { ecalPanel.setSelectedCrystal(crystal); } - - // Otherwise, clear the selection. - else { ecalPanel.clearSelectedCrystal(); } - - // Update the status panel. - updateStatusPanel(); - } - - /** - * Triggers crystal activation events on all listeners for - * this component. - * @param activatedCrystal - The panel coordinates for the - * activated crystal. - */ - private void throwActivationEvent(Point activatedCrystal) { - // Create a crystal event. - CrystalEvent ce = new CrystalEvent(Viewer.this, activatedCrystal); - - // Throw the event with every listener. - for(CrystalListener cl : listenerList) { cl.crystalActivated(ce); } - } - - /** - * Triggers crystal deactivation events on all listeners for - * this component. - * @param deactivatedCrystal - The panel coordinates for the - * deactivated crystal. - */ - private void throwDeactivationEvent(Point deactivatedCrystal) { - // Create a crystal event. - CrystalEvent ce = new CrystalEvent(Viewer.this, deactivatedCrystal); - - // Throw the event with every listener. - for(CrystalListener cl : listenerList) { cl.crystalDeactivated(ce); } - } + private class EcalMouseMotionListener implements MouseMotionListener { + public void mouseDragged(MouseEvent arg0) { } + + public void mouseMoved(MouseEvent e) { + // Get the panel coordinates. + int x = e.getX(); + int y = e.getY(); + + // Get the crystal index for these coordinates. + Point crystal = ecalPanel.getCrystalID(x, y); + + // If either of the crystal indices are negative, then + // the mouse is not in a crystal and the selection should + // be cleared. + boolean validCrystal = (crystal != null); + + // Get the currently selected calorimeter crystal. + Point curCrystal = ecalPanel.getSelectedCrystal(); + + // Perform event comparison checks. + boolean[] nullCrystal = { !validCrystal, curCrystal == null }; + boolean[] disabledCrystal = { true, true }; + if(!nullCrystal[0]) { disabledCrystal[0] = ecalPanel.isCrystalDisabled(crystal); } + if(!nullCrystal[1]) { disabledCrystal[1] = ecalPanel.isCrystalDisabled(curCrystal); } + boolean sameCrystal = true; + if(validCrystal) { sameCrystal = crystal.equals(curCrystal); } + + // If the crystals are the same, there are no events to throw. + if(!sameCrystal) { + // If the new crystal is non-null and enabled, throw an event. + if(!nullCrystal[0] && !disabledCrystal[0]) { throwActivationEvent(crystal); } + + // If the old crystal is non-null and enabled, throw an event. + if(!nullCrystal[1] && !disabledCrystal[1]) { throwDeactivationEvent(curCrystal); } + } + + // If the crystal is valid, then set the selected crystal + // to the current one. + if(validCrystal) { ecalPanel.setSelectedCrystal(crystal); } + + // Otherwise, clear the selection. + else { ecalPanel.clearSelectedCrystal(); } + + // Update the status panel. + updateStatusPanel(); + } + + /** + * Triggers crystal activation events on all listeners for + * this component. + * @param activatedCrystal - The panel coordinates for the + * activated crystal. + */ + private void throwActivationEvent(Point activatedCrystal) { + // Create a crystal event. + CrystalEvent ce = new CrystalEvent(Viewer.this, activatedCrystal); + + // Throw the event with every listener. + for(CrystalListener cl : listenerList) { cl.crystalActivated(ce); } + } + + /** + * Triggers crystal deactivation events on all listeners for + * this component. + * @param deactivatedCrystal - The panel coordinates for the + * deactivated crystal. + */ + private void throwDeactivationEvent(Point deactivatedCrystal) { + // Create a crystal event. + CrystalEvent ce = new CrystalEvent(Viewer.this, deactivatedCrystal); + + // Throw the event with every listener. + for(CrystalListener cl : listenerList) { cl.crystalDeactivated(ce); } + } } /** Added: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/util/CrystalDataSet.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/util/CrystalDataSet.java (added) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/util/CrystalDataSet.java Sat Nov 1 02:29:56 2014 @@ -0,0 +1,213 @@ +package org.hps.monitoring.ecal.eventdisplay.util; + +import java.awt.Point; + +/** + * Class <code>CrystalDataSet</code> contains all of the hardware data + * for a single calorimeter crystal as defined in the crystal hardware + * reference sheet. + * + * @author Kyle McCarty + */ +public class CrystalDataSet { + // Data points. + private final Point crystalIndex; + private final short apd; + private final PreamplifierNumber preamp; + private final short ledChannel; + private final byte[] ledDriver; + private final byte fadcSlot; + private final byte fadcChannel; + private final byte splitterNum; + private final byte hvGroup; + private final byte jout; + private final String mb; + private final short channel; + private final int gain; + + /** + * Defines the data set. + * @param ix - The crystal's x-index in the LCSimcoordinate system. + * @param iy - The crystal's y-index in the LCSimcoordinate system. + * @param apd - The number of the APD attached to the crystal. + * @param preamp - The number of the crystal's premaplifier. This + * may also include a reference wire color. + * @param ledChannel - The channel number for the crystal's LED. + * @param ledDriver + * @param fadcSlot - The FADC slot the crystal occupies. + * @param fadcChannel - The channel number through which the crystal + * communicates with the FADC. + * @param splitter + * @param hvGroup - The high voltage group for which the crystal + * is a member. + * @param jout + * @param mb + * @param channel + * @param gain - The crystal's gain. + */ + public CrystalDataSet(int ix, int iy, int apd, String preamp, int ledChannel, + double ledDriver, int fadcSlot, int fadcChannel, int splitter, int hvGroup, + int jout, String mb, int channel, int gain) { + // Define crystal indices. + crystalIndex = new Point(ix, iy); + + // Define the general properties. + this.apd = (short) apd; + this.ledChannel = (short) ledChannel; + this.fadcSlot = (byte) fadcSlot; + this.fadcChannel = (byte) fadcChannel; + this.splitterNum = (byte) splitter; + this.hvGroup = (byte) hvGroup; + this.jout = (byte) jout; + this.channel = (short) channel; + this.gain = gain; + this.mb = mb; + + // Define the LED driver. + this.ledDriver = new byte[2]; + this.ledDriver[0] = (byte) Math.floor(ledDriver); + this.ledDriver[1] = (byte) ((ledDriver - this.ledDriver[0]) * 10); + + // Handle the preamplifier number. + StringBuffer num = new StringBuffer(); + StringBuffer col = new StringBuffer(); + for(char c : preamp.toCharArray()) { + if(Character.isDigit(c)) { num.append(c); } + else { col.append(c); } + } + int number = Integer.parseInt(num.toString()); + String color = null; + if(col.length() != 0) { color = col.toString(); } + this.preamp = new PreamplifierNumber(number, color); + } + + /** + * Gets the crystal's positional indices in the LCSim coordinate + * system. + * @return Returns the crystal's positional indices as a <code> + * Point</code> object. + */ + public Point getCrystalIndex() { return crystalIndex; } + + /** + * Gets the crystal's x-index in the LCSim coordinate system. + * @return Returns the crystal's x-index as an <code>int</code> + * primitive. + */ + public int getCrystalXIndex() { return crystalIndex.x; } + + /** + * Gets the crystal's y-index in the LCSim coordinate system. + * @return Returns the crystal's y-index as an <code>int</code> + * primitive. + */ + public int getCrystalYIndex() { return crystalIndex.y; } + + /** + * Gets the number of the APD attached to the crystal. + * @return Returns the crystal's APD number as an <code>int</code> + * primitive. + */ + public int getAPDNumber() { return apd; } + + /** + * Gets the crystal's preamplifier reference data. + * @return Returns the preamplifier reference as a <code> + * PreamplifierNumber</code> object. + */ + public PreamplifierNumber getPreamplifierNumber() { return preamp; } + + /** + * Gets the crystal's LED channel. + * @return Returns the LED channel as an <code>int</code> primitive. + */ + public int getLEDChannel() { return ledChannel; } + + public double getLEDDriver() { + return ((double) ledDriver[0]) + ((double) ledDriver[1] / 10); + } + + /** + * Gets the crystal's FADC slot. + * @return Returns the FADC slot as an <code>int</code> primitive. + */ + public int getFADCSlot() { return fadcSlot; } + + /** + * Gets the crystal's FADC channel. + * @return Returns the FADC channel as an <code>int</code> primitive. + */ + public int getFADCChannel() { return fadcChannel; } + + public int getSplitterNumber() { return splitterNum; } + + /** + * Gets the crystal's high voltage group. + * @return Returns the high voltage group number as an <code>int + * </code> primitive. + */ + public int getHighVoltageGroup() { return hvGroup; } + + public int getJout() { return jout; } + + public String getMB() { return mb; } + + public int getChannel() { return channel; } + + /** + * Gets the crystal's gain. + * @return Returns the gain as an <code>int</code> primitive. + */ + public int getGain() { return gain; } + + /** + * Class <code>PreamplifierNumber</code> represents the number + * of a crystal's preamplifier. It can also contain a reference + * wire color if necessary. + * + * @author Kyle McCarty + */ + public class PreamplifierNumber { + private final short number; + private final String color; + + /** + * Initializes a preamplifier number with no reference wire + * color. + * @param number - The preamplifier's number. + */ + public PreamplifierNumber(int number) { this(number, null); } + + /** + * Initializes a preamplifier number with the specified reference + * wire color. + * @param number - The preamplifier's number. + * @param color - The reference wire color. + */ + public PreamplifierNumber(int number, String color) { + this.number = (short) number; + this.color = color; + } + + /** + * Gets the number of the preamplifier. + * @return Returns the preamplifier number as an <code>int + * </code> primitive. + */ + public int getNumber() { return number; } + + /** + * Gets the reference wire color associated with the crystal's + * preamplifier if it exists. + * @return Returns the reference wire color as a <code>String + * </code> object or <code>null</code> if it does not exist. + */ + public String getColor() { return color; } + + @Override + public String toString() { + if(color == null) { return "" + number; } + else { return number + " (" + color + ")"; } + } + } +} Added: java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/util/EcalWiringManager.java ============================================================================= --- java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/util/EcalWiringManager.java (added) +++ java/trunk/ecal-event-display/src/main/java/org/hps/monitoring/ecal/eventdisplay/util/EcalWiringManager.java Sat Nov 1 02:29:56 2014 @@ -0,0 +1,112 @@ +package org.hps.monitoring.ecal.eventdisplay.util; + +import java.awt.Point; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Scanner; + +/** + * Class <code>EcalWiringManager</code> reads in the crystal hardware + * data sheet for the calorimeter and stores the data in <code> + * CrystalDataSet</code> objects for access and reference by the <code> + * Viewer</code> classes. Crystal LCSim indices are mapped to the data + * set that corresponds to that crystal. + * + * @author Kyle McCarty + */ +public class EcalWiringManager { + // Delimiter class statics. + public static final int SPACE_DELIMITED = 1; + public static final int TAB_DELIMITED = 2; + public static final int COMMA_DELIMITED = 3; + + // Internal variables. + private Map<Point, CrystalDataSet> crystalMap = new HashMap<Point, CrystalDataSet>(442); + + /** + * Initializes an <code>EcalWiringManager</code> database with + * hardware information loaded from the indicated file. The data + * file is assumed to be comma delimited and the first line is + * assumed to be a header line and to not contain data. + * @param dataFile - The path to the data file. + * @throws IOException Occurs if there is an error opening or parsing + * the data file. + */ + public EcalWiringManager(String dataFile) throws IOException { + this(dataFile, COMMA_DELIMITED, true); + } + + /** + * Initializes an <code>EcalWiringManager</code> database with + * hardware information loaded from the indicated file. + * @param dataFile - The path to the data file. + * @param delimiter - The delimiter used by the data file. + * @param skipFirstLine - Whether the first line should be skipped. + * @throws IOException Occurs if there is an error opening or parsing + * the data file. + */ + public EcalWiringManager(String dataFile, int delimiter, boolean skipFirstLine) throws IOException { + // Create a file reader. + FileReader baseReader = new FileReader(dataFile); + BufferedReader reader = new BufferedReader(baseReader); + + // If the first line should be skipped, do that. + if(skipFirstLine) { reader.readLine(); } + + // Iterate over the lines of the data file. + String curLine = null; + readLoop: + while((curLine = reader.readLine()) != null) { + // If the current line is empty, skip it. + if(curLine.isEmpty()) { continue readLoop; } + + // Create a line scanner. + Scanner lineScan = new Scanner(curLine); + if(delimiter == COMMA_DELIMITED) { lineScan.useDelimiter(","); } + else if(delimiter == SPACE_DELIMITED) { lineScan.useDelimiter(" *"); } + else if(delimiter == TAB_DELIMITED) { lineScan.useDelimiter("\t"); } + + // Get the crystal data values. + int ix = lineScan.nextInt(); + int iy = lineScan.nextInt(); + int apd = lineScan.nextInt(); + String preamp = lineScan.next(); + int ledChan = lineScan.nextInt(); + double ledDriver = lineScan.nextDouble(); + int fadcSlot = lineScan.nextInt(); + int fadcChan = lineScan.nextInt(); + int splitter = lineScan.nextInt(); + int hvGroup = lineScan.nextInt(); + int jout = lineScan.nextInt(); + String mb = lineScan.next(); + int channel = lineScan.nextInt(); + int gain = lineScan.nextInt(); + lineScan.close(); + + // Create a crystal data set in which to store the data. + CrystalDataSet cds = new CrystalDataSet(ix, iy, apd, preamp, ledChan, ledDriver, fadcSlot, + fadcChan, splitter, hvGroup, jout, mb, channel, gain); + + // Map the crystal index to the crystal data set. + crystalMap.put(cds.getCrystalIndex(), cds); + } + + // Close the readers. + reader.close(); + baseReader.close(); + } + + /** + * Gets the set of calorimeter hardware data associated with the + * crystal at the given index. + * @param crystalIndex - The index of the crystal for which to obtain + * the hardware information. This should be in LCSim coordinates. + * @return Returns the hardware information for the crystal as a + * <code>CrystalDataSet</code> object or returns <code>null</code> + * if the crystal index is invalid. + */ + public CrystalDataSet getCrystalData(Point crystalIndex) { return crystalMap.get(crystalIndex); } +}