create changelog entry
[debian/openrocket] / core / 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                         throwable = e;
58                         return null;
59                 }
60                 return simulation.getSimulatedData();
61         }
62         
63         
64         /**
65          * Return additional listeners to use during the simulation.  The default
66          * implementation returns an empty array.
67          * 
68          * @return      additional listeners to use, or <code>null</code>.
69          */
70         protected SimulationListener[] getExtraListeners() {
71                 return new SimulationListener[0];
72         }
73         
74         
75         /**
76          * Called after a simulation is successfully simulated.  This method is not
77          * called if the simulation ends in an exception.
78          */
79         protected abstract void simulationDone();
80         
81         /**
82          * Called if the simulation is interrupted due to an exception.
83          * 
84          * @param t             the Throwable that caused the interruption
85          */
86         protected abstract void simulationInterrupted(Throwable t);
87         
88         
89
90         /**
91          * Marks this simulation as done and calls the progress update.
92          */
93         @Override
94         protected final void done() {
95                 if (throwable == null)
96                         simulationDone();
97                 else
98                         simulationInterrupted(throwable);
99         }
100         
101         
102
103         /**
104          * A simulation listener that throws a {@link SimulationCancelledException} if
105          * this SwingWorker has been cancelled.  The conditions is checked every time a step
106          * is taken.
107          * 
108          * @author Sampo Niskanen <sampo.niskanen@iki.fi>
109          */
110         private class CancelListener extends AbstractSimulationListener {
111                 
112                 @Override
113                 public void postStep(SimulationStatus status) throws SimulationCancelledException {
114                         
115                         if (isCancelled()) {
116                                 throw new SimulationCancelledException("The simulation was interrupted.");
117                         }
118                         
119                 }
120         }
121 }