/*
* KrutTimer.java
*
* Created on 17. maj 2007, 14:57
*/
package krut.KRUT_GUI;
/**
*
* @author Jonas
*/
/** A class used as a timer to start the Krut program. The KrutTimer is a
* JPanel that when displayed sits below the main window of the Krut program.
* It can be used to program Krut to start and stop recording at given
* offset times, or at given system calendar clock times.
*/
public class KrutTimer extends javax.swing.JPanel {
/** This should contain the JFrame in which the KrutTimer is drawn.
* The JButton1ActionPerformed method will call that object and tell
* it to re-pack. This parameter is set in the setMainGUI method or the
* constructor.
*/
private javax.swing.JFrame myContainer;
/** The output window of this KrutTimer. Should be set through
* the setOutput method.
*/
private krut.KRUT_GUI.OutputText myOutput;
/** Timer used to count down to recording start/stop. */
public javax.swing.Timer timer;
/** When the timer is activated, startRecSeconds
* contains the programmed starting time for
* recording, counted in seconds from last
* midnight. startRecSeconds is set in the
* startTimer method. In the tickTimer method,
* the current calendar time is compared to
* startRecSeconds to see if recording should
* start.
*/
private int startRecSeconds;
/** When the timer is activated, stopRecSeconds
* contains the programmed stopping time for
* recording, counted in seconds from last
* midnight. stopRecSeconds is set in the
* startTimer method. In the tickTimer method,
* the current calendar time is compared to
* stopRecSeconds to see if recording should
* stop.
*/
private int stopRecSeconds;
/** When the user changes the type of time to use in
* the KrutTimer from actual time to relative time,
* the old start-time fields are switched
* with those in recHMemory, recMMemory, and
* recSMemory. The switch is done in the
* restoreTime method.
*/
private int recHMemory = 0;
/** When the user changes the type of time to use in
* the KrutTimer from actual time to relative time,
* the old start-time fields are switched
* with those in recHMemory, recMMemory, and
* recSMemory. The switch is done in the
* restoreTime method.
*/
private int recMMemory = 0;
/** When the user changes the type of time to use in
* the KrutTimer from actual time to relative time,
* the old start-time fields are switched
* with those in recHMemory, recMMemory, and
* recSMemory. The switch is done in the
* restoreTime method.
*/
private int recSMemory = 0;
/** When the user changes the type of time to use in
* the KrutTimer from actual time to relative time,
* the old stop-time fields are switched
* with those in stopHMemory, stopMMemory, and
* stopSMemory. The switch is done in the
* restoreTime method.
*/
private int stopHMemory = 0;
/** When the user changes the type of time to use in
* the KrutTimer from actual time to relative time,
* the old stop-time fields are switched
* with those in stopHMemory, stopMMemory, and
* stopSMemory. The switch is done in the
* restoreTime method.
*/
private int stopMMemory = 0;
/** When the user changes the type of time to use in
* the KrutTimer from actual time to relative time,
* the old stop-time fields are switched
* with those in stopHMemory, stopMMemory, and
* stopSMemory. The switch is done in the
* restoreTime method.
*/
private int stopSMemory = 0;
/** The countdown mode for the KrutTimer. */
public final static int COUNTDOWN = 0;
/** The countup mode for the KrutTimer. */
public final static int COUNTUP = 1;
/** The not active state for the KrutTimer. */
public final static int NOT_ACTIVE = 2;
/** The waiting state for the KrutTimer. */
public final static int WAITING = 3;
/** The recording state for the KrutTimer. */
public final static int RECORDING = 4;
/** The mode of the KrutTimer. This can be either COUNTDOWN or COUNTUP.
* In the countdown mode, the KrutTimer counts down from a given time,
* and in the countup mode, the KrutTimer counts up towards a given
* calendar time.
* The mode can be read through getMode().
*/
private int mode = COUNTDOWN;
/** The state of the KrutTimer. This can be NOT_ACTIVE, WAITING, or
* RECORDING. When the KrutTimer is not active, it waits for the
* user to activate it through the "Activate Timer" JToggleButton.
* When the KrutTimer is waiting, it waits for the time to reach
* the given start time for recording. When the KrutTimer is
* recording, it waits for the KrutTimer to reach the given stop
* timer for recording, if there is one.
* The state can be read through getState().
*/
private int state = NOT_ACTIVE;
/** This is a class we use to make sure the numbers displayed in
* the JFormattedTextFields for the spinners are always two digit numbers,
* even if their values are below 10. The values of the text fields
* are never changed, just the way they are displayed.
*
* @return A String representation of the value in the JFormattedTextField.
*/
private class DoubleDigitFormatter
extends javax.swing.JFormattedTextField.AbstractFormatter {
/** Give a String representation of the value of
* the JFormattedTextField to which this DoubleDigitFormatter is
* attached.
*
* @param value The Object which represents the value of the
* JFormattedTextField. This will always be an integer,
* since we only use SpinnerNumberModels for the
* spinners.
*
* @return A String representation of the value. If the value is
* not a valid integer, "00" is returned.
*/
public String valueToString(Object value) {
String returnString = "00";
try {
int val = (Integer) value;
/** First we must check that we have a valid number. */
if (val < 0) {}
/** Add a zero if it is a one-digit number. */
else if (val < 10) {
returnString = "0" + val;
} else {
returnString = "" + val;
}
} catch (Exception e) {
System.out.println(e);
}
return returnString;
}
/** Give the integer value of the String read from the JFormattedTextField
* to which this DoubleDigitFormatter is attached.
*
* @param text The String read from the JFormattedTextField.
*
* @return An Integer representing the value of the input parameter
* text, or 0 if there is no such Integer representation.
*/
public Integer stringToValue(String text) {
Integer returnInt = 0;
try {
returnInt = Integer.parseInt(text);
} catch (Exception e) {
System.out.println("Error in KrutTimer.DoubleDigitFormatter.stringToValue: ");
System.out.println(e);
/** If the user made an invalid edit, this will change it to 0. */
getFormattedTextField().setValue(0);
}
return returnInt;
}
}
/** This class is used to deliver our DoubleDigitFormatter, whenever
* someone asks the JFormattedTextFields of the spinners for their
* AbstractFormatter.
*/
private class DoubleDigitFactory extends javax.swing.JFormattedTextField.AbstractFormatterFactory {
/** Deliver the DoubleDigitFormatter
*
* @param tf A JFormattedTextField to which this DoubleDigitFactory is
* attached.
*
* @return A new DoubleDigitFormatter object.
*/
public DoubleDigitFormatter getFormatter(javax.swing.JFormattedTextField tf) {
return new DoubleDigitFormatter();
}
}
/** A class used to limit the highest number that can be written
* in the JFormattedTextField beloning to a JSpinner to 59. If
* a higher number is entered, the spinner will start over from
* 0, and its parent will add 1 to it's value. The parent must
* be set using the setParent method before using an object of
* this class.
*/
private class TimeModel extends javax.swing.SpinnerNumberModel {
/** The JSpinner which is parent to the JSpinner that this
* TimeModel belongs to. Eg. if this is the TimeModel for the
* recS (recording seconds) spinner, the parent would be the
* recM (recording minutes) spinner.
*/
private javax.swing.JSpinner myParentSpinner;
/** Constructor for TimeModel. See SpinnerNumberModel for details.
*
* @param value The current (non null) value of the component.
* @param min The first number in the sequence, or null.
* @param max The last number in the sequence, or null.
* @param stepSize The difference between elements of the sequence.
*/
TimeModel(Number value, Comparable min, Comparable max, Number stepSize) {
super(value, min, max, stepSize);
}
/** A TimeModel needs to know the JSpinner which is parent to the
* JSpinner the TimeModel belongs to. Eg. if this is the TimeModel for the
* recS (recording seconds) spinner, the parent would be the
* recM (recording minutes) spinner.
*
* This is the method used to set this parent.
*
* @param parent The parent JSpinner to the JSpinner that this
* TimeModel belongs to.
*/
public void setParent(javax.swing.JSpinner parent) {
myParentSpinner = parent;
}
/** Set the value of the JSpinner that this TimeModel belongs to.
* Since this is a SpinnerNumberModel, the value should be an
* integer number.
*
* @param value The integer number that should be used as
* the value of the JSpinner that this TimeModel
* belongs to.
*/
public void setValue(Object value) {
/** Used to store the value of the input parameter, converted
* to an integer.
*/
int val = 0;
/** Used to keep track of how much we should increase the
* parent when we are done.
*/
int parentIncrease = 0;
/** See description of bug at the end of this method.
*/
boolean unclearBugFix = false;
/** Convert value to an int. */
try {
val = (Integer) value;
} catch (Exception e) {
System.out.println("Error in KrutTimer.TimeModel.setValue");
System.out.println(e);
}
/** Make sure that the value is below 60. Increase the parent
* JSpinner if the value was 60 or above.
*/
while (60 <= val) {
val -= 60;
parentIncrease++;
unclearBugFix = true;
}
/** If we have decreased the value below zero, we should
* decrease parent by one, and start over at 59. This part
* is horribly ugly, and should be replaced with different
* SpinnerNumberModels for hours, minutes, and seconds.
*/
if (val == -1) {
/** If the parent spinner is at its lowest value,
* we should just stay at 0.
*/
if (myParentSpinner.getPreviousValue() == null) {
val = 0;
} else {
/** Get an integer representation of the parents
* previous value.
*/
int tempVal = (Integer) myParentSpinner.getPreviousValue();
if (tempVal == -1) {
/** The only scenario that can go wrong, is if we are
* in the field for seconds and the time is 00:00:00,
* and we try to decrease the seconds. This is a bugfix
* for that case. We try to change the minutes down,
* and see what happend. If they change to 59, then we change
* the seconds as well. If the minutes stay at 00, then
* the seconds stay as well.
*/
myParentSpinner.setValue(myParentSpinner.getPreviousValue());
/** Get an integer representation of the parents value.
*/
int testMin = (Integer) myParentSpinner.getValue();
if (testMin == 0) {
val = 0;
} else {
val = 59;
}
} else {
/** If we get this far, the parents previous value is
* not -1, and not null, which means that the parent has
* a value of over 0, which means we should decrease it,
* and change the current field to 59.
*/
val = 59;
myParentSpinner.setValue(myParentSpinner.getPreviousValue());
}
}
}
/** Set the value of this field. */
super.setValue(val);
/** Increase the parent if necessary. */
if (0 < parentIncrease) {
int parentVal = (Integer) myParentSpinner.getValue();
myParentSpinner.setValue(parentVal + parentIncrease);
}
/** It seems that some values when inputted in
* the text fields by the user, does not change
* the way they should after the proper HH:MM:SS
* value has been calculated. It seems to occur
* for some values that are even multiples of 300
* more than the final value that should end up in the
* text field of the spinner. For those cases,
* the two digits that will be the final text in
* window will be the same as the last two digits of
* the larger number which was originally there,
* which is a probable cause of the problem.
* Ex: If the first value put in by the user after
* the window is opened is 300 in the recS field,
* the minutes will update to 5, but the seconds
* have repeatedly been found to remain at 300,
* instead of 00. This was found with the default
* windows XP look and feel.
* Calling fireStateChanged() seems to fix this issue.
*/
if (unclearBugFix) fireStateChanged();
}
}
/** The SpinnerNumberModel used for the recH spinner. */
private javax.swing.SpinnerNumberModel recHModel =
new javax.swing.SpinnerNumberModel(0, 0, null, 1);
/** The SpinnerNumberModel used for the stopH spinner. */
private javax.swing.SpinnerNumberModel stopHModel =
new javax.swing.SpinnerNumberModel(0, 0, null, 1);
/** The TimeModel used for the recM spinner. */
private TimeModel recMModel = new TimeModel(0, -1, null, 1);
/** The TimeModel used for the stopM spinner. */
private TimeModel stopMModel = new TimeModel(0, -1, null, 1);
/** The TimeModel used for the recS spinner. */
private TimeModel recSModel = new TimeModel(0, -1, null, 1);
/** The TimeModel used for the stopS spinner. */
private TimeModel stopSModel = new TimeModel(0, -1, null, 1);
/** Creates new KrutTimer.
*
* @param GUI The JFrame that this KrutTimer is
* being drawn in.
*/
public KrutTimer(javax.swing.JFrame GUI) {
myContainer = GUI;
initComponents();
initSpinners();
/** Initialize a timer that updates once per second. */
initTimer(1000);
jButton1.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
jCheckBox1.setFont(jTextField1.getFont());
}
/** This is used to give the KrutTimer direct access to the
* main GUI, for easy communication.
*/
public void setMainGUI(javax.swing.JFrame GUI) {
myContainer = GUI;
}
/** Used to set the output window for this KrutTimer.
*
* @param output An OutputText object that this
* KrutTimer can use for its output.
*/
public void setOutput(krut.KRUT_GUI.OutputText output) {
myOutput = output;
}
/** Set up the spinners to use SpinnerNumberModels, and also to
* interoperate with each other.
*/
private void initSpinners() {
/** Set the NumberModel to each spinner. */
recH.setModel(recHModel);
stopH.setModel(stopHModel);
recM.setModel(recMModel);
stopM.setModel(stopMModel);
recS.setModel(recSModel);
stopS.setModel(stopSModel);
/** Make the NumberModels aware of the parent JSPinners. */
recMModel.setParent(recH);
stopMModel.setParent(stopH);
recSModel.setParent(recM);
stopSModel.setParent(stopM);
/** The DoubleDigitFactory used to change the editors of the
* JFormattedTextFields in the spinners to double digit,
* (01 instead of 1, etc.)
*/
DoubleDigitFactory ddf = new DoubleDigitFactory();
javax.swing.JSpinner.NumberEditor tempEditor;
/** Change the recS spinner. */
tempEditor= (javax.swing.JSpinner.NumberEditor) recS.getEditor();
tempEditor.getTextField().setFormatterFactory(ddf);
/** Change the stopS spinner. */
tempEditor= (javax.swing.JSpinner.NumberEditor) stopS.getEditor();
tempEditor.getTextField().setFormatterFactory(ddf);
/** Change the recM spinner. */
tempEditor= (javax.swing.JSpinner.NumberEditor) recM.getEditor();
tempEditor.getTextField().setFormatterFactory(ddf);
/** Change the stopM spinner. */
tempEditor= (javax.swing.JSpinner.NumberEditor) stopM.getEditor();
tempEditor.getTextField().setFormatterFactory(ddf);
/** Change the recH spinner. */
tempEditor= (javax.swing.JSpinner.NumberEditor) recH.getEditor();
tempEditor.getTextField().setFormatterFactory(ddf);
/** Change the stopH spinner. */
tempEditor= (javax.swing.JSpinner.NumberEditor) stopH.getEditor();
tempEditor.getTextField().setFormatterFactory(ddf);
}
/** This initializes the timer, and makes it start to
* keep track of the calendar time. After this is done,
* the startTimer method must be called to start the KrutTimer,
* and the stopTimer method will stop the KrutTimer.
*
* @param msDelay The delay in ms between each
* update for the timer.
*/
public void initTimer(int msDelay) {
java.awt.event.ActionListener timerTask =
new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
timerAction();
}
};
timer = new javax.swing.Timer(msDelay, timerTask);
timer.start();
}
/** Start the KrutTimer */
public void startTimer() {
enableComponents(false);
startRecSeconds = getRecSeconds();
stopRecSeconds = getStopSeconds();
if (mode == COUNTDOWN) {
int currentTime = getCalendarSeconds();
startRecSeconds += currentTime;
stopRecSeconds += currentTime;
}
state = WAITING;
}
/** Stop the KrutTimer */
public void stopTimer() {
stopRecording();
enableComponents(true);
}
/** Sets the enabled state of selected components
* in the KrutTimer. This is used to disable some
* components while the timer is running.
*
* @param enabled The enabled state of the compontents.
*/
private void enableComponents(boolean enabled) {
jRadioButton1.setEnabled(enabled);
jRadioButton2.setEnabled(enabled);
jCheckBox1.setEnabled(enabled);
recH.setEnabled(enabled);
recM.setEnabled(enabled);
recS.setEnabled(enabled);
if (jCheckBox1.isSelected()) {
stopH.setEnabled(enabled);
stopM.setEnabled(enabled);
stopS.setEnabled(enabled);
}
}
/** Sets the mode of the KrutTimer. The mode should be
* set to either COUNTDOWN or COUNTUP.
* COUNTDOWN means that the timer will count down the number of
* hours, minutes and seconds given in the start-time in the GUI before starting
* to record, and then count down the time given in the stop-time in the GUI
* before stopping recording.
* COUNTUP means that the timer will start recording when the system clock
* reaches the time given in the start-time in the GUI, and stop recording
* when the system time reaches the stop-time given in the GUI.
*
* @param newMode An integer containing either COUNTDOWN
* or COUNTUP.
*/
public void setMode(int newMode) {
mode = newMode;
}
/** This is where the timer starts every new cycle.
*/
private void timerAction() {
if (mode == COUNTUP) checkMidnight();
if (state == NOT_ACTIVE) {
/** There would be no point in updating
* countdown times here (They are constant). */
updateCalendarTimes();
} else if (state == WAITING) {
/** We do not care about updating calendar times
* when the timer is active. It looks bad. */
updateCountdownTimes();
if (startRecSeconds <= getCalendarSeconds()) {
startRecording();
}
} else if ((state == RECORDING) && jCheckBox1.isSelected()) {
/** We do not care about updating calendar times
* when the timer is active. It looks bad. */
updateCountdownTimes();
if (stopRecSeconds <= getCalendarSeconds()) {
/** We quickly enable the button and perform a click,
* then we restore it to the state it is supposed to have.
*/
jToggleButton1.setEnabled(true);
jToggleButton1.doClick();
updateToggleButton();
}
}
}
/** This method is executed when the countUp or countDown
* methods find that the programmed time to start
* recording has been reached.
*/
private void startRecording() {
java.util.GregorianCalendar currentTime =
new java.util.GregorianCalendar();
int currentHour = currentTime.get(currentTime.HOUR_OF_DAY);
int currentMinute = currentTime.get(currentTime.MINUTE);
int currentSecond = currentTime.get(currentTime.SECOND);
state = RECORDING;
output("Timer started recording at " +
currentHour + ":" +
((currentMinute < 10) ? "0" : "") +
currentMinute + ":" +
((currentSecond < 10) ? "0" : "") +
currentSecond);
/** We temporarily change the action command of the
* JToggleButton to send a message to users that are
* listening for the "Start recording" action event.
* Then we enable it (which shouldn't be necessary,
* because it should always be enabled when the timer
* is active) and push it once. The action command
* will be restored by the action event in this class.
* We then do a updateToggleButton just to make sure we
* have the right value for the enabled state of the
* toggle button.
*/
jToggleButton1.setActionCommand("Timer recording");
jToggleButton1.setEnabled(true);
jToggleButton1.doClick();
updateToggleButton();
}
/** This method is executed when the countUp or countDown
* methods find that the programmed time to stop
* recording has been reached.
*/
private void stopRecording() {
java.util.GregorianCalendar currentTime =
new java.util.GregorianCalendar();
int currentHour = currentTime.get(currentTime.HOUR_OF_DAY);
int currentMinute = currentTime.get(currentTime.MINUTE);
int currentSecond = currentTime.get(currentTime.SECOND);
if (state == RECORDING) {
output("Timer stopped recording at " +
currentHour + ":" +
((currentMinute < 10) ? "0" : "") +
currentMinute + ":" +
((currentSecond < 10) ? "0" : "") +
currentSecond);
}
state = NOT_ACTIVE;
}
/** Send a string to the OutputText object in myOutput.
*
* @param The string to be printed in by myOutput.
*/
private void output(String outString) {
try {
myOutput.out(outString);
myOutput.out("");
} catch (Exception e) {
System.out.println("output error, KrutRecording.output");
System.out.println("");
}
}
/** Updates the time in the start-recording fields given the
* amount of seconds since last 00:00:00;
*
* @param seconds The number of seconds to be
* converted into a time and
* displayed in the start-
* recording fields.
*/
private void setRecFields(int seconds) {
int hours = getHours(seconds);
seconds -= hours * 3600;
int minutes = getMinutes(seconds);
seconds -= minutes * 60;
recS.setValue(seconds);
recM.setValue(minutes);
recH.setValue(hours);
}
/** Updates the time in the stop-recording fields given the
* amount of seconds since last 00:00:00;
*
* @param seconds The number of seconds to be
* converted into a time and
* displayed in the stop-
* recording fields.
*/
private void setStopFields(int seconds) {
int hours = getHours(seconds);
seconds -= hours * 3600;
int minutes = getMinutes(seconds);
seconds -= minutes * 60;
stopS.setValue(seconds);
stopM.setValue(minutes);
stopH.setValue(hours);
}
/** Updates the recording time and stopping time
* fields during a countdown.
*/
private void updateCountdownTimes() {
if (mode == COUNTUP) {
/** If the mode is COUNTUP, we shouldn't do
* anything here.
*/
} else if (state == WAITING) {
setRecFields(startRecSeconds - getCalendarSeconds());
if (jCheckBox1.isSelected()) {
setStopFields(stopRecSeconds - getCalendarSeconds());
}
} else if ((state == RECORDING) && jCheckBox1.isSelected()){
setStopFields(stopRecSeconds - getCalendarSeconds());
}
}
/** Updates the time fields so that the time
* given in them is never lower than the current
* time.
*/
private void updateCalendarTimes() {
/** If the mode is COUNTDOWN, we shouldn't do
* anything here.
*/
if (mode == COUNTDOWN) return;
int calendarSeconds = getCalendarSeconds();
if (getRecSeconds() < calendarSeconds) {
setRecFields(calendarSeconds);
}
}
/** Changes the time in the stop-time fields to read
* exactly the same as the time in the rec-time fields.
*/
private void syncTimes() {
setStopFields(getRecSeconds());
}
/** Checks if the time given in the stop-time fields is lower than
* the one in the rec-time fields. Also check jCheckBox1 before returning
* an answer.
*
* @return true if the time in the rec-time fields is higher than
* the one in the stop-time fields, or if jCheckBox1 is not
* selected. false if the time in the rec-time fields is
* lower than the one in the stop-time fields and jCheckBox1
* is selected.
*/
private boolean checkTimes() {
/** The only combination that will give false here is:
* box selected + stop < rec */
return (!jCheckBox1.isSelected() ||
(getRecSeconds() <= getStopSeconds()));
}
/** Controls that the total amount of hours
* since last midnight is not more than 24.
* Subtracts an integer multiple of 24h
* until a proper time is reached, and
* resets the time field. This is done
* for both start and stop times.
*/
private void checkMidnight() {
/** Get the start and stop times in seconds */
int rs = getRecSeconds();
int ss = getStopSeconds();
boolean rec = false, stop = false;
/** Are they over 24h? */
while (24 <= getHours(rs)) {
rs -= 24*3600;
rec = true;
}
while (24 <= getHours(ss)) {
ss -= 24*3600;
stop = true;
}
/** Correct if they are. */
if (rec) setRecFields(rs);
if (stop) setStopFields(ss);
}
/** Get the value of the time entered into the record
* time fields, expressed in seconds.
*
* return The total amount of seconds entered into the record time fields.
*/
private int getRecSeconds() {
int recHour = (Integer) recH.getValue();
int recMinute = (Integer) recM.getValue();
int recSecond = (Integer) recS.getValue();
return getSeconds(recHour, recMinute, recSecond);
}
/** Get the value of the time entered into the stop
* time fields, expressed in seconds.
*
* @return The total amount of seconds entered into the stop time fields.
*/
private int getStopSeconds() {
int stopHour = (Integer) stopH.getValue();
int stopMinute = (Integer) stopM.getValue();
int stopSecond = (Integer) stopS.getValue();
return getSeconds(stopHour, stopMinute, stopSecond);
}
/** Get the value of the current calendar time,
* expressed in seconds.
*
* @return The total amount of seconds since last midnight.
*/
private int getCalendarSeconds() {
java.util.GregorianCalendar currentTime =
new java.util.GregorianCalendar();
int currentHour = currentTime.get(currentTime.HOUR_OF_DAY);
int currentMinute = currentTime.get(currentTime.MINUTE);
int currentSecond = currentTime.get(currentTime.SECOND);
return getSeconds(currentHour, currentMinute, currentSecond);
}
/** Returns the number of whole hours in a time given in
* seconds.
*
* @param seconds The total number of seconds
*
* @return The total number of whole hours.
*/
public int getHours(int seconds) {
return (seconds / 3600);
}
/** Returns the number of whole minutes in a time given in
* seconds.
*
* @param seconds The total number of seconds
*
* @return The total number of whole minutes.
*/
public int getMinutes(int seconds) {
return (seconds / 60);
}
/** Gives the number of seconds in the time given in the
* input parameters.
*
* @param hours The number of hours
* @param minutes The number of minutes
* @param seconds The number of seconds
*
* @return The total number of seconds.
*/
public int getSeconds(int hours, int minutes, int seconds) {
return seconds + 60 * minutes + 3600 * hours;
}
/** When the user switches between relative time and
* actual time, this method is used to save the
* time that was entered in the time fields,
* and restore the calendar/actual time that was
* last entered.
*/
private void restoreTime() {
int tempRecH = (Integer) recH.getValue();
int tempRecM = (Integer) recM.getValue();
int tempRecS = (Integer) recS.getValue();
int tempStopH = (Integer) stopH.getValue();
int tempStopM = (Integer) stopM.getValue();
int tempStopS = (Integer) stopS.getValue();
setRecFields(getSeconds(recHMemory, recMMemory, recSMemory));
setStopFields(getSeconds(stopHMemory, stopMMemory, stopSMemory));
recSMemory = tempRecS;
recMMemory = tempRecM;
recHMemory = tempRecH;
stopSMemory = tempStopS;
stopMMemory = tempStopM;
stopHMemory = tempStopH;
}
/** Controls if the "Activate Timer"-buttons should be
* enabled or disabled. It should be enabled if the
* given starting time of recording is more than 0s
* into the future. This method also enables or disables
* the button based on the results.
*
* This method also makes sure that the toggleButton is
* selected when the timer is activated and deselected
* when the timer not activated.
*/
public void updateToggleButton() {
if (state == NOT_ACTIVE) {
jToggleButton1.setSelected(false);
if (mode == COUNTDOWN) {
if (getRecSeconds() == 0) {
disableToggleButton();
} else {
enableToggleButton();
}
} else if (mode == COUNTUP) {
if (getCalendarSeconds() < getRecSeconds()) {
enableToggleButton();
} else {
disableToggleButton();
}
}
} else {
jToggleButton1.setSelected(true);
}
}
/** Disables the "Activate Timer" togglebutton.
*/
public void disableToggleButton() {
jToggleButton1.setEnabled(false);
jToggleButton1.setToolTipText("<HTML>The Start time must be more than 0 seconds away<BR>" +
"for this button to activate.</HTML>");
}
/** Enables the "Activate Timer" togglebutton.
*/
public void enableToggleButton() {
jToggleButton1.setEnabled(true);
jToggleButton1.setToolTipText("");
}
/** This method returns the toggle button that activates
* the timer, so that the user can decide what to do
* when the timer is activated. The following ActionEvents
* will be fired to all ActionListeners on the button:
*
* Action: Action name:
* Timer activated "Timer active"
* Recording started "Timer recording"
* Recording stopped "Timer stopped"
*
* @return the JToggleButton that activates the timer.
*/
public javax.swing.JToggleButton getTimerButton() {
return jToggleButton1;
}
/** Returns the mode of the timer, either
* COUNTDOWN or COUNTUP.
*
* @return The mode of the timer.
*/
public int getMode() {
return mode;
}
/** Returns the state of the timer, either
* NOT_ACTIVE, RECORDING or WAITING.
*
* @return The state of the timer.
*/
public int getState() {
return state;
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
buttonGroup1 = new javax.swing.ButtonGroup();
jScrollPane1 = new javax.swing.JScrollPane();
jPanel3 = new javax.swing.JPanel();
jPanel1 = new javax.swing.JPanel();
jRadioButton1 = new javax.swing.JRadioButton();
jRadioButton2 = new javax.swing.JRadioButton();
jPanel2 = new javax.swing.JPanel();
jTextField1 = new javax.swing.JTextField();
recH = new javax.swing.JSpinner();
recS = new javax.swing.JSpinner();
recM = new javax.swing.JSpinner();
stopH = new javax.swing.JSpinner();
stopS = new javax.swing.JSpinner();
stopM = new javax.swing.JSpinner();
jCheckBox1 = new javax.swing.JCheckBox();
jToggleButton1 = new javax.swing.JToggleButton();
jButton1 = new javax.swing.JButton();
jSeparator1 = new javax.swing.JSeparator();
setLayout(new java.awt.GridBagLayout());
jScrollPane1.setBorder(null);
jPanel3.setLayout(new java.awt.GridBagLayout());
jPanel1.setLayout(new java.awt.GridBagLayout());
jPanel1.setBorder(new javax.swing.border.TitledBorder(null, "Use:"));
buttonGroup1.add(jRadioButton1);
jRadioButton1.setSelected(true);
jRadioButton1.setText("Relative time");
jRadioButton1.setToolTipText("<HTML>Start and stop recording at the given times (HH:MM:SS),<BR>\ncounted from when the \"Activate Timer\"-button is pressed</HTML>");
jRadioButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jRadioButton1ActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
jPanel1.add(jRadioButton1, gridBagConstraints);
buttonGroup1.add(jRadioButton2);
jRadioButton2.setText("Actual time");
jRadioButton2.setToolTipText("<HTML>Start and stop recording when the calendar clock of<BR>your system reaches the given times (HH:MM:SS)</HTML>");
jRadioButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jRadioButton2ActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
jPanel1.add(jRadioButton2, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 0.5;
jPanel3.add(jPanel1, gridBagConstraints);
jPanel2.setLayout(new java.awt.GridBagLayout());
jPanel2.setBorder(new javax.swing.border.TitledBorder(null, "Recording timer"));
jTextField1.setEditable(false);
jTextField1.setText("Start in:");
jTextField1.setBorder(null);
jTextField1.setPreferredSize(new java.awt.Dimension(50, 14));
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
jPanel2.add(jTextField1, gridBagConstraints);
recH.setToolTipText("Hours");
recH.setPreferredSize(new java.awt.Dimension(35, 18));
recH.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
recHStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
jPanel2.add(recH, gridBagConstraints);
recS.setToolTipText("Seconds");
recS.setPreferredSize(new java.awt.Dimension(32, 18));
recS.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
recSStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 3;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.weightx = 0.5;
gridBagConstraints.weighty = 0.5;
jPanel2.add(recS, gridBagConstraints);
recM.setToolTipText("Minutes");
recM.setPreferredSize(new java.awt.Dimension(32, 18));
recM.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
recMStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.weightx = 0.5;
gridBagConstraints.weighty = 0.5;
jPanel2.add(recM, gridBagConstraints);
stopH.setToolTipText("Hours");
stopH.setEnabled(false);
stopH.setPreferredSize(new java.awt.Dimension(35, 18));
stopH.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
stopHStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
jPanel2.add(stopH, gridBagConstraints);
stopS.setToolTipText("Seconds");
stopS.setEnabled(false);
stopS.setPreferredSize(new java.awt.Dimension(32, 18));
stopS.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
stopSStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 3;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.weightx = 0.5;
gridBagConstraints.weighty = 0.5;
jPanel2.add(stopS, gridBagConstraints);
stopM.setToolTipText("Minutes");
stopM.setEnabled(false);
stopM.setPreferredSize(new java.awt.Dimension(32, 18));
stopM.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent evt) {
stopMStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
gridBagConstraints.weightx = 0.5;
gridBagConstraints.weighty = 0.5;
jPanel2.add(stopM, gridBagConstraints);
jCheckBox1.setText("Stop in:");
jCheckBox1.setToolTipText("<HTML>Check box to enable stop-time.<BR>\nIf this box is unchecked, recording will not stop automatically.</HTML>");
jCheckBox1.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
jCheckBox1ItemStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
jPanel2.add(jCheckBox1, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 0.1;
jPanel3.add(jPanel2, gridBagConstraints);
jToggleButton1.setText("Activate Timer");
jToggleButton1.setToolTipText("<HTML>The Start time must be more than 0 seconds away<BR>for this button to activate.</HTML>");
jToggleButton1.setActionCommand("Timer active");
jToggleButton1.setEnabled(false);
jToggleButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jToggleButton1ActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 4;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 0.1;
jPanel3.add(jToggleButton1, gridBagConstraints);
jButton1.setFont(new java.awt.Font("Tahoma", 0, 10));
jButton1.setForeground(java.awt.SystemColor.activeCaption);
jButton1.setText("Close");
jButton1.setBorder(null);
jButton1.setBorderPainted(false);
jButton1.setContentAreaFilled(false);
jButton1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
jButton1.setIconTextGap(0);
jButton1.setMaximumSize(new java.awt.Dimension(27, 13));
jButton1.setPreferredSize(new java.awt.Dimension(27, 9));
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
jButton1.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
jButton1MouseEntered(evt);
}
public void mouseExited(java.awt.event.MouseEvent evt) {
jButton1MouseExited(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 2);
jPanel3.add(jButton1, gridBagConstraints);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
jPanel3.add(jSeparator1, gridBagConstraints);
jScrollPane1.setViewportView(jPanel3);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(jScrollPane1, gridBagConstraints);
}
// </editor-fold>//GEN-END:initComponents
private void recSStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_recSStateChanged
// TODO add your handling code here:
if (!checkTimes()) syncTimes();
updateToggleButton();
}//GEN-LAST:event_recSStateChanged
private void recMStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_recMStateChanged
// TODO add your handling code here:
if (!checkTimes()) syncTimes();
updateToggleButton();
}//GEN-LAST:event_recMStateChanged
private void recHStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_recHStateChanged
// TODO add your handling code here:
if (!checkTimes()) syncTimes();
updateToggleButton();
}//GEN-LAST:event_recHStateChanged
private void stopHStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_stopHStateChanged
// TODO add your handling code here:
if (!checkTimes()) syncTimes();
updateToggleButton();
}//GEN-LAST:event_stopHStateChanged
private void stopMStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_stopMStateChanged
// TODO add your handling code here:
if (!checkTimes()) syncTimes();
updateToggleButton();
}//GEN-LAST:event_stopMStateChanged
private void stopSStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_stopSStateChanged
// TODO add your handling code here:
if (!checkTimes()) syncTimes();
updateToggleButton();
}//GEN-LAST:event_stopSStateChanged
private void jCheckBox1ItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_jCheckBox1ItemStateChanged
// TODO add your handling code here:
if (evt.getStateChange() == java.awt.event.ItemEvent.SELECTED) {
stopS.setEnabled(true);
stopM.setEnabled(true);
stopH.setEnabled(true);
if (!checkTimes()) syncTimes();
} else if (evt.getStateChange() == java.awt.event.ItemEvent.DESELECTED) {
stopS.setEnabled(false);
stopM.setEnabled(false);
stopH.setEnabled(false);
}
}//GEN-LAST:event_jCheckBox1ItemStateChanged
private void jButton1MouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jButton1MouseExited
// TODO add your handling code here:
jButton1.setFont(new java.awt.Font("Tahoma", 0, 10));
}//GEN-LAST:event_jButton1MouseExited
private void jButton1MouseEntered(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jButton1MouseEntered
// TODO add your handling code here:
jButton1.setFont(new java.awt.Font("Tahoma", 1, 10));
}//GEN-LAST:event_jButton1MouseEntered
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
// TODO add your handling code here:
setVisible(false);
if (myContainer != null) {
myContainer.pack();
}
}//GEN-LAST:event_jButton1ActionPerformed
private void jRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButton1ActionPerformed
// TODO add your handling code here:
if (jRadioButton1.isSelected() && (mode == COUNTUP)) {
setMode(COUNTDOWN);
jTextField1.setText("Start in:");
jCheckBox1.setText("Stop in:");
restoreTime();
timerAction();
}
}//GEN-LAST:event_jRadioButton1ActionPerformed
private void jRadioButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButton2ActionPerformed
// TODO add your handling code here:
if (jRadioButton2.isSelected() && (mode == COUNTDOWN)) {
setMode(COUNTUP);
jTextField1.setText("Start at:");
jCheckBox1.setText("Stop at:");
restoreTime();
timerAction();
}
}//GEN-LAST:event_jRadioButton2ActionPerformed
private void jToggleButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jToggleButton1ActionPerformed
// TODO add your handling code here:
if (evt.getActionCommand().equals("Timer active")) {
jToggleButton1.setText("Stop Timer");
startTimer();
jToggleButton1.setActionCommand("Timer stopped");
} else if(evt.getActionCommand().equals("Timer recording")) {
jToggleButton1.setActionCommand("Timer stopped");
} else if (evt.getActionCommand().equals("Timer stopped")) {
jToggleButton1.setText("Activate Timer");
stopTimer();
jToggleButton1.setActionCommand("Timer active");
updateToggleButton();
}
repaint();
}//GEN-LAST:event_jToggleButton1ActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.JButton jButton1;
private javax.swing.JCheckBox jCheckBox1;
private javax.swing.JPanel jPanel1;
private javax.swing.JPanel jPanel2;
private javax.swing.JPanel jPanel3;
private javax.swing.JRadioButton jRadioButton1;
private javax.swing.JRadioButton jRadioButton2;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JSeparator jSeparator1;
private javax.swing.JTextField jTextField1;
private javax.swing.JToggleButton jToggleButton1;
private javax.swing.JSpinner recH;
private javax.swing.JSpinner recM;
private javax.swing.JSpinner recS;
private javax.swing.JSpinner stopH;
private javax.swing.JSpinner stopM;
private javax.swing.JSpinner stopS;
// End of variables declaration//GEN-END:variables
}