View Javadoc
1   package org.opentrafficsim.demo;
2   
3   import java.awt.Color;
4   import java.awt.Dimension;
5   import java.awt.Font;
6   import java.awt.HeadlessException;
7   import java.awt.event.ActionEvent;
8   import java.awt.event.ActionListener;
9   import java.lang.reflect.InvocationTargetException;
10  import java.lang.reflect.Method;
11  import java.util.ArrayList;
12  import java.util.List;
13  
14  import javax.swing.Box;
15  import javax.swing.JButton;
16  import javax.swing.JComponent;
17  import javax.swing.JFrame;
18  import javax.swing.JLabel;
19  import javax.swing.JOptionPane;
20  import javax.swing.JScrollPane;
21  import javax.swing.JSeparator;
22  import javax.swing.JTextArea;
23  import javax.swing.ScrollPaneConstants;
24  import javax.swing.WindowConstants;
25  
26  import org.djutils.reflection.ClassUtil;
27  import org.opentrafficsim.core.dsol.OtsModelInterface;
28  import org.opentrafficsim.demo.conflict.TJunctionDemo;
29  import org.opentrafficsim.demo.conflict.TurboRoundaboutDemo;
30  import org.opentrafficsim.demo.trafficcontrol.TrafCodDemo2;
31  import org.opentrafficsim.swing.gui.OtsSwingApplication;
32  
33  /**
34   * SuperDemo.java.
35   * <p>
36   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
37   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
38   * </p>
39   * @author <a href="https://github.com/averbraeck" target="_blank">Alexander Verbraeck</a>
40   */
41  public class SuperDemo extends JFrame
42  {
43      /** */
44      private static final long serialVersionUID = 1L;
45  
46      /** demos to show. */
47      private List<Demo> demos = new ArrayList<>();
48  
49      /**
50       * Construct a mode chooser that can start different models.
51       * @throws HeadlessException when not run in graphics environment
52       */
53      public SuperDemo() throws HeadlessException
54      {
55          super("OTS demo models");
56          setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
57          setMinimumSize(new Dimension(1024, 20));
58          addDemos();
59          setContentPane(makeGUI());
60          pack();
61          setVisible(true);
62      }
63  
64      /**
65       * Add the demos to the list.
66       */
67      private void addDemos()
68      {
69          this.demos.add(new Demo("Straight", StraightSwing.class, "Single lane road with a blockage for a while.\n"
70                  + "The model shows the dissolving of the congestion that occurs as a result."));
71          this.demos.add(new Demo("CircularRoad", CircularRoadSwing.class, "Model of a two-lane circular road with overtaking.\n"
72                  + "Users can specify the fraction of cars and trucks, as well as some driving parameters."));
73          this.demos.add(new Demo("ShortMerge", ShortMerge.class, "Short merge on a highway, followed by a destination split,\n"
74                  + "forcing cars to change lanes in a relative short distance."));
75          this.demos.add(new Demo("TJunction", TJunctionDemo.class,
76                  "Complex crossing traffic on a T-junction with\n" + "automated conflict resolution."));
77          this.demos.add(new Demo("TurboRoundabout", TurboRoundaboutDemo.class,
78                  "Turbo Roundabout without traffic lights,\n" + "conflict resolution is fully automated."));
79          this.demos.add(new Demo("Networks", NetworksSwing.class,
80                  "A number of different networks with merging and splitting,\n" + "forcing cars to change lanes and to merge."));
81          this.demos.add(new Demo("TrafCODDemoComplex", TrafCodDemo2.class,
82                  "Model of a complex crossing with traffic lights.\n" + "using a TrafCOD controller"));
83      }
84  
85      /**
86       * @return a grid with model start buttons and short model descriptions.
87       */
88      private JComponent makeGUI()
89      {
90          Box table = Box.createVerticalBox();
91          table.setBackground(Color.WHITE);
92          table.setOpaque(true);
93          JScrollPane scrollPane = new JScrollPane(table, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
94                  ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
95          int maxButtonWidth = 0;
96          table.add(Box.createRigidArea(new Dimension(0, 3)));
97          Box headerBox = Box.createHorizontalBox();
98          JLabel header = new JLabel(" OpenTrafficSim demo's ");
99          header.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 36));
100         headerBox.add(header);
101         headerBox.add(Box.createHorizontalGlue());
102         table.add(headerBox);
103         table.add(Box.createRigidArea(new Dimension(0, 3)));
104         table.add(new JSeparator());
105         for (Demo demo : this.demos)
106         {
107             table.add(Box.createRigidArea(new Dimension(0, 3)));
108             Box row = Box.createHorizontalBox();
109             row.add(new JLabel("  "));
110             row.add(demo.getButton());
111             row.add(new JLabel("  "));
112             JTextArea description = new JTextArea();
113             description.setText(demo.getDescription());
114             description.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, 16));
115             description.setEditable(false);
116             description.setWrapStyleWord(true);
117             description.setLineWrap(true);
118             row.add(description);
119             row.add(Box.createHorizontalGlue());
120             row.add(new JLabel("  "));
121             table.add(row);
122             table.add(Box.createRigidArea(new Dimension(0, 3)));
123             table.add(new JSeparator());
124             maxButtonWidth = Math.max(maxButtonWidth, demo.getButton().getPreferredSize().width);
125         }
126 
127         for (Demo demo : this.demos)
128         {
129             demo.getButton().setPreferredSize(new Dimension(maxButtonWidth, demo.getButton().getPreferredSize().height));
130         }
131 
132         table.add(Box.createVerticalGlue());
133 
134         return scrollPane;
135     }
136 
137     /**
138      * @param args String[]; should be empty
139      */
140     public static void main(final String[] args)
141     {
142         new SuperDemo();
143     }
144 
145     /** the class to prevent the models from exiting the whole SuperDemo application. */
146     static class NoExitSecurityManager extends SecurityManager
147     {
148         @Override
149         public void checkExit(final int status)
150         {
151             throw new SecurityException();
152         }
153     }
154 
155     /** the information about the demos. */
156     private static class Demo implements ActionListener
157     {
158         /** the demo name. */
159         @SuppressWarnings("checkstyle:visibilitymodifier")
160         protected final String name;
161 
162         /** the start button for the demo. */
163         private final JButton button;
164 
165         /** the demo class. */
166         @SuppressWarnings("checkstyle:visibilitymodifier")
167         protected final Class<? extends OtsSwingApplication<? extends OtsModelInterface>> clazz;
168 
169         /** the demo description. */
170         private final String description;
171 
172         /**
173          * @param name String; the demo name
174          * @param clazz Class&lt;? extends OtsSwingApplication&gt;; the demo class
175          * @param description String; the demo description
176          */
177         Demo(final String name, final Class<? extends OtsSwingApplication<? extends OtsModelInterface>> clazz,
178                 final String description)
179         {
180             this.name = name;
181             this.button = new JButton(name);
182             this.button.addActionListener(this);
183             this.clazz = clazz;
184             this.description = description;
185         }
186 
187         /**
188          * @return the button to tart the demo
189          */
190         public final JButton getButton()
191         {
192             return this.button;
193         }
194 
195         /**
196          * @return the demo description
197          */
198         public final String getDescription()
199         {
200             return this.description;
201         }
202 
203         /** {@inheritDoc} */
204         @Override
205         public void actionPerformed(final ActionEvent e)
206         {
207             try
208             {
209                 final Method demoMethod = ClassUtil.resolveMethod(this.clazz, "demo", new Class[] {boolean.class});
210                 Thread demo = new Thread(new Runnable()
211                 {
212                     @Override
213                     public void run()
214                     {
215                         try
216                         {
217                             Class.forName(Demo.this.clazz.getName());
218                             demoMethod.invoke(null, new Object[] {false});
219                         }
220                         catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
221                                 | ClassNotFoundException exception)
222                         {
223                             exception.printStackTrace();
224                             JOptionPane
225                                     .showMessageDialog(null,
226                                             "Method 'demo' for demo " + Demo.this.name + " cound not be started\n"
227                                                     + exception.getMessage(),
228                                             "Could not start demo", JOptionPane.ERROR_MESSAGE);
229                         }
230                     }
231                 });
232                 demo.start();
233             }
234             catch (NoSuchMethodException exception)
235             {
236                 JOptionPane.showMessageDialog(null, "Method 'demo' not found for demo " + this.name, "Could not start demo",
237                         JOptionPane.ERROR_MESSAGE);
238             }
239         }
240     }
241 }