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