All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.darwinsys.swingui.BreakTimer Maven / Gradle / Ivy

There is a newer version: 1.8.0
Show newest version
package com.darwinsys.swingui;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.time.*;
import java.time.temporal.*;
import java.util.ResourceBundle;
import java.util.concurrent.*;

/** This class implements a short-term timer for timing e.g.,
 * breaks during a class, lunch breaks, etc.
 * Constructor takes a RootPaneContainer argument
 * to allow use with caller's choice of JFrame or JInternalFrame
 * (other RootPaneContainers are not supported).
 * XXX Set ending time instead of time limit
 * XXX Option to close iframe on done
 */
public class BreakTimer {

	/** Run the BreakTimer as a main program.
	 * @param args The command line arguments ("jf" for JFrame, "ji" for JInternalFrame)
	 */
	public static void main(String[] args) {
		JFrame jf = new JFrame("Break Timer");
		jf.add(BorderLayout.CENTER, new JLabel("Demo"));
		jf.setDefaultCloseOperation((JFrame.EXIT_ON_CLOSE));
		if (args.length == 0 || args[0].toLowerCase().startsWith("jf")) {
			// Build as a JFrame
			new BreakTimer(jf);
			UtilGUI.packAndCenter(jf);
		} else if (args[0].toLowerCase().startsWith("ji")) {
			// Build as a JInternalFrame
			jf.setSize(800, 600);
			JInternalFrame jiffy = new JInternalFrame("Timer", false, true);
			new BreakTimer(jiffy);
			jf.setGlassPane(jiffy);
			jiffy.setVisible(true);
		} else {
			throw new IllegalArgumentException("RootPaneContainer must be JFrame or JInternalFrame");
		}
		jf.setVisible(true);
	}

	private final static String NO_TIME = "00:00";
	private final static String DEFAULT_MESSAGE = "Break ends in...";
	private final static Integer[] TIMES = new Integer[]{5,10,15,30,60};
	private final Duration minute = Duration.of(1, ChronoUnit.MINUTES);

	private RootPaneContainer jf;
	private ExecutorService tp = Executors.newSingleThreadExecutor();
	private Duration duration;
	private Future handle;
	private JLabel timerLabel;
	private JTextField topText;
	private JComboBox choice;
	/** The runnable to run when the timer expires. May be null. */
	private Runnable doneAction;
	private ResourceBundle resourceBundle;

	/** Construct a BreakTimer
	 * @param jf The JFrame or JInternalFrame
	 */
	public BreakTimer(RootPaneContainer jf) {
		this.jf = jf;
		var cp = jf.getContentPane();

		// XXX add to tray

		cp.setLayout(new BorderLayout());

		JPanel topPanel = new JPanel();

		resourceBundle = ResourceBundle.getBundle("BreakTimer");

		topText = new JTextField(DEFAULT_MESSAGE);
		topText.setFont(new Font("Helvetica", Font.PLAIN, 48));
		topPanel.add(topText);

		JButton xButton = new JButton("X");
		xButton.addActionListener(ActionEvent ->  {
			topText.setText("");
		});
		topPanel.add(xButton);

		JButton rsButton = new JButton("Reset");
		rsButton.addActionListener(ActionEvent ->  {
			topText.setText(DEFAULT_MESSAGE);
		});
		topPanel.add(rsButton);
		cp.add(BorderLayout.NORTH, topPanel);

		JPanel botPanel = new JPanel();
		choice = new JComboBox<>(TIMES);
		choice.setEditable(true);

		JPanel bigPanel = new JPanel();
		timerLabel = new JLabel();
		timerLabel.setFont(new Font("Helvetica", Font.PLAIN, 256));
		timerLabel.setText(NO_TIME);
		bigPanel.add(timerLabel);
		cp.add(BorderLayout.CENTER, bigPanel);
		botPanel.add(choice);

		JButton start = new JButton("Start");
		botPanel.add(start);
		start.addActionListener(startAction);
		JButton plus = new JButton("+1");
		botPanel.add(plus);
		plus.addActionListener(ActionEvent ->  {
			duration = duration == null ? minute : duration.plusMinutes(1);
		});
		JButton minus = new JButton("-1");
		botPanel.add(minus);
		minus.addActionListener(ActionEvent ->  {
			duration = duration.minusMinutes(1);
		});
		JButton stop = new JButton("Stop");
		botPanel.add(stop);
		stop.addActionListener(ActionEvent ->  {
			handle.cancel(true);
		});

		JButton help = new JButton("Help");
		botPanel.add(help);
		help.addActionListener(e -> doHelp());

		cp.add(BorderLayout.SOUTH, botPanel);

		doneAction = DEFAULT_ACTION;
	}

	/**
	 * The ActionListener to start the timer.
	 */
	ActionListener startAction = evt ->  {
		handle = tp.submit( () -> {
			// If toString()ed, would look like PT10M
			duration =
				Duration.of((Integer)choice.getSelectedItem(), ChronoUnit.MINUTES);
			if (Thread.currentThread().isInterrupted()) {
				timerLabel.setText(NO_TIME);
				return;
			}
			while (duration.toSeconds() >= 0) {
				if (duration.toHoursPart() > 0) {
					timerLabel.setText(
						String.format("%2d:%02d:%02d",
						duration.toHoursPart(),
						duration.toMinutesPart(),
						duration.toSecondsPart()));
				} else {
					timerLabel.setText(
						String.format("%2d:%02d",
						duration.toMinutesPart(),
						duration.toSecondsPart()));
				}
				try {
					Thread.sleep(999);
				} catch (InterruptedException cancelMessage) {
					timerLabel.setText(NO_TIME);
					return;
				}
				duration = duration.minusSeconds(1);
			}
			if (doneAction != null) {
				doneAction.run();
			}
		});
	};

	private final static String[] labels = { "OK", "Restart" };

	/** A useful expiry action */
	final private Runnable DEFAULT_ACTION = () -> {
		JFrame theFrame = null;
		if (jf instanceof JFrame)
			theFrame = (JFrame)jf;
		int choice = JOptionPane.showOptionDialog(theFrame,
			"Time's up: " + topText.getText(),	// message
			"Time's up",						// title (after message - why?)
			JOptionPane.YES_NO_OPTION,			// Only two buttons, labels above
			JOptionPane.QUESTION_MESSAGE,
			null,
			labels,
			labels[0]);
		if (choice == 1) {
			startAction.actionPerformed(null);
		}
	};

	/** Set the runnable to run when the timer expires. 
	 * @param runnable The Runnable; may be null. 
	 */
	public void setExpiryAction(Runnable runnable) {
		doneAction = runnable;
	}

	/**
	 * Display the Help text for the BreakTimer
	 */
	public void doHelp() {
		JFrame theFrame = null;
		if (jf instanceof JFrame)
			theFrame = (JFrame)jf;
		String text = resourceBundle.getString("breaktimer.help.text");
		JOptionPane.showMessageDialog(theFrame, text);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy