/* HCalc.java App/applet to calculate decimal hours worked from start and end times and total of break durations Notice: This program is free software; you can redistribute it and/or modify it under the terms Version 2 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. You can also find a copy at the Free Software Foundation's website, http://www.gnu.org. History: 22 Aug 2006 Add Notice. 21 Aug 2006 "Hours Calculator" -> "Work Hours Calculator". 18 Aug 2006 Change updateValue() to updateHoursWorked() and m_amorpm to m_am_or_pm. Change return type of getValue() from float to int and simplify calculation. Add AMorPM.setAM(). Don't put listener arg in constructor; instead have add___Listener() members. Add setAM() and setValue() 17 Aug 2006 Don't bother with variables to hold spacer Objects. Use pack() to size JFrame rather than setSize(). Put main() in HCalc rather than derived class. Use setVisible() instead of deprecated show(). Substitute "break" for "meal" everywhere. 13 Aug 2006 Minor computation correction. 01 Aug 2006 Use JFrame.setDefaultCloseOperation() instead of addWindowListener(). 31 Jul 2006 First draft. */ import java.awt.*; import javax.swing.*; import javax.swing.event.*; import java.awt.event.*; /** Calculate hours worked with allowance for break durations. @author Bob Burkhardt */ public class HCalc extends JApplet implements ChangeListener, ItemListener { TimePanel m_start_time, m_end_time; DurationPanel m_breaks; JLabel m_hours_worked_label, m_hours_worked; JPanel m_main_panel, m_hours_panel, m_hours_worked_panel; public static void main(String args[]) { JFrame f = new JFrame("Work Hours Calculator"); HCalc calc = new HCalc(); calc.init(); f.getContentPane().add(calc); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.pack(); f.setVisible(true); calc.start(); } public void init() { getContentPane().setLayout(new FlowLayout()); m_main_panel = new JPanel(); m_main_panel.setLayout(new BoxLayout(m_main_panel, BoxLayout.Y_AXIS)); // start and end time m_hours_panel = new JPanel(); m_hours_panel.setLayout(new BoxLayout(m_hours_panel, BoxLayout.X_AXIS)); // start time m_start_time = new TimePanel("Start Time"); m_start_time.addItemListener(this); m_start_time.addChangeListener(this); m_start_time.setValue(9*60); m_hours_panel.add(m_start_time); // spacer m_hours_panel.add(m_start_time.createBoxSpacer()); // end time m_end_time = new TimePanel("End Time"); m_end_time.addItemListener(this); m_end_time.addChangeListener(this); m_end_time.setValue(12*60 + 5*60); m_hours_panel.add(m_end_time); // spacer m_main_panel.add(m_end_time.createLabelSpacer()); m_main_panel.add(m_hours_panel); // spacer m_main_panel.add(m_end_time.createLabelSpacer()); // breaks duration m_breaks = new DurationPanel("Breaks Duration"); m_breaks.addItemListener(this); m_main_panel.add(m_breaks); // spacer m_main_panel.add(m_end_time.createLabelSpacer()); // hours worked m_hours_worked_panel = new JPanel(); m_hours_worked_panel.setLayout (new BoxLayout(m_hours_worked_panel, BoxLayout.Y_AXIS)); m_hours_worked_label = new JLabel("Hours Worked", JLabel.CENTER); m_hours_worked_label.setAlignmentX(JLabel.CENTER_ALIGNMENT); m_hours_worked_panel.add(m_hours_worked_label); m_hours_worked = new JLabel("0.00", JLabel.CENTER); m_hours_worked.setAlignmentX(JLabel.CENTER_ALIGNMENT); m_hours_worked_panel.add(m_hours_worked); m_main_panel.add(m_hours_worked_panel); // spacer m_main_panel.add(m_end_time.createLabelSpacer()); getContentPane().add(m_main_panel); updateHoursWorked(); } /** Handle AM/PM changes (implements ChangeListener). */ public void stateChanged(ChangeEvent evt) { updateHoursWorked(); } /** Handle JComboBox changes (implements ItemListener). */ public void itemStateChanged(ItemEvent evt) { updateHoursWorked(); } /** Recalculate hours worked and post it. */ void updateHoursWorked() { if (m_hours_worked == null) return; int start = m_start_time.getValue(); int end = m_end_time.getValue(); int breaks = m_breaks.getValue(); if (start > end) end += 24*60; int totalMinutes = end - start - breaks; float hours = (float)Math.floor(totalMinutes*(100f/60f) + 0.5f)/100f; m_hours_worked.setText(Float.toString(hours)); } } class AMorPM extends JPanel { JRadioButton m_am, m_pm; ButtonGroup m_group; /** Create AM-PM panel set to prescribed value (true == AM). */ AMorPM(boolean isAM) { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); m_am = new JRadioButton("AM"); m_pm = new JRadioButton("PM"); m_group = new ButtonGroup(); m_group.add(m_am); add(m_am); m_group.add(m_pm); add(m_pm); setAM(isAM); } /** Create AM-PM panel set to AM. */ AMorPM() { this(true); } void addChangeListener(ChangeListener listener) { m_am.addChangeListener(listener); } boolean isAM() { return m_am.isSelected(); } void setAM(boolean isAM) { m_am.setSelected(isAM); m_pm.setSelected(!isAM); } } class TimePanel extends DurationPanel { AMorPM m_am_or_pm; TimePanel(String label) { super(label, m_hour); m_am_or_pm = new AMorPM(); m_input_panel.add(m_am_or_pm); add(m_input_panel); } void addChangeListener(ChangeListener listener) { m_am_or_pm.addChangeListener(listener); } int getValue() { return super.getValue() + (m_am_or_pm.isAM() ? 0 : 60*12); } void setValue(int value) { if (value >= 12*60) { m_am_or_pm.setAM(false); value -= 12*60; } super.setValue(value); } static final String[] m_hour = { "12", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11" }; } class DurationPanel extends JPanel { JLabel m_label, m_colon_label; protected JComboBox m_hours, m_minutes; JPanel m_input_panel; DurationPanel(String label) { this(label, m_hour); } protected DurationPanel(String label, String[] hours) { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); m_label = new JLabel(label, JLabel.CENTER); m_label.setAlignmentX(JLabel.CENTER_ALIGNMENT); add(m_label); m_input_panel = new JPanel(); m_input_panel.setLayout(new FlowLayout()); m_hours = new JComboBox(hours); m_input_panel.add(m_hours); m_colon_label = new JLabel(":"); m_input_panel.add(m_colon_label); m_minutes = new JComboBox(m_minute); m_input_panel.add(m_minutes); add(m_input_panel); } void addItemListener(ItemListener listener) { m_hours.addItemListener(listener); m_minutes.addItemListener(listener); } /** Returns a spacer element the same size as the minutes JComboBox. */ Box.Filler createBoxSpacer() { Dimension dim = m_minutes.getPreferredSize(); return new Box.Filler(dim, dim, dim); } /** Returns a spacer element the same size as the panel JLabel. */ Box.Filler createLabelSpacer() { Dimension dim = m_label.getPreferredSize(); return new Box.Filler(dim, dim, dim); } /** Calculate duration value in minutes. */ int getValue() { return 60*m_hours.getSelectedIndex() + 5*m_minutes.getSelectedIndex(); } /** Set the duration value to the greatest valid setting less than the value specified and the maximum possible. @param totalMinutes total duration in minutes */ void setValue(int totalMinutes) { if (totalMinutes < 0) totalMinutes = 0; int hours = totalMinutes/60; int minutes = (totalMinutes - hours*60)/5; if (hours > m_hour.length) hours = m_hour.length; m_hours.setSelectedIndex(hours); m_minutes.setSelectedIndex(minutes); } static final String[] m_minute = { "00", "05", "10", "15", "20", "25", "30", "35", "40", "45", "50", "55" }; static final String[] m_hour = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11" }; }