1 package org.opentrafficsim.gui;
2
3 import java.awt.BorderLayout;
4 import java.awt.Component;
5 import java.awt.Container;
6 import java.awt.Dimension;
7 import java.awt.event.ActionEvent;
8 import java.awt.event.ActionListener;
9 import java.awt.event.WindowEvent;
10 import java.awt.event.WindowListener;
11 import java.awt.geom.Rectangle2D;
12 import java.rmi.RemoteException;
13 import java.text.NumberFormat;
14 import java.util.ArrayList;
15 import java.util.HashMap;
16 import java.util.Map;
17
18 import javax.swing.BoxLayout;
19 import javax.swing.Icon;
20 import javax.swing.JButton;
21 import javax.swing.JCheckBox;
22 import javax.swing.JFrame;
23 import javax.swing.JLabel;
24 import javax.swing.JPanel;
25 import javax.swing.JToggleButton;
26
27 import org.opentrafficsim.base.modelproperties.PropertyException;
28 import org.opentrafficsim.core.gtu.animation.GTUColorer;
29 import org.opentrafficsim.simulationengine.SimpleAnimator;
30 import org.opentrafficsim.simulationengine.WrappableAnimation;
31
32 import nl.javel.gisbeans.map.MapInterface;
33 import nl.tudelft.simulation.dsol.animation.Locatable;
34 import nl.tudelft.simulation.dsol.animation.D2.AnimationPanel;
35 import nl.tudelft.simulation.dsol.animation.D2.GisRenderable2D;
36 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
37 import nl.tudelft.simulation.event.Event;
38
39
40
41
42
43
44
45
46
47
48
49
50 public class OTSAnimationPanel extends OTSSimulationPanel implements ActionListener, WindowListener
51 {
52
53 private static final long serialVersionUID = 20150617L;
54
55
56 private final AnimationPanel animationPanel;
57
58
59 private final JPanel borderPanel;
60
61
62 private final JPanel togglePanel;
63
64
65 private Map<String, Class<? extends Locatable>> toggleLocatableMap = new HashMap<>();
66
67
68 private Map<String, MapInterface> toggleGISMap = new HashMap<>();
69
70
71 private Map<String, JToggleButton> toggleGISButtons = new HashMap<>();
72
73
74 private GTUColorer gtuColorer = null;
75
76
77 private ColorControlPanel colorControlPanel = null;
78
79
80 private final JLabel coordinateField;
81
82
83 private final ArrayList<JButton> buttons = new ArrayList<JButton>();
84
85
86 private static final NumberFormat FORMATTER = NumberFormat.getInstance();
87
88
89 @SuppressWarnings("checkstyle:visibilitymodifier")
90 protected boolean closeHandlerRegistered = false;
91
92
93 @SuppressWarnings("checkstyle:visibilitymodifier")
94 protected boolean windowExited = false;
95
96
97 static
98 {
99 FORMATTER.setMaximumFractionDigits(3);
100 }
101
102
103
104
105
106
107
108
109
110
111
112 public OTSAnimationPanel(final Rectangle2D extent, final Dimension size, final SimpleAnimator simulator,
113 final WrappableAnimation wrappableAnimation, final GTUColorer gtuColorer) throws RemoteException, PropertyException
114 {
115 super(simulator, wrappableAnimation);
116
117
118 this.animationPanel = new AnimationPanel(extent, size, simulator);
119 this.borderPanel = new JPanel(new BorderLayout());
120 this.borderPanel.add(this.animationPanel, BorderLayout.CENTER);
121 getTabbedPane().addTab(0, "animation", this.borderPanel);
122 getTabbedPane().setSelectedIndex(0);
123
124
125 this.gtuColorer = gtuColorer;
126 this.colorControlPanel = new ColorControlPanel(this.gtuColorer);
127 JPanel buttonPanel = new JPanel();
128 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
129 this.borderPanel.add(buttonPanel, BorderLayout.NORTH);
130 buttonPanel.add(this.colorControlPanel);
131
132
133 this.togglePanel = new JPanel();
134 this.togglePanel.setLayout(new BoxLayout(this.togglePanel, BoxLayout.Y_AXIS));
135 this.borderPanel.add(this.togglePanel, BorderLayout.WEST);
136
137
138 buttonPanel.add(new JLabel(" "));
139 buttonPanel.add(makeButton("allButton", "/Expand.png", "ZoomAll", "Zoom whole network", true));
140 buttonPanel.add(makeButton("homeButton", "/Home.png", "Home", "Zoom to original extent", true));
141 buttonPanel.add(makeButton("gridButton", "/Grid.png", "Grid", "Toggle grid on/off", true));
142 buttonPanel.add(new JLabel(" "));
143 this.coordinateField = new JLabel("Mouse: ");
144 this.coordinateField.setMinimumSize(new Dimension(250, 10));
145 this.coordinateField.setPreferredSize(new Dimension(250, 10));
146 buttonPanel.add(this.coordinateField);
147
148
149 this.animationPanel.notify(new Event(SimulatorInterface.START_REPLICATION_EVENT, simulator, null));
150
151
152 this.animationPanel.setShowToolTip(false);
153
154
155 new UpdateTimer().start();
156
157
158 installWindowCloseHandler();
159 }
160
161
162
163
164
165
166
167
168
169
170 private JButton makeButton(final String name, final String iconPath, final String actionCommand, final String toolTipText,
171 final boolean enabled)
172 {
173
174 JButton result = new JButton(OTSControlPanel.loadIcon(iconPath));
175 result.setPreferredSize(new Dimension(34, 32));
176 result.setName(name);
177 result.setEnabled(enabled);
178 result.setActionCommand(actionCommand);
179 result.setToolTipText(toolTipText);
180 result.addActionListener(this);
181 this.buttons.add(result);
182 return result;
183 }
184
185
186
187
188
189
190
191
192
193
194
195
196 public final void addToggleAnimationButtonIcon(final String name, final Class<? extends Locatable> locatableClass,
197 final String iconPath, final String toolTipText, final boolean initiallyVisible, final boolean idButton)
198 {
199 JToggleButton button;
200 Icon icon = OTSControlPanel.loadIcon(iconPath);
201 button = new JCheckBox(icon);
202 button.setPreferredSize(new Dimension(32, 28));
203 button.setName(name);
204 button.setEnabled(true);
205 button.setSelected(initiallyVisible);
206 button.setActionCommand(name);
207 button.setToolTipText(toolTipText);
208 button.addActionListener(this);
209
210
211 if (idButton && this.togglePanel.getComponentCount() > 0)
212 {
213 JPanel lastToggleBox = (JPanel) this.togglePanel.getComponent(this.togglePanel.getComponentCount() - 1);
214 lastToggleBox.add(button);
215 }
216 else
217 {
218 JPanel toggleBox = new JPanel();
219 toggleBox.setLayout(new BoxLayout(toggleBox, BoxLayout.X_AXIS));
220 toggleBox.add(button);
221 this.togglePanel.add(toggleBox);
222 toggleBox.setAlignmentX(Component.LEFT_ALIGNMENT);
223 }
224
225 if (initiallyVisible)
226 {
227 this.animationPanel.showClass(locatableClass);
228 }
229 else
230 {
231 this.animationPanel.hideClass(locatableClass);
232 }
233 this.toggleLocatableMap.put(name, locatableClass);
234 }
235
236
237
238
239
240
241
242
243 public final void addToggleAnimationButtonText(final String name, final Class<? extends Locatable> locatableClass,
244 final String toolTipText, final boolean initiallyVisible)
245 {
246 JToggleButton button;
247 button = new JCheckBox(name);
248 button.setName(name);
249 button.setEnabled(true);
250 button.setSelected(initiallyVisible);
251 button.setActionCommand(name);
252 button.setToolTipText(toolTipText);
253 button.addActionListener(this);
254
255 JPanel toggleBox = new JPanel();
256 toggleBox.setLayout(new BoxLayout(toggleBox, BoxLayout.X_AXIS));
257 toggleBox.add(button);
258 this.togglePanel.add(toggleBox);
259 toggleBox.setAlignmentX(Component.LEFT_ALIGNMENT);
260
261 if (initiallyVisible)
262 {
263 this.animationPanel.showClass(locatableClass);
264 }
265 else
266 {
267 this.animationPanel.hideClass(locatableClass);
268 }
269 this.toggleLocatableMap.put(name, locatableClass);
270 }
271
272
273
274
275
276 public final void addToggleText(final String text)
277 {
278 JPanel textBox = new JPanel();
279 textBox.setLayout(new BoxLayout(textBox, BoxLayout.X_AXIS));
280 textBox.add(new JLabel(text));
281 this.togglePanel.add(textBox);
282 textBox.setAlignmentX(Component.LEFT_ALIGNMENT);
283 }
284
285
286
287
288
289
290
291
292 public final void addToggleGISButtonText(final String layerName, final String displayName, final GisRenderable2D gisMap,
293 final String toolTipText)
294 {
295 JToggleButton button;
296 button = new JCheckBox(displayName);
297 button.setName(layerName);
298 button.setEnabled(true);
299 button.setSelected(true);
300 button.setActionCommand(layerName);
301 button.setToolTipText(toolTipText);
302 button.addActionListener(this);
303
304 JPanel toggleBox = new JPanel();
305 toggleBox.setLayout(new BoxLayout(toggleBox, BoxLayout.X_AXIS));
306 toggleBox.add(button);
307 this.togglePanel.add(toggleBox);
308 toggleBox.setAlignmentX(Component.LEFT_ALIGNMENT);
309
310 this.toggleGISMap.put(layerName, gisMap.getMap());
311 this.toggleGISButtons.put(layerName, button);
312 }
313
314
315
316
317
318 public final void showGISLayer(final String layerName)
319 {
320 MapInterface gisMap = this.toggleGISMap.get(layerName);
321 if (gisMap != null)
322 {
323 try
324 {
325 gisMap.showLayer(layerName);
326 this.toggleGISButtons.get(layerName).setSelected(true);
327 this.animationPanel.repaint();
328 }
329 catch (RemoteException exception)
330 {
331 exception.printStackTrace();
332 }
333 }
334 }
335
336
337
338
339
340 public final void hideGISLayer(final String layerName)
341 {
342 MapInterface gisMap = this.toggleGISMap.get(layerName);
343 if (gisMap != null)
344 {
345 try
346 {
347 gisMap.hideLayer(layerName);
348 this.toggleGISButtons.get(layerName).setSelected(false);
349 this.animationPanel.repaint();
350 }
351 catch (RemoteException exception)
352 {
353 exception.printStackTrace();
354 }
355 }
356 }
357
358
359
360
361
362 public final void toggleGISLayer(final String layerName)
363 {
364 MapInterface gisMap = this.toggleGISMap.get(layerName);
365 if (gisMap != null)
366 {
367 try
368 {
369 if (gisMap.getVisibleLayers().contains(gisMap.getLayerMap().get(layerName)))
370 {
371 gisMap.hideLayer(layerName);
372 this.toggleGISButtons.get(layerName).setSelected(false);
373 }
374 else
375 {
376 gisMap.showLayer(layerName);
377 this.toggleGISButtons.get(layerName).setSelected(true);
378 }
379 this.animationPanel.repaint();
380 }
381 catch (RemoteException exception)
382 {
383 exception.printStackTrace();
384 }
385 }
386 }
387
388
389 @Override
390 public final void actionPerformed(final ActionEvent actionEvent)
391 {
392 String actionCommand = actionEvent.getActionCommand();
393 try
394 {
395 if (actionCommand.equals("Home"))
396 {
397 this.animationPanel.home();
398 }
399 if (actionCommand.equals("ZoomAll"))
400 {
401 this.animationPanel.zoomAll();
402 }
403 if (actionCommand.equals("Grid"))
404 {
405 this.animationPanel.showGrid(!this.animationPanel.isShowGrid());
406 }
407
408 if (this.toggleLocatableMap.containsKey(actionCommand))
409 {
410 Class<? extends Locatable> locatableClass = this.toggleLocatableMap.get(actionCommand);
411 this.animationPanel.toggleClass(locatableClass);
412 this.togglePanel.repaint();
413 }
414
415 if (this.toggleGISMap.containsKey(actionCommand))
416 {
417 this.toggleGISLayer(actionCommand);
418 this.togglePanel.repaint();
419 }
420 }
421 catch (Exception exception)
422 {
423 exception.printStackTrace();
424 }
425 }
426
427
428
429
430
431 public final AnimationPanel getAnimationPanel()
432 {
433 return this.animationPanel;
434 }
435
436
437
438
439 protected final void updateWorldCoordinate()
440 {
441 String worldPoint = "(x=" + FORMATTER.format(this.animationPanel.getWorldCoordinate().getX()) + " ; y="
442 + FORMATTER.format(this.animationPanel.getWorldCoordinate().getY()) + ")";
443 this.coordinateField.setText("Mouse: " + worldPoint);
444 this.coordinateField.repaint();
445 }
446
447
448
449
450
451
452 public final GTUColorer getGTUColorer()
453 {
454 return this.gtuColorer;
455 }
456
457
458
459
460
461
462 public final ColorControlPanel getColorControlPanel()
463 {
464 return this.colorControlPanel;
465 }
466
467
468
469
470 public final void installWindowCloseHandler()
471 {
472 if (this.closeHandlerRegistered)
473 {
474 return;
475 }
476
477
478 new DisposeOnCloseThread(this).start();
479 }
480
481
482 protected class DisposeOnCloseThread extends Thread
483 {
484
485 private OTSAnimationPanel panel;
486
487
488
489
490 public DisposeOnCloseThread(final OTSAnimationPanel panel)
491 {
492 super();
493 this.panel = panel;
494 }
495
496
497 @Override
498 public final void run()
499 {
500 Container root = this.panel;
501 while (!(root instanceof JFrame))
502 {
503 try
504 {
505 Thread.sleep(10);
506 }
507 catch (InterruptedException exception)
508 {
509
510 }
511
512
513 root = this.panel;
514 while (null != root.getParent() && !(root instanceof JFrame))
515 {
516 root = root.getParent();
517 }
518 }
519 JFrame frame = (JFrame) root;
520 frame.addWindowListener(this.panel);
521 this.panel.closeHandlerRegistered = true;
522 }
523
524
525 @Override
526 public final String toString()
527 {
528 return "DisposeOnCloseThread of OTSAnimationPanel [panel=" + this.panel + "]";
529 }
530 }
531
532
533 @Override
534 public void windowOpened(final WindowEvent e)
535 {
536
537 }
538
539
540 @Override
541 public final void windowClosing(final WindowEvent e)
542 {
543
544 }
545
546
547 @Override
548 public final void windowClosed(final WindowEvent e)
549 {
550 this.windowExited = true;
551 }
552
553
554 @Override
555 public final void windowIconified(final WindowEvent e)
556 {
557
558 }
559
560
561 @Override
562 public final void windowDeiconified(final WindowEvent e)
563 {
564
565 }
566
567
568 @Override
569 public final void windowActivated(final WindowEvent e)
570 {
571
572 }
573
574
575 @Override
576 public final void windowDeactivated(final WindowEvent e)
577 {
578
579 }
580
581
582
583
584 protected class UpdateTimer extends Thread
585 {
586
587 @Override
588 public final void run()
589 {
590 while (!OTSAnimationPanel.this.windowExited)
591 {
592 if (OTSAnimationPanel.this.isShowing())
593 {
594 OTSAnimationPanel.this.updateWorldCoordinate();
595 }
596 try
597 {
598 Thread.sleep(50);
599 }
600 catch (InterruptedException exception)
601 {
602
603 }
604 }
605 }
606
607
608 @Override
609 public final String toString()
610 {
611 return "UpdateTimer thread for OTSAnimationPanel";
612 }
613
614 }
615 }