package ui.view.main; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.Hashtable; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.swing.AbstractAction; import javax.swing.Box; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.Timer; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.basic.BasicSliderUI; import ui.controller.Control; import utility.ImageImport; /** * This Class represents a Panel where the User can start and stop the * Simulation. He Can also reset the Simulation and click through every * Iteration. * * @author Gruppe14 */ public class TimePanel extends JPanel implements ActionListener{ private static final Color PALE_RED = new Color(255, 192, 192); private static final int MAX_ITERATIONS=100000; /* * variable for calculating the performance */ //private long performanceTime; final JButton playBtn = new JButton(); final JButton timeResetBtn = new JButton(); final JButton timeForwardBtn = new JButton(); final JButton timeBackwardBtn = new JButton(); JTextField iterationsField; final JLabel iterationsLabel=new JLabel("Iterations:" , SwingConstants.CENTER); JLabel hint = new JLabel("Invalid", SwingConstants.RIGHT); private final JPanel btnAndSpeedPanel = new JPanel(); private final JPanel speedPanel = new JPanel(); private final JPanel timeBtnPanel = new JPanel(); private final JPanel iterationsPanel=new JPanel(); private final JPanel timePanel=new JPanel(); private ScheduledFuture futureTask; //private LabelHint iterationsLblHint; JSlider timeSlider = new JSlider() { /** * */ private static final long serialVersionUID = 1L; { // Make the slider jump to mouse position on left click MouseListener[] listeners = getMouseListeners(); for (MouseListener l : listeners) removeMouseListener(l); // remove UI-installed TrackListener final BasicSliderUI ui = (BasicSliderUI) getUI(); BasicSliderUI.TrackListener tl = ui.new TrackListener() { // this is where we jump to absolute value of click @Override public void mouseClicked(MouseEvent e) { Point p = e.getPoint(); int value = ui.valueForXPosition(p.x); setValue(value); } // disable check that will invoke scrollDueToClickInTrack @Override public boolean shouldScroll(int dir) { return false; } }; addMouseListener(tl); } }; //private Model model; private Control controller; private int dragResetIteration = 0; private JLabel simSpeedLabel = new JLabel("Speed:"); private JSlider speedSlider = new JSlider(); private Timer timer; private boolean running = false; /** * Constructor. * * @param mod * the Model * @param cont * the Controller */ public TimePanel(Control cont) { super(); this.controller = cont; // One Iteration timer = new Timer(0, new ActionListener() {//TODO: Merge all these damned listeners. @Override public void actionPerformed(ActionEvent ae) { timeSlider.setValue(timeSlider.getValue() + 1); controller.setCurIteration(timeSlider.getValue()); timer.setDelay(cont.getModel().getTimerSpeed()); if (timeSlider.getValue() >= cont.getModel().getIterations() - 1) { /*/calc and print performance performanceTime = System.nanoTime()-performanceTime; System.out.println(performanceTime/1000000000 + " Sekunden " + (performanceTime%1000000000)/1000000 + " Millisekunden " + (performanceTime%1000000)/1000 + " Mikrosekunden "); //*/ running = false; playBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/play.png", 30, 30))); timer.stop(); } } }); // Time Slider. Panels and Buttons this.setLayout(new BorderLayout(0, 0)); this.setBorder(null); // Slider timeSlider.setPaintTicks(true); timeSlider.setPaintLabels(true); timeSlider.setMajorTickSpacing((int)Math.ceil(((double)cont.getModel().getIterations())/20)); timeSlider.setMinorTickSpacing((int)Math.ceil(((double)cont.getModel().getIterations())/100)); timeSlider.setToolTipText("Time Slider"); timeSlider.setMaximum(cont.getModel().getIterations() - 1); timeSlider.setValue(0); timeSlider.addChangeListener(changeEvent -> controller.setCurIteration(timeSlider.getValue())); timeSlider.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { dragResetIteration = cont.getModel().getCurIteration(); } }); timeSlider.addMouseMotionListener(new MouseAdapter() { @Override public void mouseDragged(MouseEvent e) { if (dragResetIteration != cont.getModel().getCurIteration()) { if (running) { playBtn.doClick(); } } } }); // Panel timeBtnPanel.setBorder(null); timeBtnPanel.setLayout(new FlowLayout(FlowLayout.CENTER)); // Buttons playBtn.setToolTipText("Play"); playBtn.setContentAreaFilled(false); playBtn.setBorderPainted(false); playBtn.setBorder(null); playBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/play.png",30,30))); playBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if(cont.getModel().getCurIteration()==cont.getModel().getIterations()-1)timeSlider.setValue(timeSlider.getMinimum()); running = !running; if (running) { timer.setDelay(cont.getModel().getTimerSpeed()); /* * start the Performance Test * / performanceTime = System.nanoTime(); timeSlider.setValue(0); timer.setDelay(0); speedSlider.setValue(10); timeSlider.setValue(0); //*/ timer.start(); playBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/pause.png", 30, 30))); } else { timer.stop(); playBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/play.png", 30, 30))); } } }); timeResetBtn.setToolTipText("Reset"); timeResetBtn.setContentAreaFilled(false); timeResetBtn.setBorder(null); timeResetBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/reset.png", 30, 30))); timeResetBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { timeSlider.setValue(timeSlider.getMinimum()); controller.setCurIteration(timeSlider.getValue()); // controller.calculateStateForCurrentTimeStep(); controller.resetSimulation(); if (running) { playBtn.doClick(); } } }); timeForwardBtn.setToolTipText("Forward"); timeForwardBtn.setContentAreaFilled(false); timeForwardBtn.setBorder(null); timeForwardBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/forward.png",30,30))); timeForwardBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { timeSlider.setValue(timeSlider.getValue() + 1); controller.setCurIteration(timeSlider.getValue()); } }); timeBackwardBtn.setToolTipText("Backward"); timeBackwardBtn.setBorder(null); timeBackwardBtn.setIcon(new ImageIcon(ImageImport.loadImage("/Button_Images/backward.png", 30,30))); timeBackwardBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { timeSlider.setValue(timeSlider.getValue() - 1); controller.setCurIteration(timeSlider.getValue()); } }); timeBtnPanel.add(playBtn); timeBtnPanel.add(Box.createRigidArea(new Dimension(10, 0))); timeBtnPanel.add(timeResetBtn); timeBtnPanel.add(Box.createRigidArea(new Dimension(10, 0))); timeBtnPanel.add(timeForwardBtn); // Speed Panel speedPanel.add(simSpeedLabel); speedPanel.add(speedSlider); speedSlider.setPaintTicks(true); speedSlider.setPaintLabels(true); speedSlider.setMaximum(6); speedSlider.setMinimum(0); speedSlider.setValue(1); speedSlider.setPaintLabels(true); Hashtable table = new Hashtable(); table.put (0, new JLabel("1x")); table.put (1, new JLabel("2x")); table.put (2, new JLabel("4x")); table.put (3, new JLabel("8x")); table.put (4, new JLabel("16x")); table.put (5, new JLabel("32x")); table.put (6, new JLabel("64x")); speedSlider.setLabelTable(table); speedSlider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { /** * Shifting Powers of two: * e.g. 1<<0 -> 1 step per Second * 1<<3 -> 8 steps per Second * and so on, */ int calculationsPerSecond = 1 << speedSlider.getValue(); controller.setTimerSpeed(1024 >> speedSlider.getValue()); speedSlider.setToolTipText("Speed: " + calculationsPerSecond + " Calculations per Second."); } }); speedSlider.setToolTipText("Change the Number of Calculations per Secons"); // Buttons and Speed Panel btnAndSpeedPanel.setLayout(new BorderLayout(0, 0)); btnAndSpeedPanel.setBorder(null); btnAndSpeedPanel.add(timeBtnPanel, BorderLayout.NORTH); btnAndSpeedPanel.add(speedPanel, BorderLayout.CENTER); iterationsPanel.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.anchor = GridBagConstraints.CENTER; c.fill = GridBagConstraints.HORIZONTAL; c.gridx = 0; c.gridy = 0; iterationsPanel.add(iterationsLabel, c); //iterationsLblHint=new LabelHint(iterationsLabel); hint.setForeground(Color.red); hint.setText(" "); iterationsField=new JTextField(6);//Considering hundreds of thousands in an extreme case iterationsField.setText(""+cont.getModel().getIterations()); iterationsField.setToolTipText("0-" + MAX_ITERATIONS ); iterationsField.addActionListener(this); ScheduledThreadPoolExecutor s = new ScheduledThreadPoolExecutor(1); iterationsField.addCaretListener((e)-> { try{ iterationsField.setBackground(Color.WHITE);//red stings if(futureTask != null){ futureTask.cancel(true); } futureTask = s.schedule((Runnable)() -> updateIterationsInput(), 1, TimeUnit.SECONDS); hint.setText(" "); }catch(NumberFormatException n){ iterationsField.setBackground(PALE_RED);//red stings hint.setText("Invalid"); } } ); iterationsField.addFocusListener((interfaces.FocusListener)(e) ->{ //FocusLost is not defined in interface have to be defined here updateIterationsInput(); }); c.gridy = 1; iterationsPanel.add(iterationsField, c); c.gridy = 2; iterationsPanel.add(hint, c); //iterationsPanel.add(new JLabel(), BorderLayout.SOUTH); timePanel.setLayout(new BorderLayout());; timePanel.add(iterationsPanel, BorderLayout.WEST); timePanel.add(timeSlider, BorderLayout.CENTER); this.add(btnAndSpeedPanel, BorderLayout.WEST); add(timePanel); //Disable Keys timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "UP_ARROW"); timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "DOWN_ARROW"); timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0, false), "PAGE_DOWN"); timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0, false), "PAGE_UP"); timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_END, 0, false), "END"); timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0, false), "HOME"); // Left arrow Key timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "LEFT_ARROW"); timeSlider.getActionMap().put("LEFT_ARROW", new AbstractAction() { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { timeSlider.setValue(timeSlider.getValue() - 1); controller.resetSimulation(); } }); //Right arrow Key timeSlider.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "Right_ARROW"); timeSlider.getActionMap().put("Right_ARROW", new AbstractAction() { private static final long serialVersionUID = 1L; @Override public void actionPerformed(ActionEvent e) { timeSlider.setValue(timeSlider.getValue() + 1); } }); } /** * Returns the TimeSlider. * * @return the TimeSlider */ public JSlider getTimeSlider() { return timeSlider; } @Override public void actionPerformed(ActionEvent arg0) { updateIterationsInput(); } /** * Update the Text field and apply valid changes to update Iterations from to model. *

* Executed by user input. */ private void updateIterationsInput() { try{ int iterations=Integer.parseInt(iterationsField.getText()); //iterationsLblHint.reset(); boolean resetField=true; if(iterations<1)iterations=1; else if(iterations>MAX_ITERATIONS)iterations=MAX_ITERATIONS; else resetField=false; if(resetField)iterationsField.setText(""+iterations); controller.getModel().setIterations(Integer.parseInt(iterationsField.getText())); timeSlider.setMaximum(controller.getModel().getIterations()-1); timeSlider.setLabelTable(null);//Otherwise the ticks won't update timeSlider.setMajorTickSpacing((int)Math.ceil(((double)iterations)/20)); timeSlider.setMinorTickSpacing((int)Math.ceil(((double)iterations)/100));//Even though the final mark can't actually be reached. }catch(NumberFormatException e){} } }