1 package nl.tudelft.simulation.dsol.swing.gui.control;
2
3 import java.awt.event.ActionEvent;
4 import java.beans.PropertyChangeEvent;
5 import java.beans.PropertyChangeListener;
6 import java.rmi.RemoteException;
7
8 import javax.swing.JButton;
9
10 import org.djunits.value.vdouble.scalar.Duration;
11 import org.djunits.value.vfloat.scalar.FloatDuration;
12 import org.djutils.event.Event;
13
14 import nl.tudelft.simulation.dsol.model.DsolModel;
15 import nl.tudelft.simulation.dsol.simulators.DevsRealTimeAnimator;
16 import nl.tudelft.simulation.dsol.simulators.DevsSimulatorInterface;
17 import nl.tudelft.simulation.dsol.simulators.RunState;
18
19 /**
20 * ControlPanel container for the a DEVS simulator, with clocks for different time units.
21 * <p>
22 * Copyright (c) 2020-2023 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
23 * for project information <a href="https://simulation.tudelft.nl/dsol/manual/" target="_blank">DSOL Manual</a>. The DSOL
24 * project is distributed under a three-clause BSD-style license, which can be found at
25 * <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">DSOL License</a>.
26 * </p>
27 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
28 * @param <T> the time type
29 * @param <S> the simulator type to use
30 */
31 public class RealTimeControlPanel<T extends Number & Comparable<T>, S extends DevsRealTimeAnimator<T>>
32 extends DevsControlPanel<T, S> implements PropertyChangeListener
33 {
34 /** */
35 private static final long serialVersionUID = 20201227L;
36
37 /** The timeWarpPanel to control the speed. */
38 private final RunSpeedSliderPanel runSpeedSliderPanel;
39
40 /** The default animation delay (stored during fast forward). */
41 private long savedAnimationDelay = 100L;
42
43 /**
44 * Generic control panel with a different set of control buttons. The control panel assumes a RealTimeDevsAnimator and
45 * animation, but the model specification is not necessarily specified as "real time"; its execution is.
46 * @param model DsolModel<T, ? extends DevsSimulationInterface<T>>; the model for the control panel, to allow a
47 * reset of the model
48 * @param simulator S; the simulator. Specified separately, because the model can have been specified with a superclass of
49 * the simulator that the ControlPanel actually needs (e.g., model has been specified with a DevsAnimator,
50 * whereas the panel needs a RealTimeControlAnimator)
51 * @throws RemoteException when simulator cannot be accessed for listener attachment
52 */
53 public RealTimeControlPanel(final DsolModel<T, ? extends DevsSimulatorInterface<T>> model, final S simulator)
54 throws RemoteException
55 {
56 super(model, simulator);
57
58 getControlButtonsPanel().add(makeButton("fastForwardButton", "/resources/FastForward.png", "FastForward",
59 "Run the simulation as fast as possible", true));
60
61 this.runSpeedSliderPanel = new RunSpeedSliderPanel(0.1, 1000, 1, 3, getSimulator());
62 add(this.runSpeedSliderPanel);
63
64 getSimulator().addListener(this, DevsRealTimeAnimator.CHANGE_SPEED_FACTOR_EVENT);
65 }
66
67 /** {@inheritDoc} */
68 @Override
69 public void actionPerformed(final ActionEvent actionEvent)
70 {
71 String actionCommand = actionEvent.getActionCommand();
72 try
73 {
74 if (actionCommand.equals("FastForward"))
75 {
76 if (getSimulator().isStoppingOrStopped())
77 {
78 this.savedAnimationDelay = getSimulator().getAnimationDelay();
79 getSimulator().setAnimationDelay(0L);
80 getSimulator().setUpdateMsec(1000);
81 getSimulator().setAnimationDelay(500); // 2 Hz
82 getSimulator().start();
83 }
84 }
85 if (actionCommand.equals("RunPause") || actionCommand.equals("Reset"))
86 {
87 getSimulator().setAnimationDelay(this.savedAnimationDelay);
88 }
89 }
90 catch (Exception exception)
91 {
92 exception.printStackTrace();
93 }
94 super.actionPerformed(actionEvent); // includes fixButtons()
95 }
96
97 /** {@inheritDoc} */
98 @Override
99 protected void fixButtons()
100 {
101 final boolean moreWorkToDo = getSimulator().getRunState() != RunState.ENDED;
102 for (JButton button : getControlButtons())
103 {
104 final String actionCommand = button.getActionCommand();
105 if (actionCommand.equals("FastForward"))
106 {
107 button.setEnabled(moreWorkToDo && isControlButtonsEnabled() && getSimulator().isStoppingOrStopped());
108 }
109 }
110 super.fixButtons(); // handles the start/stop button
111 }
112
113 /** {@inheritDoc} */
114 @Override
115 protected void invalidateButtons()
116 {
117 for (JButton button : getControlButtons())
118 {
119 final String actionCommand = button.getActionCommand();
120 if (actionCommand.equals("FastForward"))
121 {
122 button.setEnabled(false);
123 }
124 }
125 super.invalidateButtons(); // handles the start/stop button
126 }
127
128 /** {@inheritDoc} */
129 @Override
130 public void propertyChange(final PropertyChangeEvent evt)
131 {
132 // TODO: when external change on speed -- update the slider panel
133 }
134
135 /** {@inheritDoc} */
136 @Override
137 public void notify(final Event event) throws RemoteException
138 {
139 if (event.getType().equals(DevsRealTimeAnimator.CHANGE_SPEED_FACTOR_EVENT))
140 {
141 this.runSpeedSliderPanel.setSpeedFactor((Double) event.getContent());
142 fixButtons();
143 }
144 super.notify(event);
145 }
146
147 /**
148 * DEVS Real Time ControlPanel for a Double timeunit.
149 * <p>
150 * Copyright (c) 2020-2023 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved.
151 * See for project information <a href="https://simulation.tudelft.nl/dsol/manual/" target="_blank">DSOL Manual</a>. The
152 * DSOL project is distributed under a three-clause BSD-style license, which can be found at
153 * <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">DSOL License</a>.
154 * </p>
155 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
156 */
157 public static class TimeDouble extends RealTimeControlPanel<Double, DevsRealTimeAnimator<Double>>
158 {
159 /** */
160 private static final long serialVersionUID = 20201227L;
161
162 /**
163 * Construct a real time control panel for a Double time unit, with a different set of control buttons. The control
164 * panel assumes a DevsSimulator and animation. The model specification is not necessarily specified as "real time"; its
165 * execution is.
166 * @param model DsolModel<Double>; the model for the control panel, to allow a reset of the model
167 * @param simulator DevsRealTimeAnimator.TimeDouble; the simulator. Specified separately, because the model can have
168 * been specified with a superclass of the simulator that the ControlPanel actually needs (e.g., model has
169 * been specified with a DevsAnimator, whereas the panel needs a RealTimeControlAnimator)
170 * @throws RemoteException when simulator cannot be accessed for listener attachment
171 */
172 public TimeDouble(final DsolModel<Double, ? extends DevsSimulatorInterface<Double>> model,
173 final DevsRealTimeAnimator<Double> simulator) throws RemoteException
174 {
175 super(model, simulator);
176 setClockPanel(new ClockPanel.TimeDouble(getSimulator()));
177 setSpeedPanel(new SpeedPanel.TimeDouble(getSimulator()));
178 setRunUntilPanel(new RunUntilPanel.TimeDouble(getSimulator()));
179 }
180 }
181
182 /**
183 * DEVS Real Time ControlPanel for a Float timeunit.
184 * <p>
185 * Copyright (c) 2020-2023 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved.
186 * See for project information <a href="https://simulation.tudelft.nl/dsol/manual/" target="_blank">DSOL Manual</a>. The
187 * DSOL project is distributed under a three-clause BSD-style license, which can be found at
188 * <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">DSOL License</a>.
189 * </p>
190 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
191 */
192 public static class TimeFloat extends RealTimeControlPanel<Float, DevsRealTimeAnimator<Float>>
193 {
194 /** */
195 private static final long serialVersionUID = 20201227L;
196
197 /**
198 * Construct a real time control panel for a Float time unit, with a different set of control buttons. The control panel
199 * assumes a DevsSimulator and animation. The model specification is not necessarily specified as "real time"; its
200 * execution is.
201 * @param model DsolModel<Float>; the model for the control panel, to allow a reset of the model
202 * @param simulator DevsRealTimeAnimator<Float>; the simulator. Specified separately, because the model can have been
203 * specified with a superclass of the simulator that the ControlPanel actually needs (e.g., model has been
204 * specified with a DevsAnimator, whereas the panel needs a RealTimeControlAnimator)
205 * @throws RemoteException when simulator cannot be accessed for listener attachment
206 */
207 public TimeFloat(final DsolModel<Float, ? extends DevsSimulatorInterface<Float>> model,
208 final DevsRealTimeAnimator<Float> simulator) throws RemoteException
209 {
210 super(model, simulator);
211 setClockPanel(new ClockPanel.TimeFloat(getSimulator()));
212 setSpeedPanel(new SpeedPanel.TimeFloat(getSimulator()));
213 setRunUntilPanel(new RunUntilPanel.TimeFloat(getSimulator()));
214 }
215 }
216
217 /**
218 * DEVS Real Time ControlPanel for a Long timeunit.
219 * <p>
220 * Copyright (c) 2020-2023 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved.
221 * See for project information <a href="https://simulation.tudelft.nl/dsol/manual/" target="_blank">DSOL Manual</a>. The
222 * DSOL project is distributed under a three-clause BSD-style license, which can be found at
223 * <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">DSOL License</a>.
224 * </p>
225 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
226 */
227 public static class TimeLong extends RealTimeControlPanel<Long, DevsRealTimeAnimator<Long>>
228 {
229 /** */
230 private static final long serialVersionUID = 20201227L;
231
232 /**
233 * Construct a real time control panel for a Long time unit, with a different set of control buttons. The control panel
234 * assumes a DevsSimulator and animation. The model specification is not necessarily specified as "real time"; its
235 * execution is.
236 * @param model DsolModel<Long>; the model for the control panel, to allow a reset of the model
237 * @param simulator DevsRealTimeAnimator<Long>; the simulator. Specified separately, because the model can have been
238 * specified with a superclass of the simulator that the ControlPanel actually needs (e.g., model has been
239 * specified with a DevsAnimator, whereas the panel needs a RealTimeControlAnimator)
240 * @throws RemoteException when simulator cannot be accessed for listener attachment
241 */
242 public TimeLong(final DsolModel<Long, ? extends DevsSimulatorInterface<Long>> model,
243 final DevsRealTimeAnimator<Long> simulator) throws RemoteException
244 {
245 super(model, simulator);
246 setClockPanel(new ClockPanel.TimeLong(getSimulator()));
247 setSpeedPanel(new SpeedPanel.TimeLong(getSimulator()));
248 setRunUntilPanel(new RunUntilPanel.TimeLong(getSimulator()));
249 }
250 }
251
252 /**
253 * DEVS Real Time ControlPanel for a djunits double timeunit.
254 * <p>
255 * Copyright (c) 2020-2023 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved.
256 * See for project information <a href="https://simulation.tudelft.nl/dsol/manual/" target="_blank">DSOL Manual</a>. The
257 * DSOL project is distributed under a three-clause BSD-style license, which can be found at
258 * <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">DSOL License</a>.
259 * </p>
260 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
261 */
262 public static class TimeDoubleUnit extends RealTimeControlPanel<Duration, DevsRealTimeAnimator<Duration>>
263 {
264 /** */
265 private static final long serialVersionUID = 20201227L;
266
267 /**
268 * Construct a real time control panel for a djunits double time unit, with a different set of control buttons. The
269 * control panel assumes a DevsSimulator and animation. The model specification is not necessarily specified as "real
270 * time"; its execution is.
271 * @param model DsolModel<Duration>; the model for the control panel, to allow a reset of the model
272 * @param simulator DevsRealTimeAnimator<Duration>; the simulator. Specified separately, because the model can have been
273 * specified with a superclass of the simulator that the ControlPanel actually needs (e.g., model has been
274 * specified with a DevsAnimator, whereas the panel needs a RealTimeControlAnimator)
275 * @throws RemoteException when simulator cannot be accessed for listener attachment
276 */
277 public TimeDoubleUnit(final DsolModel<Duration, ? extends DevsSimulatorInterface<Duration>> model,
278 final DevsRealTimeAnimator<Duration> simulator) throws RemoteException
279 {
280 super(model, simulator);
281 setClockPanel(new ClockPanel.TimeDoubleUnit(getSimulator()));
282 setSpeedPanel(new SpeedPanel.TimeDoubleUnit(getSimulator()));
283 setRunUntilPanel(new RunUntilPanel.TimeDoubleUnit(getSimulator()));
284 }
285 }
286
287 /**
288 * DEVS Real Time ControlPanel for a djunits float timeunit.
289 * <p>
290 * Copyright (c) 2020-2023 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved.
291 * See for project information <a href="https://simulation.tudelft.nl/dsol/manual/" target="_blank">DSOL Manual</a>. The
292 * DSOL project is distributed under a three-clause BSD-style license, which can be found at
293 * <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">DSOL License</a>.
294 * </p>
295 * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
296 */
297 public static class TimeFloatUnit extends RealTimeControlPanel<FloatDuration, DevsRealTimeAnimator<FloatDuration>>
298 {
299 /** */
300 private static final long serialVersionUID = 20201227L;
301
302 /**
303 * Construct a real time control panel for a djunits float time unit, with a different set of control buttons. The
304 * control panel assumes a DevsSimulator and animation. The model specification is not necessarily specified as "real
305 * time"; its execution is.
306 * @param model DsolModel<FloatDuration>; the model for the control panel, to allow a reset of the model
307 * @param simulator DevsRealTimeAnimator<FloatDuration>; the simulator. Specified separately, because the model can have
308 * been specified with a superclass of the simulator that the ControlPanel actually needs (e.g., model has
309 * been specified with a DevsAnimator, whereas the panel needs a RealTimeControlAnimator)
310 * @throws RemoteException when simulator cannot be accessed for listener attachment
311 */
312 public TimeFloatUnit(final DsolModel<FloatDuration, ? extends DevsSimulatorInterface<FloatDuration>> model,
313 final DevsRealTimeAnimator<FloatDuration> simulator) throws RemoteException
314 {
315 super(model, simulator);
316 setClockPanel(new ClockPanel.TimeFloatUnit(getSimulator()));
317 setSpeedPanel(new SpeedPanel.TimeFloatUnit(getSimulator()));
318 setRunUntilPanel(new RunUntilPanel.TimeFloatUnit(getSimulator()));
319 }
320 }
321
322 }