View Javadoc
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&lt;T, ? extends DevsSimulationInterface&lt;T&gt;&gt;; 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&lt;Double&gt;; 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&lt;Float&gt;; the model for the control panel, to allow a reset of the model
202          * @param simulator DevsRealTimeAnimator&lt;Float&gt;; 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&lt;Long&gt;; the model for the control panel, to allow a reset of the model
237          * @param simulator DevsRealTimeAnimator&lt;Long&gt;; 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&lt;Duration&gt;; the model for the control panel, to allow a reset of the model
272          * @param simulator DevsRealTimeAnimator&lt;Duration&gt;; 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&lt;FloatDuration&gt;; the model for the control panel, to allow a reset of the model
307          * @param simulator DevsRealTimeAnimator&lt;FloatDuration&gt;; 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 }