package de.uni_passau.fim.infosun.prophet.experimentViewer; import java.awt.event.ActionEvent; import java.util.concurrent.TimeUnit; import javax.swing.JLabel; import javax.swing.Timer; import de.uni_passau.fim.infosun.prophet.util.qTree.QTreeNode; /** * A <code>JLabel</code> displaying 'Caption MM:SS', the elapsed time since the <code>StopwatchLabel</code> was started. * The <code>StopwatchLabel</code> will save that time in seconds in the <code>QTreeNode</code> given in the * constructor when it is paused or stopped. */ public class StopwatchLabel extends JLabel { private static final String noCaptionFormat = "%02d:%02d"; private static final String captionFormat = "%s " + noCaptionFormat; private final QTreeNode node; private final String caption; private final Timer timer; // millisecond timestamps private long startTime; private long pauseTime; private long lastUpdateTime; /** * Constructs a new <code>StopwatchLabel</code> for the given <code>QTreeNode</code>. * The given <code>caption</code> will be prepended to the time the * <code>StopwatchLabel</code> displays. * * @param node the <code>QTreeNode</code> this <code>StopwatchLabel</code> saves its time in or <code>null</code> if * the time should not be saved * @param caption the caption to be prepended to the displayed time or <code>null</code> for no caption */ public StopwatchLabel(QTreeNode node, String caption) { this.node = node; this.caption = caption; this.timer = new Timer(200, this::update); this.timer.setInitialDelay(0); this.startTime = 0; updateText(); } /** * Called every time the <code>timer</code> fires. * * @param event the <code>ActionEvent</code> produced by the <code>timer</code> */ private void update(ActionEvent event) { lastUpdateTime = System.currentTimeMillis(); updateText(); } /** * Updates the text of this <code>JLabel</code> to show the current elapsed time. */ private void updateText() { long elapsedTime; if (startTime == 0) { elapsedTime = 0; } else { elapsedTime = System.currentTimeMillis() - startTime; } long minutes = TimeUnit.MILLISECONDS.toMinutes(elapsedTime); long remainingSeconds = TimeUnit.MILLISECONDS.toSeconds(elapsedTime - TimeUnit.MINUTES.toMillis(minutes)); Object[] formatArgs; String formatString; if (caption != null) { formatString = captionFormat; formatArgs = new Object[] {caption, minutes, remainingSeconds}; } else { formatString = noCaptionFormat; formatArgs = new Object[] {minutes, remainingSeconds}; } setText(String.format(formatString, formatArgs)); } /** * Saves the current elapsed time to the <code>node</code> if there is one. * * @param now the current elapsed time in milliseconds */ private void saveTime(long now) { if (node != null) { node.setAnswerTime(TimeUnit.MILLISECONDS.toSeconds(now - startTime)); } } /** * Starts (or unpauses) the <code>StopwatchLabel</code>. */ public void start() { if (timer.isRunning()) { return; } long now = System.currentTimeMillis(); if (startTime == 0) { startTime = now; } else { startTime += now - pauseTime; } timer.start(); } /** * Stops the <code>StopwatchLabel</code>. */ public void stop() { if (!timer.isRunning()) { return; } saveTime(System.currentTimeMillis()); timer.stop(); timer.setInitialDelay(0); startTime = 0; pauseTime = 0; lastUpdateTime = 0; } /** * Pauses the <code>StopwatchLabel</code>. */ public void pause() { if (!timer.isRunning()) { return; } long now = System.currentTimeMillis(); saveTime(now); timer.stop(); timer.setInitialDelay((int) (now - lastUpdateTime)); pauseTime = now; } }