Rework the CustomExpression evaluation to use SimulationListeners. Removed the OpenR...
[debian/openrocket] / core / src / net / sf / openrocket / gui / main / SimulationRunDialog.java
index c108030567921690797a37cf7f477ca796a417f0..65fabb8fa36430ef8384c7a2dd5749ba0bc10e7c 100644 (file)
@@ -10,8 +10,11 @@ import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.util.Iterator;
 import java.util.List;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
 import javax.swing.JButton;
 import javax.swing.JDialog;
@@ -21,6 +24,7 @@ import javax.swing.JPanel;
 import javax.swing.JProgressBar;
 
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.gui.dialogs.DetailDialog;
 import net.sf.openrocket.gui.util.GUIUtil;
@@ -32,6 +36,8 @@ import net.sf.openrocket.rocketcomponent.MotorMount;
 import net.sf.openrocket.rocketcomponent.MotorMount.IgnitionEvent;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.simulation.SimulationStatus;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
+import net.sf.openrocket.simulation.customexpression.CustomExpressionSimulationListener;
 import net.sf.openrocket.simulation.exception.SimulationCancelledException;
 import net.sf.openrocket.simulation.exception.SimulationException;
 import net.sf.openrocket.simulation.exception.SimulationLaunchException;
@@ -47,7 +53,7 @@ public class SimulationRunDialog extends JDialog {
        private static final LogHelper log = Application.getLogger();
        private static final Translator trans = Application.getTranslator();
        
-
+       
        /** Update the dialog status every this many ms */
        private static final long UPDATE_MS = 200;
        
@@ -57,25 +63,42 @@ public class SimulationRunDialog extends JDialog {
        /** Flight progress at apogee */
        private static final double APOGEE_PROGRESS = 0.7;
        
-
-       /*
-        * The executor service is not static since we want concurrent simulation
-        * dialogs to run in parallel, ie. they both have their own executor service.
+       
+       /**
+        * A single ThreadPoolExecutor that will be used for all simulations.
+        * This executor must not be shut down.
         */
-       private final ExecutorService executor = Executors.newFixedThreadPool(
-                       SwingPreferences.getMaxThreadCount());
+       private static final ThreadPoolExecutor executor;
+       static {
+               int n = SwingPreferences.getMaxThreadCount();
+               executor = new ThreadPoolExecutor(n, n,
+                               0L, TimeUnit.MILLISECONDS,
+                               new LinkedBlockingQueue<Runnable>(),
+                               new ThreadFactory() {
+                                       private ThreadFactory factory = Executors.defaultThreadFactory();
+                                       
+                                       @Override
+                                       public Thread newThread(Runnable r) {
+                                               Thread t = factory.newThread(r);
+                                               t.setDaemon(true);
+                                               return t;
+                                       }
+                               });
+       }
+       
+       
        
-
        private final JLabel simLabel, timeLabel, altLabel, velLabel;
        private final JProgressBar progressBar;
        
-
+       
        /*
         * NOTE:  Care must be used when accessing the simulation parameters, since they
         * are being run in another thread.  Mutexes are used to avoid concurrent usage, which
         * will result in an exception being thrown!
         */
        private final Simulation[] simulations;
+       private final OpenRocketDocument document;
        private final String[] simulationNames;
        private final SimulationWorker[] simulationWorkers;
        private final SimulationStatus[] simulationStatuses;
@@ -83,9 +106,10 @@ public class SimulationRunDialog extends JDialog {
        private final double[] simulationMaxVelocity;
        private final boolean[] simulationDone;
        
-       public SimulationRunDialog(Window window, Simulation... simulations) {
+       public SimulationRunDialog(Window window, OpenRocketDocument document, Simulation... simulations) {
                //// Running simulations...
-               super(window, trans.get("SimuRunDlg.title.RunSim"), Dialog.ModalityType.DOCUMENT_MODAL);
+               super(window, trans.get("SimuRunDlg.title.RunSim"), Dialog.ModalityType.APPLICATION_MODAL);
+               this.document = document;
                
                if (simulations.length == 0) {
                        throw new IllegalArgumentException("Called with no simulations to run");
@@ -93,7 +117,7 @@ public class SimulationRunDialog extends JDialog {
                
                this.simulations = simulations;
                
-
+               
                // Randomize the simulation random seeds
                for (Simulation sim : simulations) {
                        sim.getOptions().randomizeSeed();
@@ -110,7 +134,7 @@ public class SimulationRunDialog extends JDialog {
                
                for (int i = 0; i < n; i++) {
                        simulationNames[i] = simulations[i].getName();
-                       simulationWorkers[i] = new InteractiveSimulationWorker(simulations[i], i);
+                       simulationWorkers[i] = new InteractiveSimulationWorker(document, simulations[i], i);
                        executor.execute(simulationWorkers[i]);
                }
                
@@ -138,7 +162,7 @@ public class SimulationRunDialog extends JDialog {
                progressBar = new JProgressBar();
                panel.add(progressBar, "spanx, growx, wrap para");
                
-
+               
                // Add cancel button
                JButton cancel = new JButton(trans.get("dlg.but.cancel"));
                cancel.addActionListener(new ActionListener() {
@@ -149,7 +173,7 @@ public class SimulationRunDialog extends JDialog {
                });
                panel.add(cancel, "spanx, tag cancel");
                
-
+               
                // Cancel simulations when user closes the window
                this.addWindowListener(new WindowAdapter() {
                        @Override
@@ -158,7 +182,7 @@ public class SimulationRunDialog extends JDialog {
                        }
                });
                
-
+               
                this.add(panel);
                this.setMinimumSize(new Dimension(300, 0));
                this.setLocationByPlatform(true);
@@ -176,10 +200,10 @@ public class SimulationRunDialog extends JDialog {
         * the Cancel button on the dialog.
         */
        public void cancelSimulations() {
-               executor.shutdownNow();
                for (SimulationWorker w : simulationWorkers) {
                        w.cancel(true);
                }
+               executor.purge();
        }
        
        
@@ -189,13 +213,13 @@ public class SimulationRunDialog extends JDialog {
         * @param parent                the parent Window of the dialog to use.
         * @param simulations   the simulations to run.
         */
-       public static void runSimulations(Window parent, Simulation... simulations) {
-               new SimulationRunDialog(parent, simulations).setVisible(true);
+       public static void runSimulations(Window parent, OpenRocketDocument document, Simulation... simulations) {
+               new SimulationRunDialog(parent, document, simulations).setVisible(true);
        }
        
        
-
-
+       
+       
        private void updateProgress() {
                int index;
                for (index = 0; index < simulations.length; index++) {
@@ -242,7 +266,7 @@ public class SimulationRunDialog extends JDialog {
        }
        
        
-
+       
        /**
         * A SwingWorker that performs a flight simulation.  It periodically updates the
         * simulation statuses of the parent class and calls updateProgress().
@@ -258,6 +282,8 @@ public class SimulationRunDialog extends JDialog {
                private volatile double burnoutVelocity;
                private volatile double apogeeAltitude;
                
+               private final CustomExpressionSimulationListener exprListener;
+               
                /*
                 * -2 = time from 0 ... burnoutTimeEstimate
                 * -1 = velocity from v(burnoutTimeEstimate) ... 0
@@ -268,8 +294,10 @@ public class SimulationRunDialog extends JDialog {
                private int progress = 0;
                
                
-               public InteractiveSimulationWorker(Simulation sim, int index) {
+               public InteractiveSimulationWorker(OpenRocketDocument doc, Simulation sim, int index) {
                        super(sim);
+                       List<CustomExpression> exprs = doc.getCustomExpressions();
+                       exprListener = new CustomExpressionSimulationListener(exprs);
                        this.index = index;
                        
                        // Calculate estimate of motor burn time
@@ -295,7 +323,7 @@ public class SimulationRunDialog extends JDialog {
                 */
                @Override
                protected SimulationListener[] getExtraListeners() {
-                       return new SimulationListener[] { new SimulationProgressListener() };
+                       return new SimulationListener[] { new SimulationProgressListener(), exprListener };
                }