Author: [log in to unmask] Date: Sun Mar 15 11:31:15 2015 New Revision: 2459 Log: Merge changes from monitoring dev branch into trunk. Added: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java - copied unchanged from r2457, java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsCollectionTableModel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConditionsPanel.java - copied unchanged from r2457, java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/ConditionsPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventDashboard.java - copied unchanged from r2457, java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/EventDashboard.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java - copied unchanged from r2457, java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusEventsTable.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java - copied unchanged from r2457, java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/SystemStatusPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/EtEventFilter.java - copied unchanged from r2457, java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/EtEventFilter.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/MonitoringApplicationEventBuilder.java - copied unchanged from r2457, java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/MonitoringApplicationEventBuilder.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/PhysicsSyncEventStation.java - copied unchanged from r2457, java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/PhysicsSyncEventStation.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/PreStartEtStation.java - copied unchanged from r2457, java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/PreStartEtStation.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/util/RunnableEtStation.java - copied unchanged from r2457, java/branches/monitoring-app-dev/src/main/java/org/hps/monitoring/application/util/RunnableEtStation.java Removed: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/RunPanel.java Modified: java/trunk/monitoring-app/ (props changed) java/trunk/monitoring-app/pom.xml java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventProcessing.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusTable.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/RunModel.java java/trunk/monitoring-app/src/main/resources/org/hps/monitoring/config/default_config.prop Modified: java/trunk/monitoring-app/pom.xml ============================================================================= --- java/trunk/monitoring-app/pom.xml (original) +++ java/trunk/monitoring-app/pom.xml Sun Mar 15 11:31:15 2015 @@ -111,6 +111,10 @@ </dependency> <dependency> <groupId>org.hps</groupId> + <artifactId>hps-ecal-recon</artifactId> + </dependency> + <dependency> + <groupId>org.hps</groupId> <artifactId>hps-monitoring-drivers</artifactId> </dependency> <dependency> @@ -134,6 +138,16 @@ <groupId>org.freehep</groupId> <artifactId>freehep-jaida-remote</artifactId> <version>3.4.11</version> + <exclusions> + <exclusion> + <groupId>org.jdom</groupId> + <artifactId>jdom</artifactId> + </exclusion> + <exclusion> + <groupId>commons-math</groupId> + <artifactId>commons-math</artifactId> + </exclusion> + </exclusions> </dependency> </dependencies> -</project> +</project> Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/Commands.java Sun Mar 15 11:31:15 2015 @@ -34,9 +34,10 @@ // Save a screenshot static final String SAVE_SCREENSHOT = "saveScreenshot"; - // Save the plots + // Plotting actions static final String SAVE_PLOTS = "savePlots"; static final String CLEAR_PLOTS = "resetPlots"; + static final String SAVE_SELECTED_PLOTS = "saveSelectedPlots"; // Exit the application. static final String EXIT = "exit"; Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/ConnectionStatusPanel.java Sun Mar 15 11:31:15 2015 @@ -45,7 +45,6 @@ setMinimumSize(new Dimension(PANEL_WIDTH, PANEL_HEIGHT)); setLayout(new GridBagLayout()); - // setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED)); GridBagConstraints c = new GridBagConstraints(); c.weightx = c.weighty = 1.0; Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventButtonsPanel.java Sun Mar 15 11:31:15 2015 @@ -80,10 +80,19 @@ resumeButton.setEnabled(false); connectButton.setActionCommand(Commands.CONNECT); connectButton.setIcon(disconnectedIcon); - } else { + connectButton.setEnabled(true); + } else if (status.equals(ConnectionStatus.DISCONNECTING)) { + nextButton.setEnabled(false); + pauseButton.setEnabled(false); + resumeButton.setEnabled(false); + connectButton.setEnabled(false); + } else if (status.equals(ConnectionStatus.CONNECTED)) { + nextButton.setEnabled(false); pauseButton.setEnabled(true); + resumeButton.setEnabled(false); connectButton.setActionCommand(Commands.DISCONNECT); connectButton.setIcon(connectedIcon); + connectButton.setEnabled(true); } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventProcessing.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventProcessing.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/EventProcessing.java Sun Mar 15 11:31:15 2015 @@ -4,6 +4,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; @@ -14,6 +15,9 @@ import org.hps.monitoring.application.model.ConnectionStatus; import org.hps.monitoring.application.model.SteeringType; import org.hps.monitoring.application.util.EtSystemUtil; +import org.hps.monitoring.application.util.PhysicsSyncEventStation; +import org.hps.monitoring.application.util.PreStartEtStation; +import org.hps.monitoring.application.util.RunnableEtStation; import org.hps.monitoring.subsys.et.EtSystemMonitor; import org.hps.monitoring.subsys.et.EtSystemStripCharts; import org.hps.record.LCSimEventBuilder; @@ -24,26 +28,30 @@ import org.hps.record.enums.DataSourceType; import org.hps.record.et.EtConnection; import org.hps.record.evio.EvioDetectorConditionsProcessor; +import org.jlab.coda.et.EtSystem; import org.jlab.coda.et.exception.EtClosedException; import org.jlab.coda.et.exception.EtException; +import org.lcsim.conditions.ConditionsListener; import org.lcsim.conditions.ConditionsManager; import org.lcsim.conditions.ConditionsReader; import org.lcsim.util.Driver; /** - * This class encapsulates all of the logic involved with processing events - * and managing the related state and objects within the monitoring application. + * This class encapsulates all of the logic involved with processing events and managing the related + * state and objects within the monitoring application. * * @author Jeremy McCormick <[log in to unmask]> */ class EventProcessing { - + MonitoringApplication application; Logger logger; SessionState sessionState; List<CompositeRecordProcessor> processors; List<Driver> drivers; - + List<ConditionsListener> conditionsListeners; + int stationPosition; + /** * This class is used to organize the objects for an event processing session. */ @@ -53,33 +61,54 @@ CompositeLoop loop; EventProcessingThread processingThread; Thread sessionWatchdogThread; + ThreadGroup stationThreadGroup = new ThreadGroup("Station Threads"); + List<RunnableEtStation> stations = new ArrayList<RunnableEtStation>(); EtConnection connection; } - - /** - * Initialize with reference to the current monitoring application - * and a list of extra processors to add to the loop after - * configuration. + + /** + * Initialize with reference to the current monitoring application and a list of extra + * processors to add to the loop after configuration. * @param application The current monitoring application. * @param processors A list of processors to add after configuration is performed. */ EventProcessing( MonitoringApplication application, - List<CompositeRecordProcessor> processors, - List<Driver> drivers) { + List<CompositeRecordProcessor> processors, + List<Driver> drivers, + List<ConditionsListener> conditionsListeners) { this.application = application; - this.sessionState = new SessionState(); + this.sessionState = new SessionState(); this.logger = MonitoringApplication.logger; this.processors = processors; this.drivers = drivers; + this.conditionsListeners = conditionsListeners; + this.stationPosition = application.configurationModel.getStationPosition(); } + int getNextStationPosition() { + this.stationPosition += 1; + return this.stationPosition; + } + /** * Setup this class from the global configuration. * @param configurationModel The global configuration. */ void setup(ConfigurationModel configurationModel) { - MonitoringApplication.logger.info("setting up LCSim"); + + // Setup LCSim from the configuration. + setupLcsim(configurationModel); + + // Now setup the CompositeLoop. + setupLoop(configurationModel); + } + + /** + * @param configurationModel + */ + private void setupLcsim(ConfigurationModel configurationModel) { + MonitoringApplication.logger.info("setting up lcsim"); // Get steering resource or file as a String parameter. String steering = null; @@ -90,22 +119,31 @@ steering = configurationModel.getSteeringResource(); } - MonitoringApplication.logger.config("Set steering to " + steering + " with type " + (steeringType == SteeringType.RESOURCE ? "RESOURCE" : "FILE")); + MonitoringApplication.logger.config("set steering " + steering + " with type " + (steeringType == SteeringType.RESOURCE ? "RESOURCE" : "FILE")); try { - // Create and the job manager. The conditions manager is instantiated from this call but not configured. + // Create and the job manager. The conditions manager is instantiated from this call but + // not configured. sessionState.jobManager = new JobManager(); - + + // Add conditions listeners after new database conditions manager is initialized from + // job manager. + DatabaseConditionsManager conditionsManager = DatabaseConditionsManager.getInstance(); + for (ConditionsListener conditionsListener : conditionsListeners) { + logger.config("adding conditions listener " + conditionsListener.getClass().getName()); + conditionsManager.addConditionsListener(conditionsListener); + } + if (configurationModel.hasValidProperty(ConfigurationModel.DETECTOR_ALIAS_PROPERTY)) { - // Set a detector alias. + // Set a detector alias. ConditionsReader.addAlias(configurationModel.getDetectorName(), "file://" + configurationModel.getDetectorAlias()); logger.config("using detector alias " + configurationModel.getDetectorAlias()); } - + // Setup the event builder to translate from EVIO to LCIO. // This must happen before Driver setup so the builder's listeners are activated first! createEventBuilder(configurationModel); - + // Configure the job manager for the XML steering. sessionState.jobManager.setPerformDryRun(true); if (steeringType == SteeringType.RESOURCE) { @@ -113,24 +151,23 @@ } else if (steeringType.equals(SteeringType.FILE)) { setupSteeringFile(steering); } - + // Set conditions tag. if (configurationModel.hasValidProperty(ConfigurationModel.CONDITIONS_TAG_PROPERTY) && !configurationModel.getConditionsTag().equals("")) { - logger.config("conditions tag is set to " + configurationModel.getConditionsTag()); + logger.config("conditions tag is set to " + configurationModel.getConditionsTag()); } else { logger.config("conditions NOT using a tag"); } - + // Is there a user specified run number from the JobPanel? if (configurationModel.hasValidProperty(ConfigurationModel.USER_RUN_NUMBER_PROPERTY)) { int userRunNumber = configurationModel.getUserRunNumber(); String detectorName = configurationModel.getDetectorName(); - DatabaseConditionsManager conditionsManager = DatabaseConditionsManager.getInstance(); logger.config("setting user run number " + userRunNumber + " with detector " + detectorName); conditionsManager.setDetector(configurationModel.getDetectorName(), userRunNumber); if (configurationModel.hasPropertyKey(ConfigurationModel.FREEZE_CONDITIONS_PROPERTY)) { - // Freeze the conditions system to ignore run numbers from the events. - logger.config("user configured to freeze conditions system from monitoring app"); + // Freeze the conditions system to ignore run numbers from the events. + logger.config("user configured to freeze conditions system"); conditionsManager.freeze(); } else { // Allow run numbers to be picked up from the events. @@ -142,18 +179,15 @@ logger.info("lcsim setup was successful"); } catch (Throwable t) { - // Catch all errors and rethrow them as RuntimeExceptions. + // Catch all errors and re-throw them as RuntimeExceptions. application.errorHandler.setError(t).setMessage("Error setting up LCSim.").printStackTrace().raiseException(); } - - // Now setup the CompositeLoop. - setupLoop(configurationModel); - } - + } + /** * Create the event builder for converting EVIO events to LCSim. */ - void createEventBuilder(ConfigurationModel configurationModel) { + private void createEventBuilder(ConfigurationModel configurationModel) { // Get the class for the event builder. String eventBuilderClassName = configurationModel.getEventBuilderClassName(); @@ -168,12 +202,12 @@ // Add the builder as a listener so it is notified when conditions change. ConditionsManager.defaultInstance().addConditionsListener(sessionState.eventBuilder); } - + /** * Setup the loop from the global configuration. * @param configurationModel The global configuration. */ - void setupLoop(ConfigurationModel configurationModel) { + private void setupLoop(ConfigurationModel configurationModel) { CompositeLoopConfiguration loopConfig = new CompositeLoopConfiguration() .setStopOnEndRun(configurationModel.getDisconnectOnEndRun()) @@ -187,13 +221,12 @@ if (configurationModel.hasValidProperty(ConfigurationModel.MAX_EVENTS_PROPERTY)) { long maxEvents = configurationModel.getMaxEvents(); if (maxEvents > 0L) { - //logger.config("processing will stop after max events: " + maxEvents); loopConfig.setMaxRecords(maxEvents); } } - + // Add all Drivers from the JobManager. - for (Driver driver : sessionState.jobManager.getDriverExecList()) { + for (Driver driver : sessionState.jobManager.getDriverExecList()) { loopConfig.add(driver); logger.config("added Driver " + driver.getName() + " to job"); } @@ -211,30 +244,30 @@ } // Add extra CompositeRecordProcessors to the loop config. - for (CompositeRecordProcessor processor : processors) { - loopConfig.add(processor); + for (CompositeRecordProcessor processor : processors) { + loopConfig.add(processor); logger.config("added extra processor " + processor.getClass().getSimpleName() + " to job"); } - + // Add extra Drivers to the loop config. - for (Driver driver : drivers) { + for (Driver driver : drivers) { loopConfig.add(driver); logger.config("added extra Driver " + driver.getName() + " to job"); } - - // Enable conditions system activation from EVIO event information. + + // Enable conditions system activation from EVIO event data in case the PRESTART is missed. logger.config("added EvioDetectorConditionsProcessor to job with detector " + configurationModel.getDetectorName()); loopConfig.add(new EvioDetectorConditionsProcessor(configurationModel.getDetectorName())); // Create the CompositeLoop with the configuration. - sessionState.loop = new CompositeLoop(loopConfig); - } - + sessionState.loop = new CompositeLoop(loopConfig); + } + /** * Setup a steering file on disk. * @param steering The steering file. */ - void setupSteeringFile(String steering) { + private void setupSteeringFile(String steering) { sessionState.jobManager.setup(new File(steering)); } @@ -243,83 +276,121 @@ * @param steering The steering resource. * @throws IOException if there is a problem setting up or accessing the resource. */ - void setupSteeringResource(String steering) throws IOException { + private void setupSteeringResource(String steering) throws IOException { InputStream is = this.getClass().getClassLoader().getResourceAsStream(steering); if (is == null) throw new IOException("Steering resource is not accessible or does not exist."); sessionState.jobManager.setup(is); is.close(); } + + synchronized void stop() { + + // Kill session watchdog thread. + killWatchdogThread(); + + // Wake up all ET stations to unblock the system and make sure secondary stations are detached. + wakeUpEtStations(); - synchronized void stop() { - - // Kill session watchdog thread. - logger.fine("killing watchdog thread ..."); - killWatchdogThread(); - logger.fine("watchdog thread killed"); - - // Wake up ET system in case it is blocked in a getEvents() call. - if (sessionState.connection != null) { - try { - logger.fine("waking up ET stations ..."); - sessionState.connection.getEtSystem().wakeUpAll(sessionState.connection.getEtStation()); - logger.fine("ET stations woken up"); - } catch (IOException | EtException | EtClosedException e) { - e.printStackTrace(); - } - } - - // Stop event processing. - logger.fine("commanding event processing to stop ..."); + // Stop the event processing now that ET system is unblocked. + logger.fine("sending STOP command to loop ..."); sessionState.loop.execute(Command.STOP); - logger.fine("event processing commanded to stop"); - - // Cleanup the event processing thread. + logger.fine("loop got command STOP"); + + // Cleanup the event processing thread since it was told to stop now. try { - logger.fine("joining on event processing thread ..."); + logger.fine("waiting for event processing thread to end ..."); sessionState.processingThread.join(); - logger.fine("event processing thread joined"); - - // Invalidate event processing thread. - sessionState.processingThread = null; + logger.fine("event processing thread ended"); } catch (InterruptedException e) { e.printStackTrace(); } - + // Notify of last error that occurred in event processing. if (sessionState.loop.getLastError() != null) { // Log the error. application.errorHandler.setError(sessionState.loop.getLastError()).log(); } + + // Invalidate the loop. + sessionState.loop = null; + + // Disconnect from the ET system. + disconnect(); - // Invalidate loop. - sessionState.loop = null; - - // Disconnect from the ET system. - logger.fine("disconnecting from ET system ..."); - disconnect(); - logger.fine("ET system disconnected"); - } - - /** - * Start event processing on the event processing thread - * and start the watchdog thread. + // Invalidate the event processing object so it is unusable now. + invalidate(); + } + + /** + * Wake up all ET stations associated with event processing. + */ + private void wakeUpEtStations() { + if (sessionState.connection != null) { + logger.fine("waking up ET stations ..."); + + // Wake up secondary ET stations. + for (RunnableEtStation station : sessionState.stations) { + if (station.getEtStation().isUsable()) { + // Wake up the station which will automatically trigger a detach. + try { + logger.finest("waking up " + station.getEtStation().getName() + " ..."); + sessionState.connection.getEtSystem().wakeUpAll(station.getEtStation()); + logger.finest(station.getEtStation().getName() + " woken up"); + } catch (IOException | EtException | EtClosedException e) { + e.printStackTrace(); + } + } + } + + // Wait for station threads to die after being woken up. + while (sessionState.stationThreadGroup.activeCount() != 0) { + logger.finest("waiting for station threads to die ..."); + Object lock = new Object(); + synchronized (lock) { + try { + lock.wait(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + logger.finest("destroying station thread group"); + sessionState.stationThreadGroup.destroy(); + logger.finest("station thread group destroyed"); + + // Wake up the primary ET station doing the event processing. + logger.finest("waking up event processing station ..."); + try { + sessionState.connection.getEtSystem().wakeUpAll(sessionState.connection.getEtStation()); + logger.finest("event processing station woken up"); + } catch (IOException | EtException | EtClosedException e) { + e.printStackTrace(); + } + + logger.finest("ET stations woken up"); + } + } + + /** + * Start event processing on the event processing thread and start the watchdog thread. */ synchronized void start() { - + logger.fine("event processing threads are starting"); - + // Start the event processing thread. sessionState.processingThread = new EventProcessingThread(sessionState.loop); sessionState.processingThread.start(); - + // Start the watchdog thread which will auto-disconnect when event processing is done. sessionState.sessionWatchdogThread = new SessionWatchdogThread(sessionState.processingThread); sessionState.sessionWatchdogThread.start(); - + logger.fine("started event processing threads"); } - + /** * Notify the event processor to pause processing. */ @@ -331,7 +402,7 @@ } logger.finest("paused"); } - + /** * Get next event if in pause mode. */ @@ -344,7 +415,7 @@ } logger.finest("got next event"); } - + /** * Resume processing events from pause mode. */ @@ -352,19 +423,19 @@ logger.finest("resuming"); if (application.connectionModel.getPaused()) { // Notify event processor to continue. - sessionState.loop.resume(); + sessionState.loop.resume(); application.connectionModel.setPaused(false); } logger.finest("resumed"); } - + /** * Interrupt and join to the processing watchdog thread. */ synchronized void killWatchdogThread() { - logger.fine("killing watchdog thread"); // Is the session watchdog thread not null? if (sessionState.sessionWatchdogThread != null) { + logger.finest("killing watchdog thread ..."); // Is the thread still alive? if (sessionState.sessionWatchdogThread.isAlive()) { // Interrupt the thread which should cause it to stop. @@ -379,10 +450,10 @@ } // Set the thread object to null. sessionState.sessionWatchdogThread = null; - } - logger.fine("watchdog thread killed"); - } - + logger.finest("watchdog thread killed"); + } + } + /** * Cleanup the ET connection. */ @@ -390,15 +461,15 @@ if (sessionState.connection != null) { logger.fine("closing ET connection"); if (sessionState.connection.getEtSystem().alive()) { - logger.fine("cleaning up the connection ..."); + logger.finest("cleaning up the connection ..."); sessionState.connection.cleanup(); - logger.fine("connection cleanup successful"); + logger.finest("connection cleanup successful"); } sessionState.connection = null; logger.fine("ET connection closed"); } } - + /** * True if the processing thread is active. * @return True if processing thread is active. @@ -406,71 +477,109 @@ boolean isActive() { return sessionState.processingThread != null && sessionState.processingThread.isAlive(); } - + /** * Connect to the ET system using the current connection settings. */ - synchronized void connect() throws IOException { - logger.fine("connecting to ET system"); + synchronized void connect() throws IOException { // Setup the network connection if using an ET server. if (usingEtServer()) { // Create a connection to the ET server. try { + logger.fine("connecting to ET system ..."); + + // Create the main ET system connection. createEtConnection(); + + // Add an attachment that listens for DAQ configuration changes via physics SYNC events. + createPhysicsSyncStation(); + + // Add an attachment that listens for PRESTART events. + createPreStartStation(); + } catch (Exception e) { throw new IOException(e); } + + logger.fine("ET system is connected"); } else { // This is when a direct file source is used and ET is not needed. application.connectionModel.setConnectionStatus(ConnectionStatus.CONNECTED); } - logger.fine("ET system is connected"); - } - + + } + /** * True if using an ET server. * @return True if using an ET server. */ boolean usingEtServer() { return application.configurationModel.getDataSourceType().equals(DataSourceType.ET_SERVER); - } - - /** - * Create a connection to an ET system using current parameters from the GUI. If successful, the - * application's ConnectionStatus is changed to CONNECTED. - */ - void createEtConnection() { + } + + /** + * Create a connection to an ET system using current parameters from the GUI. + */ + synchronized void createEtConnection() { // Setup connection to ET system. sessionState.connection = EtSystemUtil.createEtConnection(application.configurationModel); if (sessionState.connection != null) { // Set status to connected as there is now a live ET connection. application.connectionModel.setConnectionStatus(ConnectionStatus.CONNECTED); - //logger.info("successfully connected to ET system"); } else { application.errorHandler.setError(new RuntimeException("Failed to create ET connection.")).log().printStackTrace().raiseException(); } } + + /** + * Create the ET that listens for DAQ configuration change via SYNC events. + */ + private void createPhysicsSyncStation() { + logger.fine("creating physics SYNC station ..."); + PhysicsSyncEventStation configStation = new PhysicsSyncEventStation( + this.sessionState.connection.getEtSystem(), + this.sessionState.connection.getEtStation().getName() + "_PhysicsSync", + getNextStationPosition()); + sessionState.stations.add(configStation); + new Thread(sessionState.stationThreadGroup, configStation).start(); + logger.fine("physics SYNC station created"); + } /** - * Disconnect from the current ET session with a particular status. + * Create the ET station that listens for GO events in order to initialize the conditions system. + */ + private void createPreStartStation() { + logger.fine("creating PRESTART station ..."); + String detectorName = this.application.configurationModel.getDetectorName(); + EtSystem system = this.sessionState.connection.getEtSystem(); + String stationName = this.sessionState.connection.getEtStation().getName() + "_PreStart"; + int order = getNextStationPosition(); + PreStartEtStation preStartStation = new PreStartEtStation( + detectorName, + system, + stationName, + order); + sessionState.stations.add(preStartStation); + new Thread(sessionState.stationThreadGroup, preStartStation).start(); + logger.fine("PRESTART station created"); + } + + /** + * Disconnect from the current ET session. * @param status The connection status. */ synchronized void disconnect() { - - logger.fine("disconnecting"); // Cleanup the ET connection. closeEtConnection(); - + // Change application state to disconnected. application.connectionModel.setConnectionStatus(ConnectionStatus.DISCONNECTED); - - logger.fine("disconnected"); - } - - /** - * This class notifies the application to disconnect if the event processing thread completes. + } + + /** + * This class notifies the application to disconnect if the event processing thread completes. */ class SessionWatchdogThread extends Thread { @@ -479,21 +588,39 @@ SessionWatchdogThread(Thread processingThread) { this.processingThread = processingThread; } - + public void run() { try { - // When the event processing thread finishes, the session should be stopped and a - // disconnect should occur. + // This thread waits on the event processing thread to die. processingThread.join(); - + // Activate a disconnect using the ActionEvent which is used by the disconnect button. - logger.fine("processing thread ended so automatic disconnect is happening"); + logger.finest("processing thread ended so automatic disconnect is happening"); application.actionPerformed(new ActionEvent(Thread.currentThread(), 0, Commands.DISCONNECT)); - + } catch (InterruptedException e) { - logger.fine("SessionWatchdogThread got interrupted"); + logger.finest("SessionWatchdogThread got interrupted"); // This happens when the thread is interrupted by the user pressing the disconnect button. - } - } + } + } + } + + void invalidate() { + + this.application = null; + this.conditionsListeners = null; + this.drivers = null; + this.logger = null; + this.processors = null; + + this.sessionState.jobManager = null; + this.sessionState.eventBuilder = null; + this.sessionState.loop = null; + this.sessionState.processingThread = null; + this.sessionState.sessionWatchdogThread = null; + this.sessionState.stationThreadGroup = null; + this.sessionState.stations = null; + this.sessionState.connection = null; + this.sessionState = null; } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/LogLevelFilterComboBox.java Sun Mar 15 11:31:15 2015 @@ -13,7 +13,7 @@ import org.hps.monitoring.application.model.ConfigurationModel; /** - * + * This is a combo box used to filter the log table messages by level. * @author Jeremy McCormick <[log in to unmask]> */ class LogLevelFilterComboBox extends JComboBox<Level> implements ActionListener, PropertyChangeListener { Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplication.java Sun Mar 15 11:31:15 2015 @@ -5,12 +5,10 @@ import hep.aida.jfree.plotter.PlotterRegionListener; import hep.aida.ref.remote.rmi.client.RmiStoreFactory; -import java.awt.Dimension; -import java.awt.Rectangle; -import java.awt.Robot; -import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; @@ -40,6 +38,7 @@ import org.hps.monitoring.application.LogTable.LogRecordModel; import org.hps.monitoring.application.model.Configuration; import org.hps.monitoring.application.model.ConfigurationModel; +import org.hps.monitoring.application.model.ConnectionStatus; import org.hps.monitoring.application.model.ConnectionStatusModel; import org.hps.monitoring.application.model.RunModel; import org.hps.monitoring.application.util.AIDAServer; @@ -49,12 +48,11 @@ import org.hps.monitoring.application.util.TableExporter; import org.hps.monitoring.plotting.MonitoringAnalysisFactory; import org.hps.monitoring.plotting.MonitoringPlotFactory; -import org.hps.monitoring.subsys.StatusCode; import org.hps.monitoring.subsys.SystemStatus; -import org.hps.monitoring.subsys.SystemStatusListener; import org.hps.monitoring.subsys.SystemStatusRegistry; import org.hps.record.composite.CompositeRecordProcessor; import org.hps.record.enums.DataSourceType; +import org.lcsim.conditions.ConditionsListener; import org.lcsim.util.Driver; import org.lcsim.util.aida.AIDA; import org.lcsim.util.log.DefaultLogFormatter; @@ -62,12 +60,11 @@ /** * This is the primary class that implements the monitoring GUI application. * It should not be used directly. Instead the {@link Main} class should be - * used from the command line or via the supplied script built automatically - * by Maven. + * used from the command line. * * @author Jeremy McCormick <[log in to unmask]> */ -final class MonitoringApplication implements ActionListener, PropertyChangeListener, SystemStatusListener { +final class MonitoringApplication implements ActionListener, PropertyChangeListener { // Statically initialize logging, which will be fully setup later. static final Logger logger; @@ -78,14 +75,15 @@ // Default log stream. MonitoringApplicationStreamHandler streamHandler; + LogHandler logHandler; PrintStream sysOut = System.out; PrintStream sysErr = System.err; // Application error handling. - final ErrorHandler errorHandler; + ErrorHandler errorHandler; // The main GUI components inside a JFrame. - final MonitoringApplicationFrame frame; + MonitoringApplicationFrame frame; // The primary data models. final RunModel runModel = new RunModel(); @@ -150,41 +148,86 @@ super.setOutputStream(out); } } - + /** * Instantiate and show the monitoring application with the given configuration. * @param configuration The Configuration object containing application settings. */ MonitoringApplication(Configuration configuration) { - - // Setup the main GUI component. - frame = new MonitoringApplicationFrame(this); - - // Setup the error handler. - errorHandler = new ErrorHandler(frame, logger); + + try { + + // Setup the main GUI component. + frame = new MonitoringApplicationFrame(this); + + // Add window listener to perform clean shutdown. + frame.addWindowListener(new WindowListener() { + + @Override + public void windowOpened(WindowEvent e) { + } + + @Override + public void windowClosing(WindowEvent e) { + } + + @Override + public void windowClosed(WindowEvent e) { + exit(); + } + + @Override + public void windowIconified(WindowEvent e) { + } + + @Override + public void windowDeiconified(WindowEvent e) { + } + + @Override + public void windowActivated(WindowEvent e) { + } + + @Override + public void windowDeactivated(WindowEvent e) { + } + }); + + // Setup the error handler. + errorHandler = new ErrorHandler(frame, logger); - // Add this class as a listener on the configuration model. - configurationModel.addPropertyChangeListener(this); - - // Setup the logger. - setupLogger(); + // Add this class as a listener on the configuration model. + configurationModel.addPropertyChangeListener(this); + + // Setup the logger. + setupLogger(); - // Setup AIDA plotting and connect it to the GUI. - setupAida(); - - // Set the configuration. - if (configuration != null) { - // There was a user specified configuration. - this.configuration = configuration; - } else { - // Use the default configuration. - this.configuration = new Configuration(DEFAULT_CONFIGURATION); - } + // Setup AIDA plotting and connect it to the GUI. + setupAida(); + + // Set the configuration. + if (configuration != null) { + // There was a user specified configuration. + this.configuration = configuration; + } else { + // Use the default configuration. + this.configuration = new Configuration(DEFAULT_CONFIGURATION); + } - // Load the configuration. - loadConfiguration(this.configuration); - - logger.info("application initialized successfully"); + // Load the configuration. + loadConfiguration(this.configuration); + + frame.setEnabled(true); + + logger.info("application initialized successfully"); + + } catch (Exception e) { + // Don't use the ErrorHandler here because we don't know that it initialized successfully. + System.err.println("MonitoringApplication failed to initialize without errors!"); + DialogUtil.showErrorDialog(null, "Error Starting Monitoring Application", "Monitoring application failed to initialize."); + e.printStackTrace(); + System.exit(1); + } } /** @@ -192,7 +235,8 @@ */ void setupLogger() { logger.setUseParentHandlers(false); - logger.addHandler(new LogHandler()); + logHandler = new LogHandler(); + logger.addHandler(logHandler); streamHandler = new MonitoringApplicationStreamHandler(System.out); logger.addHandler(streamHandler); for (Handler handler : logger.getHandlers()) { @@ -201,7 +245,7 @@ logger.setLevel(DEFAULT_LEVEL); logger.info("logging initialized"); } - + /** * Static utility method for creating new instance. * @param configuration The application settings. @@ -217,7 +261,9 @@ */ @Override public void propertyChange(PropertyChangeEvent evt) { - // TODO: Handle log level configuration change here. + if (evt.getPropertyName().equals(ConfigurationModel.LOG_LEVEL_PROPERTY)) { + setLogLevel(); + } } /** @@ -232,11 +278,12 @@ if (Commands.CONNECT.equals(command)) { startSession(); } else if (Commands.DISCONNECT.equals(command)) { - processing.stop(); + runDisconnectThread(); } else if (Commands.SAVE_PLOTS.equals(command)) { savePlots(); } else if (Commands.EXIT.equals(command)) { - exit(); + // This will trigger the window closing action that cleans everything up. + frame.dispose(); } else if (Commands.PAUSE.equals(command)) { processing.pause(); } else if (Commands.NEXT.equals(command)) { @@ -265,8 +312,6 @@ closeFile(); } else if (Commands.SAVE_SCREENSHOT.equals(command)) { saveScreenshot(); - } else if (Commands.LOG_LEVEL_CHANGED.equals(command)) { - setLogLevel(); } else if (Commands.SAVE_LOG_TABLE.equals(command)) { saveLogTable(); } else if (Commands.CLEAR_LOG_TABLE.equals(command)) { @@ -327,11 +372,14 @@ * Reset the plots and clear the tabs in the plot window. */ void resetPlots() { - + + // Clear global list of registered plotters. + MonitoringPlotFactory.getPlotterRegistry().clear(); + // Clear the static AIDA tree in case plots are hanging around from previous sessions. AIDA.defaultInstance().clearAll(); - // Reset plot panel which removes all tabs. + // Reset plot panel which removes all its tabs. frame.plotPanel.reset(); logger.info("plots were cleared"); @@ -341,43 +389,20 @@ * Configure the system status monitor panel for a new job. */ void setupSystemStatusMonitor() { + // Clear the system status monitor table. - frame.systemStatusTable.getTableModel().clear(); + frame.systemStatusPanel.clear(); // Get the global registry of SystemStatus objects. SystemStatusRegistry registry = SystemStatusRegistry.getSystemStatusRegistery(); // Process the SystemStatus objects. for (SystemStatus systemStatus : registry.getSystemStatuses()) { - // Add a row to the table for every SystemStatus. - frame.systemStatusTable.getTableModel().addSystemStatus(systemStatus); - - // Add this class as a listener so all status changes can be logged. - systemStatus.addListener(this); + // This will add the status to the two tables. + frame.systemStatusPanel.addSystemStatus(systemStatus); } logger.info("system status monitor initialized successfully"); - } - - /** - * Hook for logging all status changes from the system status monitor. - */ - @Override - public void statusChanged(SystemStatus status) { - - // Choose the appropriate log level. - Level level = Level.FINE; - if (status.getStatusCode().equals(Level.WARNING)) { - level = Level.WARNING; - } else if (status.getStatusCode().ordinal() >= StatusCode.ERROR.ordinal()) { - level = Level.SEVERE; - } - - // Log all status changes. - logger.log(level, "STATUS, " + "subsys: " + status.getSubsystem() + ", " - + "code: " + status.getStatusCode().name() - + ", " + "descr: " + status.getDescription() - + ", " + "mesg: " + status.getMessage()); } /** @@ -399,13 +424,18 @@ // List of extra composite record processors including the updater for the RunPanel. List<CompositeRecordProcessor> processors = new ArrayList<CompositeRecordProcessor>(); - processors.add(frame.runPanel.new RunPanelUpdater()); - + processors.add(frame.dashboardPanel.new EventDashboardUpdater()); + + // Add Driver to update the trigger diagnostics tables. List<Driver> drivers = new ArrayList<Driver>(); drivers.add(frame.triggerPanel.new TriggerDiagnosticGUIDriver()); - - // Initialize event processing with the list of processors and reference to the application. - processing = new EventProcessing(this, processors, drivers); + + // Add listener to push conditions changes to conditions panel. + List<ConditionsListener> conditionsListeners = new ArrayList<ConditionsListener>(); + conditionsListeners.add(frame.conditionsPanel.new ConditionsPanelListener()); + + // Instantiate the event processing wrapper. + processing = new EventProcessing(this, processors, drivers, conditionsListeners); // Connect to the ET system, if applicable. processing.connect(); @@ -418,7 +448,7 @@ // Setup the system status monitor table. setupSystemStatusMonitor(); - // Start the event processing thread. + // Start the event processing thread. processing.start(); logger.info("new session successfully initialized"); @@ -437,17 +467,17 @@ } /** - * Exit from the application. + * Exit from the application from exit menu item or hitting close window button. */ void exit() { - if (processing != null && processing.isActive()) { + if (connectionModel.isConnected()) { processing.stop(); } - frame.setVisible(false); + logHandler.setLevel(Level.OFF); logger.info("exiting the application"); - logger.getHandlers()[0].flush(); + streamHandler.flush(); System.exit(0); - } + } /** * Save AIDA plots to a file using a file chooser. @@ -601,6 +631,7 @@ /** * Save a screenshot to a file using a file chooser. */ + // FIXME: This might need to be on a new thread to allow the GUI to redraw w/o chooser visible. void saveScreenshot() { JFileChooser fc = new JFileChooser(); fc.setAcceptAllFileFilterUsed(false); @@ -615,8 +646,17 @@ if (!fileName.endsWith("." + format)) { fileName += "." + format; } + frame.repaint(); + Object lock = new Object(); + synchronized (lock) { + try { + lock.wait(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } writeScreenshot(fileName, format); - DialogUtil.showInfoDialog(frame, "Screenshot Saved", "Screenshot was saved to file."); + DialogUtil.showInfoDialog(frame, "Screenshot Saved", "Screenshot was saved to file" + '\n' + fileName); logger.info("saved screenshot to " + fileName); } } @@ -626,15 +666,13 @@ * @param fileName The name of the output file. */ void writeScreenshot(String fileName, String format) { - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - Rectangle screenRectangle = new Rectangle(screenSize); + BufferedImage image = new BufferedImage(frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_INT_RGB); + frame.paint(image.getGraphics()); try { - Robot robot = new Robot(); - BufferedImage image = robot.createScreenCapture(screenRectangle); ImageIO.write(image, format, new File(fileName)); - } catch (Exception e) { - errorHandler.setError(e).setMessage("Failed to take screenshot.").printStackTrace().log().showErrorDialog(); - } + } catch (IOException e) { + errorHandler.setError(e).setMessage("Failed to save screenshot.").printStackTrace().log().showErrorDialog(); + } } /** @@ -785,5 +823,19 @@ frame.menu.stopAIDAServer(); logger.info("AIDA server was stopped"); DialogUtil.showInfoDialog(frame, "AIDA Server Stopped", "The AIDA server was stopped."); - } + } + + /** + * + */ + void runDisconnectThread() { + new Thread() { + public void run() { + logger.fine("disconnect thread is running ..."); + connectionModel.setConnectionStatus(ConnectionStatus.DISCONNECTING); + MonitoringApplication.this.processing.stop(); + logger.fine("disconnect thread finished!"); + } + }.run(); + } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/MonitoringApplicationFrame.java Sun Mar 15 11:31:15 2015 @@ -3,14 +3,11 @@ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; -import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; import java.awt.Rectangle; -import javax.swing.BoxLayout; -import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JPanel; -import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; @@ -23,13 +20,14 @@ */ class MonitoringApplicationFrame extends JFrame { - RunPanel runPanel; + EventDashboard dashboardPanel; PlotPanel plotPanel; PlotInfoPanel plotInfoPanel; LogPanel logPanel; - SystemStatusTable systemStatusTable; JPanel buttonsPanel; TriggerDiagnosticsPanel triggerPanel; + ConditionsPanel conditionsPanel; + SystemStatusPanel systemStatusPanel; MenuBar menu; JSplitPane mainSplitPane; @@ -39,14 +37,10 @@ DataSourceComboBox dataSourceComboBox; SettingsDialog settingsDialog; - - // Proportional layout parameters relative to the screen size. - static final double FULL_SIZE = 1.0; - static final double TOP_PANEL_HEIGHT = 0.05; - static final double BOTTOM_PANEL_HEIGHT = FULL_SIZE - TOP_PANEL_HEIGHT; - static final double LEFT_PANEL_WIDTH = 0.3; - static final double RIGHT_PANEL_WIDTH = FULL_SIZE - LEFT_PANEL_WIDTH; - static final double PLOT_PANEL_HEIGHT = 0.8; + + static final Rectangle BOUNDS = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds(); + static final int PIXEL_WIDTH_MAX = (int) BOUNDS.getWidth(); + static final int PIXEL_HEIGHT_MAX = (int) BOUNDS.getHeight(); /** * @@ -54,20 +48,22 @@ */ public MonitoringApplicationFrame( MonitoringApplication application) { + + // Disable interaction until specifically enabled externally after initialization. + setEnabled(false); // Create the content panel. JPanel contentPanel = new JPanel(); setContentPane(contentPanel); - contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS)); + contentPanel.setLayout(new BorderLayout()); contentPanel.setOpaque(true); - setProportionalSize(contentPanel, FULL_SIZE, FULL_SIZE); - + contentPanel.setPreferredSize(new Dimension(PIXEL_WIDTH_MAX, PIXEL_HEIGHT_MAX)); + // Create the top panel. JPanel topPanel = new JPanel(); topPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 20, 0)); - setProportionalSize(topPanel, FULL_SIZE, TOP_PANEL_HEIGHT); - contentPanel.add(topPanel); - + contentPanel.add(topPanel, BorderLayout.NORTH); + // Create the connection status panel. JPanel connectionPanel = new ConnectionStatusPanel(application.connectionModel); topPanel.add(connectionPanel); @@ -83,7 +79,6 @@ // Add vertical separator. sep = new JSeparator(SwingConstants.VERTICAL); - sep.setPreferredSize(new Dimension(5, topPanel.getPreferredSize().height)); topPanel.add(sep); // Add the data source combo box. @@ -93,16 +88,14 @@ // Create the bottom panel. JPanel bottomPanel = new JPanel(); bottomPanel.setLayout(new BorderLayout()); - setProportionalSize(bottomPanel, FULL_SIZE, BOTTOM_PANEL_HEIGHT); - contentPanel.add(bottomPanel); - + contentPanel.add(bottomPanel, BorderLayout.CENTER); + // Create the left panel. JPanel leftPanel = new JPanel(); leftPanel.setLayout(new BorderLayout()); - setProportionalSize(leftPanel, LEFT_PANEL_WIDTH, FULL_SIZE); - + // Create the run dashboard. - runPanel = new RunPanel(application.runModel); + dashboardPanel = new EventDashboard(application.runModel); // Create the tabbed pane for content in bottom of left panel such as log table and system monitor. JTabbedPane tableTabbedPane = new JTabbedPane(); @@ -112,76 +105,58 @@ tableTabbedPane.addTab("Log Messages", logPanel); // Create the system monitor. - systemStatusTable = new SystemStatusTable(); - tableTabbedPane.addTab("System Status Monitor", new JScrollPane(systemStatusTable)); + //systemStatusTable = new SystemStatusTable(); + systemStatusPanel = new SystemStatusPanel(); + tableTabbedPane.addTab("System Status Monitor", systemStatusPanel); // Add the trigger diagnostics tables. triggerPanel = new TriggerDiagnosticsPanel(); tableTabbedPane.addTab("Trigger Diagnostics", triggerPanel); + // Add the conditions panel. + conditionsPanel = new ConditionsPanel(); + tableTabbedPane.addTab("Detector Conditions", conditionsPanel); + // Vertical split pane in left panel. - leftSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, runPanel, tableTabbedPane); - leftSplitPane.setResizeWeight(0.5); + leftSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, dashboardPanel, tableTabbedPane); + leftSplitPane.setDividerLocation(250); leftPanel.add(leftSplitPane, BorderLayout.CENTER); // Create the right panel. JPanel rightPanel = new JPanel(); rightPanel.setLayout(new BorderLayout()); - + // Create the plot info panel. plotInfoPanel = new PlotInfoPanel(); // Create the plot panel. - plotPanel = new PlotPanel(); - plotPanel.setVisible(true); // DEBUG - setProportionalSize(plotPanel, RIGHT_PANEL_WIDTH, PLOT_PANEL_HEIGHT); + plotPanel = new PlotPanel(); + plotInfoPanel.saveButton.addActionListener(plotPanel); // Create the right panel vertical split pane for displaying plots and their information and statistics. rightSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, plotPanel, plotInfoPanel); - setProportionalSize(rightSplitPane, RIGHT_PANEL_WIDTH, FULL_SIZE); - rightSplitPane.setResizeWeight(0.8); + rightSplitPane.setResizeWeight(0.7); rightPanel.add(rightSplitPane, BorderLayout.CENTER); // Create the main horizontal split pane for dividing the left and right panels. mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPanel, rightPanel); - mainSplitPane.setResizeWeight(0.15); + mainSplitPane.setResizeWeight(0.2); bottomPanel.add(mainSplitPane, BorderLayout.CENTER); // Create the menu bar. menu = new MenuBar(application.configurationModel, application.connectionModel, application); setJMenuBar(menu); dataSourceComboBox.addActionListener(menu); - + + // Setup the settings dialog box (invisible until activated). + settingsDialog = new SettingsDialog(application.configurationModel, application); + // Setup the frame now that all components have been added. pack(); setExtendedState(JFrame.MAXIMIZED_BOTH); - setVisible(true); - - // Setup the settings dialog box. - settingsDialog = new SettingsDialog(application.configurationModel, application); + setVisible(true); } - - /** - * Set the size of a Swing component using proportions of the current screen bounds. - * @param component The component to resize. - * @param scaleX The X scaling (must be between 0 and 1). - * @param scaleY The Y scaling (must be between 0 and 1). - * @param setSize Call the setSize method as well as setPreferredSize (which is the default). - * @return - */ - void setProportionalSize(JComponent component, double scaleX, double scaleY) { - GraphicsConfiguration graphics = this.getGraphicsConfiguration(); - Rectangle bounds = graphics.getBounds(); - if (scaleX < 0 || scaleX > 1) { - throw new IllegalArgumentException("scaleX must be > 0 and <= 1."); - } - if (scaleY < 0 || scaleY > 1) { - throw new IllegalArgumentException("scaleY must be > 0 and <= 1."); - } - Dimension scaledDimension = new Dimension((int)(bounds.getWidth() * scaleX), (int)(bounds.getHeight() * scaleY)); - component.setPreferredSize(scaledDimension); - } - + /** * Restore default window settings. */ Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotInfoPanel.java Sun Mar 15 11:31:15 2015 @@ -15,10 +15,10 @@ import hep.aida.ref.function.FunctionDispatcher; import hep.aida.ref.function.FunctionListener; +import java.awt.Color; import java.awt.Component; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.Insets; +import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.EventObject; @@ -27,6 +27,8 @@ import java.util.TimerTask; import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JList; import javax.swing.JPanel; @@ -47,6 +49,8 @@ JComboBox<Object> plotComboBox; JTable infoTable = new JTable(); DefaultTableModel model; + JButton saveButton; + PlotterRegion currentRegion; Object currentObject; static final int INSET_SIZE = 5; @@ -63,11 +67,18 @@ */ @SuppressWarnings("unchecked") PlotInfoPanel() { - - setLayout(new GridBagLayout()); - setBorder(BorderFactory.createEmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - - GridBagConstraints c; + + setLayout(new FlowLayout(FlowLayout.LEFT)); + + JPanel leftPanel = new JPanel(); + leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.PAGE_AXIS)); + + JPanel buttonPanel = new JPanel(); + saveButton = new JButton("Save Plots ..."); + saveButton.setActionCommand(Commands.SAVE_SELECTED_PLOTS); + buttonPanel.add(saveButton); + //c.anchor = GridBagConstraints.NORTHWEST; + leftPanel.add(buttonPanel); plotComboBox = new JComboBox<Object>(); plotComboBox.setActionCommand(PLOT_SELECTED); @@ -85,26 +96,17 @@ } }); plotComboBox.addActionListener(this); - c = new GridBagConstraints(); - c.gridx = 0; - c.gridy = 0; - c.fill = GridBagConstraints.HORIZONTAL; - c.insets = new Insets(0, 0, INSET_SIZE, 0); - add(plotComboBox, c); - + leftPanel.add(plotComboBox); + String data[][] = new String[0][0]; model = new DefaultTableModel(data, COLUMN_NAMES); infoTable.setModel(model); - - // FIXME: Are these adequate column size settings? Could prob be bigger... infoTable.getColumn("Field").setMinWidth(25); infoTable.getColumn("Value").setMinWidth(20); - - c = new GridBagConstraints(); - c.gridx = 0; - c.gridy = 1; - c.fill = GridBagConstraints.BOTH; - add(infoTable, c); + infoTable.setMinimumSize(new Dimension(100, 200)); + leftPanel.add(infoTable); + + add(leftPanel); } /** Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/PlotPanel.java Sun Mar 15 11:31:15 2015 @@ -1,15 +1,26 @@ package org.hps.monitoring.application; +import hep.aida.IPlotter; + import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.IOException; +import javax.swing.JFileChooser; import javax.swing.JPanel; import javax.swing.JTabbedPane; + +import org.hps.monitoring.application.util.DialogUtil; +import org.hps.monitoring.plotting.MonitoringPlotFactory; /** * This is the panel containing the tabs with the monitoring plots. * @author Jeremy McCormick <[log in to unmask]> */ -class PlotPanel extends JPanel { +class PlotPanel extends JPanel implements ActionListener { private JTabbedPane plotPane; @@ -23,8 +34,55 @@ JTabbedPane getPlotPane() { return plotPane; } + + /** + * Get the indices of the current selected tabs. + * @return The indices of the current tabs. + */ + int[] getSelectedTabs() { + int[] indices = new int[2]; + indices[0] = plotPane.getSelectedIndex(); + Component component = plotPane.getSelectedComponent(); + if (component instanceof JTabbedPane) { + indices[1] = ((JTabbedPane)component).getSelectedIndex(); + } + return indices; + } + + public void actionPerformed(ActionEvent event) { + if (event.getActionCommand().equals(Commands.SAVE_SELECTED_PLOTS)) { + int[] indices = getSelectedTabs(); + IPlotter plotter = MonitoringPlotFactory.getPlotterRegistry().find(indices[0], indices[1]); + if (plotter != null) { + savePlotter(plotter); + } else { + DialogUtil.showErrorDialog(this, "Error Finding Plots", "No plots found in selected tab."); + } + } + } + + static final String DEFAULT_FORMAT = "png"; + void savePlotter(IPlotter plotter) { + JFileChooser fc = new JFileChooser(); + fc.setAcceptAllFileFilterUsed(false); + fc.setDialogTitle("Save Plots - " + plotter.title()); + fc.setCurrentDirectory(new File(".")); + int r = fc.showSaveDialog(this); + if (r == JFileChooser.APPROVE_OPTION) { + String path = fc.getSelectedFile().getPath(); + if (path.lastIndexOf(".") == -1) { + path += "." + DEFAULT_FORMAT; + } + try { + plotter.writeToFile(path); + } catch (IOException e) { + e.printStackTrace(); + DialogUtil.showErrorDialog(this, "Error Saving Plots", "There was an error saving the plots."); + } + } + } void reset() { - plotPane.removeAll(); - } + plotPane.removeAll(); + } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusTable.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusTable.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/SystemStatusTable.java Sun Mar 15 11:31:15 2015 @@ -1,6 +1,5 @@ package org.hps.monitoring.application; -import java.awt.Color; import java.awt.Component; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; @@ -17,8 +16,7 @@ import org.hps.monitoring.subsys.StatusCode; /** - * A GUI window for showing changes to {@link org.hps.monitoring.subsys.SystemStatus} objects using - * a <code>JTable</code>. + * This table shows the current state of {@link org.hps.monitoring.subsys.SystemStatus} objects. */ class SystemStatusTable extends JTable { @@ -37,28 +35,7 @@ // Color code the cell by its status. StatusCode statusCode = StatusCode.valueOf((String) value); - if (statusCode.ordinal() >= StatusCode.ERROR.ordinal()) { - // Any type of error is red. - label.setBackground(Color.RED); - } else if (statusCode.equals(StatusCode.WARNING)) { - // Warnings are yellow. - label.setBackground(Color.YELLOW); - } else if (statusCode.equals(StatusCode.OKAY)) { - // Okay is green. - label.setBackground(Color.GREEN); - } else if (statusCode.equals(StatusCode.OFFLINE)) { - // Offline is orange. - label.setBackground(Color.ORANGE); - } else if (statusCode.equals(StatusCode.UNKNOWN)) { - // Unknown is gray. - label.setBackground(Color.GRAY); - } else if (statusCode.equals(StatusCode.CLEARED)) { - // Cleared is light gray. - label.setBackground(Color.LIGHT_GRAY); - } else { - // Default is white, though this shouldn't happen! - label.setBackground(Color.WHITE); - } + label.setBackground(statusCode.getColor()); return label; } }); Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatus.java Sun Mar 15 11:31:15 2015 @@ -10,6 +10,7 @@ public enum ConnectionStatus { DISCONNECTED(Color.RED), + DISCONNECTING(Color.YELLOW), CONNECTED(Color.GREEN); Color color; Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/ConnectionStatusModel.java Sun Mar 15 11:31:15 2015 @@ -50,4 +50,16 @@ listener.propertyChange(new PropertyChangeEvent(this, PAUSED_PROPERTY, oldValue, this.paused)); } } + + public boolean isConnected() { + return this.connectionStatus == ConnectionStatus.CONNECTED; + } + + public boolean isDisconnected() { + return this.connectionStatus == ConnectionStatus.DISCONNECTED; + } + + public boolean isDisconnecting() { + return this.connectionStatus == ConnectionStatus.DISCONNECTING; + } } Modified: java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/RunModel.java ============================================================================= --- java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/RunModel.java (original) +++ java/trunk/monitoring-app/src/main/java/org/hps/monitoring/application/model/RunModel.java Sun Mar 15 11:31:15 2015 @@ -3,7 +3,7 @@ import java.util.Date; /** - * Backing model for run information that shows in the {@link org.hps.monitoring.application.RunPanel}. + * Backing model for run information that shows in the {@link org.hps.monitoring.application.EventDashboard}. */ public final class RunModel extends AbstractModel { Modified: java/trunk/monitoring-app/src/main/resources/org/hps/monitoring/config/default_config.prop ============================================================================= --- java/trunk/monitoring-app/src/main/resources/org/hps/monitoring/config/default_config.prop (original) +++ java/trunk/monitoring-app/src/main/resources/org/hps/monitoring/config/default_config.prop Sun Mar 15 11:31:15 2015 @@ -29,8 +29,7 @@ Host=localhost Port=11111 StationPosition=1 -# Prescale was 1 -Prescale=0 +Prescale=1 QueueSize=0 StationName=MY_STATION Verbose=false