TimePanel.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. package ui.view;
  2. import java.awt.BorderLayout;
  3. import java.awt.Color;
  4. import java.awt.Dimension;
  5. import java.awt.FlowLayout;
  6. import java.awt.GridBagConstraints;
  7. import java.awt.GridBagLayout;
  8. import java.awt.Point;
  9. import java.awt.event.ActionEvent;
  10. import java.awt.event.ActionListener;
  11. import java.awt.event.KeyEvent;
  12. import java.awt.event.MouseAdapter;
  13. import java.awt.event.MouseEvent;
  14. import java.awt.event.MouseListener;
  15. import java.util.Hashtable;
  16. import java.util.concurrent.ScheduledFuture;
  17. import java.util.concurrent.ScheduledThreadPoolExecutor;
  18. import java.util.concurrent.TimeUnit;
  19. import javax.swing.AbstractAction;
  20. import javax.swing.Box;
  21. import javax.swing.ImageIcon;
  22. import javax.swing.JButton;
  23. import javax.swing.JLabel;
  24. import javax.swing.JPanel;
  25. import javax.swing.JSlider;
  26. import javax.swing.JTextField;
  27. import javax.swing.KeyStroke;
  28. import javax.swing.SwingConstants;
  29. import javax.swing.Timer;
  30. import javax.swing.event.ChangeEvent;
  31. import javax.swing.event.ChangeListener;
  32. import javax.swing.plaf.basic.BasicSliderUI;
  33. import ui.controller.Control;
  34. import util.ImageImport;
  35. /**
  36. * This Class represents a Panel where the User can start and stop the
  37. * Simulation. He Can also reset the Simulation and click through every
  38. * Iteration.
  39. *
  40. * @author Gruppe14
  41. */
  42. public class TimePanel extends JPanel implements ActionListener{
  43. private static final long serialVersionUID = 1L;
  44. private static final int MAX_ITERATIONS=100000;
  45. /*
  46. * variable for calculating the performance
  47. */
  48. //private long performanceTime;
  49. final JButton playBtn = new JButton();
  50. final JButton timeResetBtn = new JButton();
  51. final JButton timeForwardBtn = new JButton();
  52. final JButton timeBackwardBtn = new JButton();
  53. JTextField iterationsField;
  54. final JLabel iterationsLabel=new JLabel("Iterations:" , SwingConstants.CENTER);
  55. JLabel hint = new JLabel("Invalid", SwingConstants.RIGHT);
  56. private final JPanel btnAndSpeedPanel = new JPanel();
  57. private final JPanel speedPanel = new JPanel();
  58. private final JPanel timeBtnPanel = new JPanel();
  59. private final JPanel iterationsPanel=new JPanel();
  60. private final JPanel timePanel=new JPanel();
  61. private ScheduledFuture<?> futureTask;
  62. //private LabelHint iterationsLblHint;
  63. JSlider timeSlider = new JSlider() {
  64. /**
  65. *
  66. */
  67. private static final long serialVersionUID = 1L;
  68. {
  69. // Make the slider jump to mouse position on left click
  70. MouseListener[] listeners = getMouseListeners();
  71. for (MouseListener l : listeners)
  72. removeMouseListener(l); // remove UI-installed TrackListener
  73. final BasicSliderUI ui = (BasicSliderUI) getUI();
  74. BasicSliderUI.TrackListener tl = ui.new TrackListener() {
  75. // this is where we jump to absolute value of click
  76. @Override
  77. public void mouseClicked(MouseEvent e) {
  78. Point p = e.getPoint();
  79. int value = ui.valueForXPosition(p.x);
  80. setValue(value);
  81. }
  82. // disable check that will invoke scrollDueToClickInTrack
  83. @Override
  84. public boolean shouldScroll(int dir) {
  85. return false;
  86. }
  87. };
  88. addMouseListener(tl);
  89. }
  90. };
  91. //private Model model;
  92. private Control controller;
  93. private int dragResetIteration = 0;
  94. private JLabel simSpeedLabel = new JLabel("Speed:");
  95. private JSlider speedSlider = new JSlider();
  96. private Timer timer;
  97. private boolean running = false;
  98. /**
  99. * Constructor.
  100. *
  101. * @param mod
  102. * the Model
  103. * @param cont
  104. * the Controller
  105. */
  106. public TimePanel(Control cont) {
  107. super();
  108. this.controller = cont;
  109. // One Iteration
  110. timer = new Timer(0, new ActionListener() {//TODO: Merge all these damned listeners.
  111. @Override
  112. public void actionPerformed(ActionEvent ae) {
  113. timeSlider.setValue(timeSlider.getValue() + 1);
  114. controller.setCurIteration(timeSlider.getValue());
  115. timer.setDelay(cont.getModel().getTimerSpeed());
  116. if (timeSlider.getValue() >= cont.getModel().getIterations() - 1) {
  117. /*/calc and print performance
  118. performanceTime = System.nanoTime()-performanceTime;
  119. System.out.println(performanceTime/1000000000 + " Sekunden "
  120. + (performanceTime%1000000000)/1000000 + " Millisekunden "
  121. + (performanceTime%1000000)/1000 + " Mikrosekunden ");
  122. //*/
  123. running = false;
  124. playBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/play.png", 30, 30)));
  125. timer.stop();
  126. }
  127. }
  128. });
  129. // Time Slider. Panels and Buttons
  130. this.setLayout(new BorderLayout(0, 0));
  131. this.setBorder(null);
  132. // Slider
  133. timeSlider.setPaintTicks(true);
  134. timeSlider.setPaintLabels(true);
  135. timeSlider.setMajorTickSpacing((int)Math.ceil(((double)cont.getModel().getIterations())/20));
  136. timeSlider.setMinorTickSpacing((int)Math.ceil(((double)cont.getModel().getIterations())/100));
  137. timeSlider.setToolTipText("Time Slider");
  138. timeSlider.setMaximum(cont.getModel().getIterations() - 1);
  139. timeSlider.setValue(0);
  140. timeSlider.addChangeListener(changeEvent -> controller.setCurIteration(timeSlider.getValue()));
  141. timeSlider.addMouseListener(new MouseAdapter() {
  142. @Override
  143. public void mousePressed(MouseEvent e) {
  144. dragResetIteration = cont.getModel().getCurIteration();
  145. }
  146. });
  147. timeSlider.addMouseMotionListener(new MouseAdapter() {
  148. @Override
  149. public void mouseDragged(MouseEvent e) {
  150. if (dragResetIteration != cont.getModel().getCurIteration()) {
  151. if (running) {
  152. playBtn.doClick();
  153. }
  154. }
  155. }
  156. });
  157. // Panel
  158. timeBtnPanel.setBorder(null);
  159. timeBtnPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
  160. // Buttons
  161. playBtn.setToolTipText("Play");
  162. playBtn.setContentAreaFilled(false);
  163. playBtn.setBorderPainted(false);
  164. playBtn.setBorder(null);
  165. playBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/play.png",30,30)));
  166. playBtn.addActionListener(new ActionListener() {
  167. @Override
  168. public void actionPerformed(ActionEvent e) {
  169. if(cont.getModel().getCurIteration()==cont.getModel().getIterations()-1)timeSlider.setValue(timeSlider.getMinimum());
  170. running = !running;
  171. if (running) {
  172. timer.setDelay(cont.getModel().getTimerSpeed());
  173. /*
  174. * start the Performance Test
  175. * /
  176. performanceTime = System.nanoTime();
  177. timeSlider.setValue(0);
  178. timer.setDelay(0);
  179. speedSlider.setValue(10);
  180. timeSlider.setValue(0);
  181. //*/
  182. timer.start();
  183. playBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/pause.png", 30, 30)));
  184. } else {
  185. timer.stop();
  186. playBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/play.png", 30, 30)));
  187. }
  188. }
  189. });
  190. timeResetBtn.setToolTipText("Reset");
  191. timeResetBtn.setContentAreaFilled(false);
  192. timeResetBtn.setBorder(null);
  193. timeResetBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/reset.png", 30, 30)));
  194. timeResetBtn.addActionListener(new ActionListener() {
  195. public void actionPerformed(ActionEvent ae) {
  196. timeSlider.setValue(timeSlider.getMinimum());
  197. controller.setCurIteration(timeSlider.getValue());
  198. // controller.calculateStateForCurrentTimeStep();
  199. controller.resetSimulation();
  200. if (running) {
  201. playBtn.doClick();
  202. }
  203. }
  204. });
  205. timeForwardBtn.setToolTipText("Forward");
  206. timeForwardBtn.setContentAreaFilled(false);
  207. timeForwardBtn.setBorder(null);
  208. timeForwardBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/forward.png",30,30)));
  209. timeForwardBtn.addActionListener(new ActionListener() {
  210. public void actionPerformed(ActionEvent ae) {
  211. timeSlider.setValue(timeSlider.getValue() + 1);
  212. controller.setCurIteration(timeSlider.getValue());
  213. }
  214. });
  215. timeBackwardBtn.setToolTipText("Backward");
  216. timeBackwardBtn.setBorder(null);
  217. timeBackwardBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/backward.png", 30,30)));
  218. timeBackwardBtn.addActionListener(new ActionListener() {
  219. public void actionPerformed(ActionEvent ae) {
  220. timeSlider.setValue(timeSlider.getValue() - 1);
  221. controller.setCurIteration(timeSlider.getValue());
  222. }
  223. });
  224. timeBtnPanel.add(playBtn);
  225. timeBtnPanel.add(Box.createRigidArea(new Dimension(10, 0)));
  226. timeBtnPanel.add(timeResetBtn);
  227. timeBtnPanel.add(Box.createRigidArea(new Dimension(10, 0)));
  228. timeBtnPanel.add(timeForwardBtn);
  229. // Speed Panel
  230. speedPanel.add(simSpeedLabel);
  231. speedPanel.add(speedSlider);
  232. speedSlider.setPaintTicks(true);
  233. speedSlider.setPaintLabels(true);
  234. speedSlider.setMaximum(6);
  235. speedSlider.setMinimum(0);
  236. speedSlider.setValue(1);
  237. speedSlider.setPaintLabels(true);
  238. Hashtable<Integer, JLabel> table = new Hashtable<Integer, JLabel>();
  239. table.put (0, new JLabel("1x"));
  240. table.put (1, new JLabel("2x"));
  241. table.put (2, new JLabel("4x"));
  242. table.put (3, new JLabel("8x"));
  243. table.put (4, new JLabel("16x"));
  244. table.put (5, new JLabel("32x"));
  245. table.put (6, new JLabel("64x"));
  246. speedSlider.setLabelTable(table);
  247. speedSlider.addChangeListener(new ChangeListener() {
  248. @Override
  249. public void stateChanged(ChangeEvent e) {
  250. /**
  251. * Shifting Powers of two:
  252. * e.g. 1<<0 -> 1 step per Second
  253. * 1<<3 -> 8 steps per Second
  254. * and so on,
  255. */
  256. int calculationsPerSecond = 1 << speedSlider.getValue();
  257. controller.setTimerSpeed(1024 >> speedSlider.getValue());
  258. speedSlider.setToolTipText("Speed: " + calculationsPerSecond + " Calculations per Second.");
  259. }
  260. });
  261. speedSlider.setToolTipText("Change the Number of Calculations per Secons");
  262. // Buttons and Speed Panel
  263. btnAndSpeedPanel.setLayout(new BorderLayout(0, 0));
  264. btnAndSpeedPanel.setBorder(null);
  265. btnAndSpeedPanel.add(timeBtnPanel, BorderLayout.NORTH);
  266. btnAndSpeedPanel.add(speedPanel, BorderLayout.CENTER);
  267. iterationsPanel.setLayout(new GridBagLayout());
  268. GridBagConstraints c = new GridBagConstraints();
  269. c.anchor = GridBagConstraints.CENTER;
  270. c.fill = GridBagConstraints.HORIZONTAL;
  271. c.gridx = 0;
  272. c.gridy = 0;
  273. iterationsPanel.add(iterationsLabel, c);
  274. //iterationsLblHint=new LabelHint(iterationsLabel);
  275. hint.setForeground(Color.red);
  276. hint.setText(" ");
  277. iterationsField=new JTextField(6);//Considering hundreds of thousands in an extreme case
  278. iterationsField.setText(""+cont.getModel().getIterations());
  279. iterationsField.setToolTipText("0-" + MAX_ITERATIONS );
  280. iterationsField.addActionListener(this);
  281. ScheduledThreadPoolExecutor s = new ScheduledThreadPoolExecutor(1);
  282. iterationsField.addCaretListener((e)->
  283. {
  284. try{
  285. iterationsField.setBackground(Color.WHITE);//red stings
  286. if(futureTask != null){
  287. futureTask.cancel(true);
  288. }
  289. futureTask = s.schedule((Runnable)() -> updateIterationsInput(), 1, TimeUnit.SECONDS);
  290. hint.setText(" ");
  291. }catch(NumberFormatException n){
  292. iterationsField.setBackground(GUI.PALE_RED);//red stings
  293. hint.setText("Invalid");
  294. }
  295. }
  296. );
  297. iterationsField.addFocusListener((interfaces.FocusListener)(e) ->{
  298. //FocusLost is not defined in interface have to be defined here
  299. updateIterationsInput();
  300. });
  301. c.gridy = 1;
  302. iterationsPanel.add(iterationsField, c);
  303. c.gridy = 2;
  304. iterationsPanel.add(hint, c);
  305. //iterationsPanel.add(new JLabel(), BorderLayout.SOUTH);
  306. timePanel.setLayout(new BorderLayout());;
  307. timePanel.add(iterationsPanel, BorderLayout.WEST);
  308. timePanel.add(timeSlider, BorderLayout.CENTER);
  309. this.add(btnAndSpeedPanel, BorderLayout.WEST);
  310. add(timePanel);
  311. //Disable Keys
  312. timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "UP_ARROW");
  313. timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "DOWN_ARROW");
  314. timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0, false), "PAGE_DOWN");
  315. timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0, false), "PAGE_UP");
  316. timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0, false), "END");
  317. timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0, false), "HOME");
  318. // Left arrow Key
  319. timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "LEFT_ARROW");
  320. timeSlider.getActionMap().put("LEFT_ARROW", new AbstractAction() {
  321. private static final long serialVersionUID = 1L;
  322. @Override
  323. public void actionPerformed(ActionEvent e) {
  324. timeSlider.setValue(timeSlider.getValue() - 1);
  325. controller.resetSimulation();
  326. }
  327. });
  328. //Right arrow Key
  329. timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "Right_ARROW");
  330. timeSlider.getActionMap().put("Right_ARROW", new AbstractAction() {
  331. private static final long serialVersionUID = 1L;
  332. @Override
  333. public void actionPerformed(ActionEvent e) {
  334. timeSlider.setValue(timeSlider.getValue() + 1);
  335. }
  336. });
  337. }
  338. /**
  339. * Returns the TimeSlider.
  340. *
  341. * @return the TimeSlider
  342. */
  343. public JSlider getTimeSlider() {
  344. return timeSlider;
  345. }
  346. @Override
  347. public void actionPerformed(ActionEvent arg0) {
  348. updateIterationsInput();
  349. }
  350. /**
  351. * Update the Text field and apply valid changes to update Iterations from to model.
  352. * <p>
  353. * Executed by user input.
  354. */
  355. private void updateIterationsInput() {
  356. try{
  357. int iterations=Integer.parseInt(iterationsField.getText());
  358. //iterationsLblHint.reset();
  359. boolean resetField=true;
  360. if(iterations<1)iterations=1;
  361. else if(iterations>MAX_ITERATIONS)iterations=MAX_ITERATIONS;
  362. else resetField=false;
  363. if(resetField)iterationsField.setText(""+iterations);
  364. controller.getModel().setIterations(Integer.parseInt(iterationsField.getText()));
  365. timeSlider.setMaximum(controller.getModel().getIterations()-1);
  366. timeSlider.setLabelTable(null);//Otherwise the ticks won't update
  367. timeSlider.setMajorTickSpacing((int)Math.ceil(((double)iterations)/20));
  368. timeSlider.setMinorTickSpacing((int)Math.ceil(((double)iterations)/100));//Even though the final mark can't actually be reached.
  369. }catch(NumberFormatException e){}
  370. }
  371. }