1 package org.opentrafficsim.swing.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.Graphics;
8 import java.awt.event.ActionEvent;
9 import java.awt.event.ActionListener;
10 import java.awt.event.ContainerEvent;
11 import java.awt.event.ContainerListener;
12 import java.awt.event.MouseAdapter;
13 import java.awt.event.MouseEvent;
14 import java.awt.event.MouseListener;
15 import java.awt.event.MouseWheelEvent;
16 import java.awt.event.MouseWheelListener;
17 import java.awt.event.WindowEvent;
18 import java.awt.event.WindowListener;
19 import java.awt.geom.Point2D;
20 import java.awt.geom.Rectangle2D;
21 import java.rmi.RemoteException;
22 import java.text.NumberFormat;
23 import java.util.ArrayList;
24 import java.util.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import javax.swing.BoxLayout;
29 import javax.swing.Icon;
30 import javax.swing.JButton;
31 import javax.swing.JCheckBox;
32 import javax.swing.JFrame;
33 import javax.swing.JLabel;
34 import javax.swing.JPanel;
35 import javax.swing.JTextField;
36 import javax.swing.JToggleButton;
37 import javax.swing.border.EmptyBorder;
38
39 import org.djutils.event.Event;
40 import org.djutils.event.EventInterface;
41 import org.djutils.event.EventListenerInterface;
42 import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
43 import org.opentrafficsim.core.dsol.OTSAnimator;
44 import org.opentrafficsim.core.dsol.OTSModelInterface;
45 import org.opentrafficsim.core.gtu.GTU;
46 import org.opentrafficsim.core.network.Network;
47 import org.opentrafficsim.core.network.OTSNetwork;
48
49 import nl.javel.gisbeans.map.MapInterface;
50 import nl.tudelft.simulation.dsol.animation.Locatable;
51 import nl.tudelft.simulation.dsol.animation.D2.GisRenderable2D;
52 import nl.tudelft.simulation.dsol.animation.D2.Renderable2DInterface;
53 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
54 import nl.tudelft.simulation.dsol.swing.animation.D2.AnimationPanel;
55 import nl.tudelft.simulation.dsol.swing.animation.D2.GridPanel;
56 import nl.tudelft.simulation.dsol.swing.animation.D2.mouse.InputListener;
57 import nl.tudelft.simulation.language.DSOLException;
58 import nl.tudelft.simulation.language.d3.DirectedPoint;
59
60
61
62
63
64
65
66
67
68
69
70
71 public class OTSAnimationPanel extends OTSSimulationPanel implements ActionListener, WindowListener, EventListenerInterface
72 {
73
74 private static final long serialVersionUID = 20150617L;
75
76
77 private final AutoAnimationPanel animationPanel;
78
79
80 private final JPanel borderPanel;
81
82
83 private final JPanel togglePanel;
84
85
86 private JPanel demoPanel = null;
87
88
89 private Map<String, Class<? extends Locatable>> toggleLocatableMap = new LinkedHashMap<>();
90
91
92 private Map<Class<? extends Locatable>, JToggleButton> toggleButtons = new LinkedHashMap<>();
93
94
95 private Map<String, MapInterface> toggleGISMap = new LinkedHashMap<>();
96
97
98 private Map<String, JToggleButton> toggleGISButtons = new LinkedHashMap<>();
99
100
101 private GTUColorer gtuColorer = null;
102
103
104 private ColorControlPanel colorControlPanel = null;
105
106
107 private final JLabel coordinateField;
108
109
110 private final JLabel gtuCountField;
111
112
113 private int gtuCount = 0;
114
115
116 private final ArrayList<JButton> buttons = new ArrayList<>();
117
118
119 private static final NumberFormat FORMATTER = NumberFormat.getInstance();
120
121
122 @SuppressWarnings("checkstyle:visibilitymodifier")
123 protected boolean closeHandlerRegistered = false;
124
125
126 @SuppressWarnings("checkstyle:visibilitymodifier")
127 protected boolean windowExited = false;
128
129
130 private boolean autoPan = false;
131
132
133 private final JCheckBox autoPanToggle;
134
135
136 private final JTextField autoPanField;
137
138
139 static
140 {
141 FORMATTER.setMaximumFractionDigits(3);
142 }
143
144
145
146
147
148
149
150
151
152
153
154
155 public OTSAnimationPanel(final Rectangle2D extent, final Dimension size, final OTSAnimator simulator,
156 final OTSModelInterface otsModel, final GTUColorer gtuColorer, final OTSNetwork network)
157 throws RemoteException, DSOLException
158 {
159 super(simulator, otsModel);
160
161
162
163 this.animationPanel = new AutoAnimationPanel(extent, size, simulator, network);
164 this.animationPanel.showGrid(false);
165 this.borderPanel = new JPanel(new BorderLayout());
166 this.borderPanel.add(this.animationPanel, BorderLayout.CENTER);
167 getTabbedPane().addTab(0, "animation", this.borderPanel);
168 getTabbedPane().setSelectedIndex(0);
169
170
171 this.gtuColorer = gtuColorer;
172 this.colorControlPanel = new ColorControlPanel(this.gtuColorer);
173 JPanel buttonPanel = new JPanel();
174 buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
175 this.borderPanel.add(buttonPanel, BorderLayout.NORTH);
176 buttonPanel.add(this.colorControlPanel);
177
178
179 this.togglePanel = new JPanel();
180 this.togglePanel.setLayout(new BoxLayout(this.togglePanel, BoxLayout.Y_AXIS));
181 this.borderPanel.add(this.togglePanel, BorderLayout.WEST);
182
183
184 buttonPanel.add(new JLabel(" "));
185 buttonPanel.add(makeButton("allButton", "/Expand.png", "ZoomAll", "Zoom whole network", true));
186 buttonPanel.add(makeButton("homeButton", "/Home.png", "Home", "Zoom to original extent", true));
187 buttonPanel.add(makeButton("gridButton", "/Grid.png", "Grid", "Toggle grid on/off", true));
188 buttonPanel.add(new JLabel(" "));
189
190
191 JPanel infoTextPanel = new JPanel();
192 buttonPanel.add(infoTextPanel);
193 infoTextPanel.setMinimumSize(new Dimension(250, 20));
194 infoTextPanel.setPreferredSize(new Dimension(250, 20));
195 infoTextPanel.setLayout(new BoxLayout(infoTextPanel, BoxLayout.Y_AXIS));
196 this.coordinateField = new JLabel("Mouse: ");
197 this.coordinateField.setMinimumSize(new Dimension(250, 10));
198 this.coordinateField.setPreferredSize(new Dimension(250, 10));
199 infoTextPanel.add(this.coordinateField);
200
201 JPanel gtuPanel = new JPanel();
202 gtuPanel.setAlignmentX(0.0f);
203 gtuPanel.setLayout(new BoxLayout(gtuPanel, BoxLayout.X_AXIS));
204 gtuPanel.setMinimumSize(new Dimension(250, 10));
205 gtuPanel.setPreferredSize(new Dimension(250, 10));
206 infoTextPanel.add(gtuPanel);
207 if (null != network)
208 {
209 network.addListener(this, Network.GTU_ADD_EVENT);
210 network.addListener(this, Network.GTU_REMOVE_EVENT);
211 }
212
213
214 class AppearanceTextField extends JTextField implements AppearanceControl
215 {
216 private static final long serialVersionUID = 20180430L;
217
218
219 @Override
220 public String toString()
221 {
222 return "AppearanceTextField []";
223 }
224 }
225 this.autoPanField = new AppearanceTextField();
226 this.autoPanField.setMaximumSize(new Dimension(100, 20));
227 this.autoPanField.setVisible(false);
228 this.autoPanField.addActionListener(new ActionListener()
229 {
230 @SuppressWarnings("synthetic-access")
231 @Override
232 public void actionPerformed(final ActionEvent e)
233 {
234 OTSAnimationPanel.this.animationPanel.repaint();
235 }
236 });
237 this.autoPanToggle = new JCheckBox();
238 this.autoPanToggle.setToolTipText("Pan to GTU");
239 this.autoPanToggle.addActionListener(new ActionListener()
240 {
241 @SuppressWarnings("synthetic-access")
242 @Override
243 public void actionPerformed(final ActionEvent e)
244 {
245 OTSAnimationPanel.this.autoPan = !OTSAnimationPanel.this.autoPanField.isVisible();
246 OTSAnimationPanel.this.autoPanField.setVisible(OTSAnimationPanel.this.autoPan);
247 if (OTSAnimationPanel.this.autoPan)
248 {
249 OTSAnimationPanel.this.autoPanField.requestFocusInWindow();
250 OTSAnimationPanel.this.autoPanField.selectAll();
251 }
252 gtuPanel.revalidate();
253 }
254 });
255 gtuPanel.add(this.autoPanToggle);
256 gtuPanel.add(this.autoPanField);
257
258 this.gtuCountField = new JLabel("0 GTU's");
259 this.gtuCount = null == network ? 0 : network.getGTUs().size();
260 gtuPanel.add(this.gtuCountField);
261 setGtuCountText();
262
263
264 this.animationPanel.notify(new Event(SimulatorInterface.START_REPLICATION_EVENT, simulator.getSourceId(), null));
265
266
267 this.animationPanel.setShowToolTip(false);
268
269
270 new UpdateTimer().start();
271
272
273 installWindowCloseHandler();
274
275 }
276
277
278
279
280
281
282
283
284
285
286 private JButton makeButton(final String name, final String iconPath, final String actionCommand, final String toolTipText,
287 final boolean enabled)
288 {
289
290 JButton result = new JButton(OTSControlPanel.loadIcon(iconPath));
291 result.setPreferredSize(new Dimension(34, 32));
292 result.setName(name);
293 result.setEnabled(enabled);
294 result.setActionCommand(actionCommand);
295 result.setToolTipText(toolTipText);
296 result.addActionListener(this);
297 this.buttons.add(result);
298 return result;
299 }
300
301
302
303
304
305
306
307
308
309
310
311
312 public final void addToggleAnimationButtonIcon(final String name, final Class<? extends Locatable> locatableClass,
313 final String iconPath, final String toolTipText, final boolean initiallyVisible, final boolean idButton)
314 {
315 JToggleButton button;
316 Icon icon = OTSControlPanel.loadIcon(iconPath);
317 Icon unIcon = OTSControlPanel.loadGrayscaleIcon(iconPath);
318 button = new JCheckBox();
319 button.setSelectedIcon(icon);
320 button.setIcon(unIcon);
321 button.setPreferredSize(new Dimension(32, 28));
322 button.setName(name);
323 button.setEnabled(true);
324 button.setSelected(initiallyVisible);
325 button.setActionCommand(name);
326 button.setToolTipText(toolTipText);
327 button.addActionListener(this);
328
329
330 if (idButton && this.togglePanel.getComponentCount() > 0)
331 {
332 JPanel lastToggleBox = (JPanel) this.togglePanel.getComponent(this.togglePanel.getComponentCount() - 1);
333 lastToggleBox.add(button);
334 }
335 else
336 {
337 JPanel toggleBox = new JPanel();
338 toggleBox.setLayout(new BoxLayout(toggleBox, BoxLayout.X_AXIS));
339 toggleBox.add(button);
340 this.togglePanel.add(toggleBox);
341 toggleBox.setAlignmentX(Component.LEFT_ALIGNMENT);
342 }
343
344 if (initiallyVisible)
345 {
346 this.animationPanel.showClass(locatableClass);
347 }
348 else
349 {
350 this.animationPanel.hideClass(locatableClass);
351 }
352 this.toggleLocatableMap.put(name, locatableClass);
353 this.toggleButtons.put(locatableClass, button);
354 }
355
356
357
358
359
360
361
362
363 public final void addToggleAnimationButtonText(final String name, final Class<? extends Locatable> locatableClass,
364 final String toolTipText, final boolean initiallyVisible)
365 {
366 JToggleButton button;
367 button = new JCheckBox(name);
368 button.setName(name);
369 button.setEnabled(true);
370 button.setSelected(initiallyVisible);
371 button.setActionCommand(name);
372 button.setToolTipText(toolTipText);
373 button.addActionListener(this);
374
375 JPanel toggleBox = new JPanel();
376 toggleBox.setLayout(new BoxLayout(toggleBox, BoxLayout.X_AXIS));
377 toggleBox.add(button);
378 this.togglePanel.add(toggleBox);
379 toggleBox.setAlignmentX(Component.LEFT_ALIGNMENT);
380
381 if (initiallyVisible)
382 {
383 this.animationPanel.showClass(locatableClass);
384 }
385 else
386 {
387 this.animationPanel.hideClass(locatableClass);
388 }
389 this.toggleLocatableMap.put(name, locatableClass);
390 this.toggleButtons.put(locatableClass, button);
391 }
392
393
394
395
396
397 public final void addToggleText(final String text)
398 {
399 JPanel textBox = new JPanel();
400 textBox.setLayout(new BoxLayout(textBox, BoxLayout.X_AXIS));
401 textBox.add(new JLabel(text));
402 this.togglePanel.add(textBox);
403 textBox.setAlignmentX(Component.LEFT_ALIGNMENT);
404 }
405
406
407
408
409
410
411
412 public final void addAllToggleGISButtonText(final String header, final GisRenderable2D gisMap, final String toolTipText)
413 {
414 addToggleText(" ");
415 addToggleText(header);
416 try
417 {
418 for (String layerName : gisMap.getMap().getLayerMap().keySet())
419 {
420 addToggleGISButtonText(layerName, layerName, gisMap, toolTipText);
421 }
422 }
423 catch (RemoteException exception)
424 {
425 exception.printStackTrace();
426 }
427 }
428
429
430
431
432
433
434
435
436 public final void addToggleGISButtonText(final String layerName, final String displayName, final GisRenderable2D gisMap,
437 final String toolTipText)
438 {
439 JToggleButton button;
440 button = new JCheckBox(displayName);
441 button.setName(layerName);
442 button.setEnabled(true);
443 button.setSelected(true);
444 button.setActionCommand(layerName);
445 button.setToolTipText(toolTipText);
446 button.addActionListener(this);
447
448 JPanel toggleBox = new JPanel();
449 toggleBox.setLayout(new BoxLayout(toggleBox, BoxLayout.X_AXIS));
450 toggleBox.add(button);
451 this.togglePanel.add(toggleBox);
452 toggleBox.setAlignmentX(Component.LEFT_ALIGNMENT);
453
454 this.toggleGISMap.put(layerName, gisMap.getMap());
455 this.toggleGISButtons.put(layerName, button);
456 }
457
458
459
460
461
462 public final void showGISLayer(final String layerName)
463 {
464 MapInterface gisMap = this.toggleGISMap.get(layerName);
465 if (gisMap != null)
466 {
467 try
468 {
469 gisMap.showLayer(layerName);
470 this.toggleGISButtons.get(layerName).setSelected(true);
471 this.animationPanel.repaint();
472 }
473 catch (RemoteException exception)
474 {
475 exception.printStackTrace();
476 }
477 }
478 }
479
480
481
482
483
484 public final void hideGISLayer(final String layerName)
485 {
486 MapInterface gisMap = this.toggleGISMap.get(layerName);
487 if (gisMap != null)
488 {
489 try
490 {
491 gisMap.hideLayer(layerName);
492 this.toggleGISButtons.get(layerName).setSelected(false);
493 this.animationPanel.repaint();
494 }
495 catch (RemoteException exception)
496 {
497 exception.printStackTrace();
498 }
499 }
500 }
501
502
503
504
505
506 public final void toggleGISLayer(final String layerName)
507 {
508 MapInterface gisMap = this.toggleGISMap.get(layerName);
509 if (gisMap != null)
510 {
511 try
512 {
513 if (gisMap.getVisibleLayers().contains(gisMap.getLayerMap().get(layerName)))
514 {
515 gisMap.hideLayer(layerName);
516 this.toggleGISButtons.get(layerName).setSelected(false);
517 }
518 else
519 {
520 gisMap.showLayer(layerName);
521 this.toggleGISButtons.get(layerName).setSelected(true);
522 }
523 this.animationPanel.repaint();
524 }
525 catch (RemoteException exception)
526 {
527 exception.printStackTrace();
528 }
529 }
530 }
531
532
533 @Override
534 public final void actionPerformed(final ActionEvent actionEvent)
535 {
536 String actionCommand = actionEvent.getActionCommand();
537
538 try
539 {
540 if (actionCommand.equals("Home"))
541 {
542 this.animationPanel.home();
543 }
544 if (actionCommand.equals("ZoomAll"))
545 {
546 this.animationPanel.zoomAll();
547 }
548 if (actionCommand.equals("Grid"))
549 {
550 this.animationPanel.showGrid(!this.animationPanel.isShowGrid());
551 }
552
553 if (this.toggleLocatableMap.containsKey(actionCommand))
554 {
555 Class<? extends Locatable> locatableClass = this.toggleLocatableMap.get(actionCommand);
556 this.animationPanel.toggleClass(locatableClass);
557 this.togglePanel.repaint();
558 }
559
560 if (this.toggleGISMap.containsKey(actionCommand))
561 {
562 this.toggleGISLayer(actionCommand);
563 this.togglePanel.repaint();
564 }
565 }
566 catch (Exception exception)
567 {
568 exception.printStackTrace();
569 }
570 }
571
572
573
574
575
576 public final AnimationPanel getAnimationPanel()
577 {
578 return this.animationPanel;
579 }
580
581
582
583
584
585 public JPanel getDemoPanel()
586 {
587 if (this.demoPanel == null)
588 {
589 this.demoPanel = new JPanel();
590 this.demoPanel.setLayout(new BoxLayout(this.demoPanel, BoxLayout.Y_AXIS));
591 this.demoPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
592 this.demoPanel.setPreferredSize(new Dimension(300, 300));
593 getAnimationPanel().getParent().add(this.demoPanel, BorderLayout.EAST);
594 this.demoPanel.addContainerListener(new ContainerListener()
595 {
596 @Override
597 public void componentAdded(final ContainerEvent e)
598 {
599 try
600 {
601
602 }
603 catch (NullPointerException exception)
604 {
605
606 }
607 }
608
609 @Override
610 public void componentRemoved(final ContainerEvent e)
611 {
612
613 }
614 });
615 }
616 return this.demoPanel;
617 }
618
619
620
621
622
623 public final void updateAnimationClassCheckBox(final Class<? extends Locatable> locatableClass)
624 {
625 JToggleButton button = this.toggleButtons.get(locatableClass);
626 if (button == null)
627 {
628 return;
629 }
630 button.setSelected(getAnimationPanel().isShowClass(locatableClass));
631 }
632
633
634
635
636 protected final void updateWorldCoordinate()
637 {
638 String worldPoint = "(x=" + FORMATTER.format(this.animationPanel.getWorldCoordinate().getX()) + " ; y="
639 + FORMATTER.format(this.animationPanel.getWorldCoordinate().getY()) + ")";
640 this.coordinateField.setText("Mouse: " + worldPoint);
641 int requiredWidth = this.coordinateField.getGraphics().getFontMetrics().stringWidth(this.coordinateField.getText());
642 if (this.coordinateField.getPreferredSize().width < requiredWidth)
643 {
644 Dimension requiredSize = new Dimension(requiredWidth, this.coordinateField.getPreferredSize().height);
645 this.coordinateField.setPreferredSize(requiredSize);
646 this.coordinateField.setMinimumSize(requiredSize);
647 Container parent = this.coordinateField.getParent();
648 parent.setPreferredSize(requiredSize);
649 parent.setMinimumSize(requiredSize);
650
651 parent.revalidate();
652 }
653 this.coordinateField.repaint();
654 }
655
656
657
658
659
660
661 public final GTUColorer getGTUColorer()
662 {
663 return this.gtuColorer;
664 }
665
666
667
668
669
670
671 public final ColorControlPanel getColorControlPanel()
672 {
673 return this.colorControlPanel;
674 }
675
676
677
678
679 public final void installWindowCloseHandler()
680 {
681 if (this.closeHandlerRegistered)
682 {
683 return;
684 }
685
686
687 new DisposeOnCloseThread(this).start();
688 }
689
690
691 protected class DisposeOnCloseThread extends Thread
692 {
693
694 private OTSAnimationPanel panel;
695
696
697
698
699 public DisposeOnCloseThread(final OTSAnimationPanel panel)
700 {
701 super();
702 this.panel = panel;
703 }
704
705
706 @Override
707 public final void run()
708 {
709 Container root = this.panel;
710 while (!(root instanceof JFrame))
711 {
712 try
713 {
714 Thread.sleep(10);
715 }
716 catch (InterruptedException exception)
717 {
718
719 }
720
721
722 root = this.panel;
723 while (null != root.getParent() && !(root instanceof JFrame))
724 {
725 root = root.getParent();
726 }
727 }
728 JFrame frame = (JFrame) root;
729 frame.addWindowListener(this.panel);
730 this.panel.closeHandlerRegistered = true;
731 }
732
733
734 @Override
735 public final String toString()
736 {
737 return "DisposeOnCloseThread of OTSAnimationPanel [panel=" + this.panel + "]";
738 }
739 }
740
741
742 @Override
743 public void windowOpened(final WindowEvent e)
744 {
745
746 }
747
748
749 @Override
750 public final void windowClosing(final WindowEvent e)
751 {
752
753 }
754
755
756 @Override
757 public final void windowClosed(final WindowEvent e)
758 {
759 this.windowExited = true;
760 }
761
762
763 @Override
764 public final void windowIconified(final WindowEvent e)
765 {
766
767 }
768
769
770 @Override
771 public final void windowDeiconified(final WindowEvent e)
772 {
773
774 }
775
776
777 @Override
778 public final void windowActivated(final WindowEvent e)
779 {
780
781 }
782
783
784 @Override
785 public final void windowDeactivated(final WindowEvent e)
786 {
787
788 }
789
790
791 @Override
792 public void notify(final EventInterface event) throws RemoteException
793 {
794 if (event.getType().equals(Network.GTU_ADD_EVENT))
795 {
796 this.gtuCount++;
797 setGtuCountText();
798 }
799 else if (event.getType().equals(Network.GTU_REMOVE_EVENT))
800 {
801 this.gtuCount--;
802 setGtuCountText();
803 }
804 }
805
806
807
808
809 private void setGtuCountText()
810 {
811 this.gtuCountField.setText(this.gtuCount + " GTU's");
812 }
813
814
815
816
817 protected class UpdateTimer extends Thread
818 {
819
820 @Override
821 public final void run()
822 {
823 while (!OTSAnimationPanel.this.windowExited)
824 {
825 if (OTSAnimationPanel.this.isShowing())
826 {
827 OTSAnimationPanel.this.updateWorldCoordinate();
828 }
829 try
830 {
831 Thread.sleep(50);
832 }
833 catch (InterruptedException exception)
834 {
835
836 }
837 }
838 }
839
840
841 @Override
842 public final String toString()
843 {
844 return "UpdateTimer thread for OTSAnimationPanel";
845 }
846
847 }
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862 private class AutoAnimationPanel extends AnimationPanel
863 {
864
865
866 private static final long serialVersionUID = 20180430L;
867
868
869 private final OTSNetwork network;
870
871
872 private GTU lastGtu;
873
874
875
876
877
878
879
880
881
882
883 AutoAnimationPanel(final Rectangle2D extent, final Dimension size, final SimulatorInterface<?, ?, ?> simulator,
884 final OTSNetwork network) throws RemoteException, DSOLException
885 {
886 super(extent, size, simulator);
887 this.network = network;
888 MouseListener[] listeners = getMouseListeners();
889 for (MouseListener listener : listeners)
890 {
891 removeMouseListener(listener);
892 }
893 this.addMouseListener(new MouseAdapter()
894 {
895
896 @SuppressWarnings("synthetic-access")
897 @Override
898 public void mouseClicked(final MouseEvent e)
899 {
900 if (e.isControlDown())
901 {
902 GTU gtu = getSelectedGTU(e.getPoint());
903 if (gtu != null)
904 {
905 OTSAnimationPanel.this.autoPanField.setText(gtu.getId());
906 OTSAnimationPanel.this.autoPanField.setVisible(true);
907 OTSAnimationPanel.this.autoPanToggle.setSelected(true);
908 OTSAnimationPanel.this.autoPanToggle.getParent().validate();
909 OTSAnimationPanel.this.autoPan = true;
910 e.consume();
911 }
912 }
913 e.consume();
914 }
915 });
916 for (MouseListener listener : listeners)
917 {
918 addMouseListener(listener);
919 }
920
921 MouseWheelListener[] wheelListeners = getMouseWheelListeners();
922 for (MouseWheelListener wheelListener : wheelListeners)
923 {
924 removeMouseWheelListener(wheelListener);
925 }
926 this.addMouseWheelListener(new InputListener(this)
927 {
928
929 @Override
930 public void mouseWheelMoved(final MouseWheelEvent e)
931 {
932 if (e.isShiftDown())
933 {
934 int amount = e.getUnitsToScroll();
935 if (amount > 0)
936 {
937 zoomVertical(GridPanel.ZOOMFACTOR, e.getX(), e.getY());
938 }
939 else
940 {
941 zoomVertical(1.0 / GridPanel.ZOOMFACTOR, e.getX(), e.getY());
942 }
943 }
944 else if (e.isAltDown())
945 {
946 int amount = e.getUnitsToScroll();
947 if (amount > 0)
948 {
949 zoomHorizontal(GridPanel.ZOOMFACTOR, e.getX(), e.getY());
950 }
951 else
952 {
953 zoomHorizontal(1.0 / GridPanel.ZOOMFACTOR, e.getX(), e.getY());
954 }
955 }
956 else
957 {
958 super.mouseWheelMoved(e);
959 }
960 }
961 });
962 }
963
964
965
966
967
968
969
970 final synchronized void zoomVertical(final double factor, final int mouseX, final int mouseY)
971 {
972
973 this.zoom(factor, mouseX, mouseY);
974
975
976
977
978
979
980
981
982
983 }
984
985
986
987
988
989
990
991 final synchronized void zoomHorizontal(final double factor, final int mouseX, final int mouseY)
992 {
993 this.zoom(factor, mouseX, mouseY);
994
995
996
997
998
999
1000
1001
1002
1003 }
1004
1005
1006
1007
1008
1009
1010 @SuppressWarnings("synthetic-access")
1011 protected GTU getSelectedGTU(final Point2D mousePoint)
1012 {
1013 List<GTU> targets = new ArrayList<>();
1014 Point2D point = Renderable2DInterface.Util.getWorldCoordinates(mousePoint,
1015 OTSAnimationPanel.this.animationPanel.getExtent(), OTSAnimationPanel.this.animationPanel.getSize());
1016 for (Renderable2DInterface<?> renderable : OTSAnimationPanel.this.animationPanel.getElements())
1017 {
1018 if (OTSAnimationPanel.this.animationPanel.isShowElement(renderable) && renderable.contains(point,
1019 OTSAnimationPanel.this.animationPanel.getExtent(), OTSAnimationPanel.this.animationPanel.getSize()))
1020 {
1021 if (renderable.getSource() instanceof GTU)
1022 {
1023 targets.add((GTU) renderable.getSource());
1024 }
1025 }
1026 }
1027 if (targets.size() == 1)
1028 {
1029 return targets.get(0);
1030 }
1031 return null;
1032 }
1033
1034
1035 @SuppressWarnings("synthetic-access")
1036 @Override
1037 public void paintComponent(final Graphics g)
1038 {
1039 if (OTSAnimationPanel.this.autoPan)
1040 {
1041 String id = OTSAnimationPanel.this.autoPanField.getText();
1042 if (this.lastGtu == null || !this.lastGtu.getId().equals(id) || this.lastGtu.isDestroyed())
1043 {
1044 this.lastGtu = this.network.getGTU(id);
1045 }
1046 DirectedPoint point;
1047 try
1048 {
1049 point = this.lastGtu != null ? this.lastGtu.getLocation() : null;
1050 }
1051 catch (RemoteException exception)
1052 {
1053 System.err.println("Could not pan to GTU location.");
1054 return;
1055 }
1056 if (point != null)
1057 {
1058 double w = this.extent.getWidth();
1059 double h = this.extent.getHeight();
1060 this.extent = new Rectangle2D.Double(point.getX() - w / 2, point.getY() - h / 2, w, h);
1061 }
1062 }
1063 super.paintComponent(g);
1064 }
1065
1066
1067 @Override
1068 public String toString()
1069 {
1070 return "AutoAnimationPanel [network=" + this.network + ", lastGtu=" + this.lastGtu + "]";
1071 }
1072 }
1073
1074 }