9e6f62bc1ca5b05765a9e1e78219211759593a43
[debian/openrocket] / src / net / sf / openrocket / gui / main / SimulationWorker.java
1 package net.sf.openrocket.gui.main;
2
3 import java.util.Arrays;
4
5 import javax.swing.SwingWorker;
6
7 import net.sf.openrocket.document.Simulation;
8 import net.sf.openrocket.simulation.FlightData;
9 import net.sf.openrocket.simulation.SimulationStatus;
10 import net.sf.openrocket.simulation.exception.SimulationCancelledException;
11 import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
12 import net.sf.openrocket.simulation.listeners.SimulationListener;
13
14
15
16 /**
17  * A SwingWorker that runs a simulation in a background thread.  The simulation
18  * always includes a listener that checks whether this SwingWorked has been cancelled,
19  * and throws a {@link SimulationCancelledException} if it has.  This allows the
20  * {@link #cancel(boolean)} method to be used to cancel the simulation.
21  * 
22  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
23  */
24 public abstract class SimulationWorker extends SwingWorker<FlightData, SimulationStatus> {
25         
26         protected final Simulation simulation;
27         private Throwable throwable = null;
28         
29         public SimulationWorker(Simulation sim) {
30                 this.simulation = sim;
31         }
32         
33         
34         /**
35          * Runs the simulation.
36          */
37         @Override
38         protected FlightData doInBackground() {
39                 if (isCancelled()) {
40                         throwable = new SimulationCancelledException("The simulation was interrupted.");
41                         return null;
42                 }
43                 
44                 SimulationListener[] listeners = getExtraListeners();
45                 
46                 if (listeners != null) {
47                         listeners = Arrays.copyOf(listeners, listeners.length + 1);
48                 } else {
49                         listeners = new SimulationListener[1];
50                 }
51                 
52                 listeners[listeners.length - 1] = new CancelListener();
53                 
54                 try {
55                         simulation.simulate(listeners);
56                 } catch (Throwable e) {
57                         //                      System.out.println("Simulation interrupted:");
58                         //                      e.printStackTrace();
59                         throwable = e;
60                         return null;
61                 }
62                 return simulation.getSimulatedData();
63         }
64         
65         
66         /**
67          * Return additional listeners to use during the simulation.  The default
68          * implementation returns an empty array.
69          * 
70          * @return      additional listeners to use, or <code>null</code>.
71          */
72         protected SimulationListener[] getExtraListeners() {
73                 return new SimulationListener[0];
74         }
75         
76         
77         /**
78          * Called after a simulation is successfully simulated.  This method is not
79          * called if the simulation ends in an exception.
80          * 
81          * @param sim   the simulation including the flight data
82          */
83         protected abstract void simulationDone();
84         
85         /**
86          * Called if the simulation is interrupted due to an exception.
87          * 
88          * @param t             the Throwable that caused the interruption
89          */
90         protected abstract void simulationInterrupted(Throwable t);
91         
92         
93
94         /**
95          * Marks this simulation as done and calls the progress update.
96          */
97         @Override
98         protected final void done() {
99                 if (throwable == null)
100                         simulationDone();
101                 else
102                         simulationInterrupted(throwable);
103         }
104         
105         
106
107         /**
108          * A simulation listener that throws a {@link SimulationCancelledException} if
109          * this SwingWorker has been cancelled.  The conditions is checked every time a step
110          * is taken.
111          * 
112          * @author Sampo Niskanen <sampo.niskanen@iki.fi>
113          */
114         private class CancelListener extends AbstractSimulationListener {
115                 
116                 @Override
117                 public void postStep(SimulationStatus status) throws SimulationCancelledException {
118                         
119                         if (isCancelled()) {
120                                 throw new SimulationCancelledException("The simulation was interrupted.");
121                         }
122                         
123                 }
124         }
125 }