/* | |
* Copyright 2001-2005 Stephen Colebourne | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package org.joda.example.time; | |
import java.awt.Component; | |
import java.awt.Container; | |
import java.awt.Dimension; | |
import java.awt.GridBagConstraints; | |
import java.awt.GridBagLayout; | |
import java.awt.event.ActionEvent; | |
import java.awt.event.ActionListener; | |
import java.awt.event.ItemEvent; | |
import java.awt.event.ItemListener; | |
import javax.swing.BorderFactory; | |
import javax.swing.Box; | |
import javax.swing.BoxLayout; | |
import javax.swing.JCheckBox; | |
import javax.swing.JComboBox; | |
import javax.swing.JComponent; | |
import javax.swing.JFrame; | |
import javax.swing.JLabel; | |
import javax.swing.JPanel; | |
import javax.swing.JTextField; | |
import javax.swing.Timer; | |
import javax.swing.event.DocumentEvent; | |
import javax.swing.event.DocumentListener; | |
import javax.swing.text.Document; | |
import org.joda.time.Chronology; | |
import org.joda.time.DateTime; | |
import org.joda.time.DateTimeZone; | |
import org.joda.time.DurationField; | |
import org.joda.time.chrono.ISOChronology; | |
/** | |
* AgeCalculator is a small Swing application that computes age from a specific | |
* birthdate and time zone. Age is broken down into multiple fields, which can | |
* be independently disabled. | |
* | |
* @author Brian S O'Neill | |
*/ | |
public class AgeCalculator extends JFrame { | |
static final int | |
YEARS = 1, | |
MONTHS = 2, | |
DAYS = 3, | |
WEEKYEARS = 4, | |
WEEKS = 5, | |
HOURS = 101, | |
MINUTES = 102, | |
SECONDS = 103; | |
public static void main(String[] args) throws Exception { | |
new AgeCalculator().show(); | |
} | |
static JComponent fixedSize(JComponent component) { | |
component.setMaximumSize(component.getPreferredSize()); | |
return component; | |
} | |
static JComponent fixedHeight(JComponent component) { | |
Dimension dim = component.getMaximumSize(); | |
dim.height = component.getPreferredSize().height; | |
component.setMaximumSize(dim); | |
return component; | |
} | |
Chronology iChronology; | |
private String iBirthdateStr; | |
private FieldSet[] iFieldSets; | |
private Timer iTimer; | |
public AgeCalculator() { | |
super(); | |
iChronology = ISOChronology.getInstance(); | |
iBirthdateStr = "1970-01-01T00:00:00"; | |
setTitle("Age Calculator"); | |
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); | |
addMainArea(getContentPane()); | |
addNotify(); | |
Dimension size = getPreferredSize(); | |
setSize(size); | |
Dimension screenSize = getToolkit().getScreenSize(); | |
setLocation(screenSize.width / 2 - size.width / 2, | |
screenSize.height / 2 - size.height / 2); | |
iTimer = new Timer(500, new ActionListener() { | |
public void actionPerformed(ActionEvent e) { | |
updateResults(); | |
} | |
}); | |
iTimer.setInitialDelay(0); | |
iTimer.start(); | |
} | |
private void addMainArea(Container container) { | |
JPanel panel = new JPanel(); | |
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); | |
addTopArea(panel); | |
panel.add(Box.createVerticalStrut(10)); | |
addBottomArea(panel); | |
panel.add(Box.createVerticalGlue()); | |
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); | |
container.add(panel); | |
} | |
private void addTopArea(Container container) { | |
JPanel panel = new JPanel(); | |
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); | |
panel.add(fixedHeight(new JLabel("Birthdate"))); | |
panel.add(Box.createHorizontalStrut(10)); | |
final JTextField birthdateField = new JTextField(iBirthdateStr + ' '); | |
Document doc = birthdateField.getDocument(); | |
doc.addDocumentListener(new DocumentListener() { | |
public void insertUpdate(DocumentEvent e) { | |
update(e); | |
} | |
public void removeUpdate(DocumentEvent e) { | |
update(e); | |
} | |
public void changedUpdate(DocumentEvent e) { | |
update(e); | |
} | |
private void update(DocumentEvent e) { | |
iBirthdateStr = birthdateField.getText(); | |
updateResults(); | |
} | |
}); | |
panel.add(fixedHeight(birthdateField)); | |
panel.add(Box.createHorizontalStrut(10)); | |
Object[] ids = DateTimeZone.getAvailableIDs().toArray(); | |
final JComboBox zoneSelector = new JComboBox(ids); | |
zoneSelector.setSelectedItem(DateTimeZone.getDefault().getID()); | |
panel.add(fixedSize(zoneSelector)); | |
zoneSelector.addActionListener(new ActionListener() { | |
public void actionPerformed(ActionEvent e) { | |
String id = (String)zoneSelector.getSelectedItem(); | |
iChronology = ISOChronology.getInstance(DateTimeZone.forID(id)); | |
updateResults(); | |
} | |
}); | |
container.add(fixedHeight(panel)); | |
} | |
private void addBottomArea(Container container) { | |
JPanel panel = new JPanel(); | |
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); | |
ItemListener listener = new ItemListener() { | |
public void itemStateChanged(ItemEvent e) { | |
updateResults(); | |
} | |
}; | |
iFieldSets = new FieldSet[] { | |
new FieldSet("Month Based", new FieldGroup[] { | |
new FieldGroup(listener, "Years", YEARS), | |
new FieldGroup(listener, "Months", MONTHS), | |
new FieldGroup(listener, "Days", DAYS), | |
new FieldGroup(listener, "Hours", HOURS), | |
new FieldGroup(listener, "Minutes", MINUTES), | |
new FieldGroup(listener, "Seconds", SECONDS) | |
}) | |
, | |
new FieldSet("Week Based", new FieldGroup[] { | |
new FieldGroup(listener, "Weekyears", WEEKYEARS), | |
new FieldGroup(listener, "Weeks", WEEKS), | |
new FieldGroup(listener, "Days", DAYS), | |
new FieldGroup(listener, "Hours", HOURS), | |
new FieldGroup(listener, "Minutes", MINUTES), | |
new FieldGroup(listener, "Seconds", SECONDS) | |
}) | |
}; | |
for (int i=0; i<iFieldSets.length; i++) { | |
if (i > 0) { | |
panel.add(Box.createHorizontalStrut(10)); | |
} | |
iFieldSets[i].addTo(panel); | |
} | |
panel.add(Box.createVerticalGlue()); | |
container.add(fixedHeight(panel)); | |
} | |
private void updateResults() { | |
try { | |
DateTime dt = new DateTime(iBirthdateStr.trim(), iChronology); | |
long minuend = System.currentTimeMillis(); | |
long subtrahend = dt.getMillis(); | |
for (int i=0; i<iFieldSets.length; i++) { | |
iFieldSets[i].updateResults(minuend, subtrahend); | |
} | |
} | |
catch (IllegalArgumentException e) { | |
for (int i=0; i<iFieldSets.length; i++) { | |
iFieldSets[i].setResultsText(""); | |
} | |
} | |
} | |
private class FieldGroup { | |
public final JCheckBox iCheckbox; | |
public final JTextField iResult; | |
public final int iFieldType; | |
FieldGroup(ItemListener listener, String checkboxText, int fieldType) { | |
iCheckbox = new JCheckBox(checkboxText, true); | |
iCheckbox.addItemListener(listener); | |
iResult = new JTextField(); | |
iResult.setEditable(false); | |
iFieldType = fieldType; | |
} | |
public long updateResult(long minuend, long subtrahend) { | |
// Because time zone can be dynamically changed, field must be | |
// dynamically acquired. | |
DurationField field; | |
switch (iFieldType) { | |
case YEARS: | |
field = iChronology.years(); | |
break; | |
case MONTHS: | |
field = iChronology.months(); | |
break; | |
case DAYS: | |
field = iChronology.days(); | |
break; | |
case WEEKYEARS: | |
field = iChronology.weekyears(); | |
break; | |
case WEEKS: | |
field = iChronology.weeks(); | |
break; | |
case HOURS: | |
field = iChronology.hours(); | |
break; | |
case MINUTES: | |
field = iChronology.minutes(); | |
break; | |
case SECONDS: default: | |
field = iChronology.seconds(); | |
break; | |
} | |
String textToSet = ""; | |
if (iCheckbox.isSelected()) { | |
long difference = field.getDifferenceAsLong(minuend, subtrahend); | |
textToSet = Long.toString(difference); | |
subtrahend = field.add(subtrahend, difference); | |
} | |
if (!iResult.getText().equals(textToSet)) { | |
iResult.setText(textToSet); | |
} | |
return subtrahend; | |
} | |
public void setResultText(String text) { | |
iResult.setText(text); | |
} | |
} | |
private static class FieldSet { | |
private final String iTitle; | |
private final FieldGroup[] iGroups; | |
FieldSet(String title, FieldGroup[] groups) { | |
iTitle = title; | |
iGroups = groups; | |
} | |
private long updateResults(long minuend, long subtrahend) { | |
for (int i=0; i<iGroups.length; i++) { | |
subtrahend = iGroups[i].updateResult(minuend, subtrahend); | |
} | |
return subtrahend; | |
} | |
public void setResultsText(String text) { | |
for (int i=0; i<iGroups.length; i++) { | |
iGroups[i].setResultText(text); | |
} | |
} | |
private void addTo(Container container) { | |
JPanel panel = new JPanel(); | |
GridBagLayout layout = new GridBagLayout(); | |
panel.setLayout(layout); | |
panel.setBorder(BorderFactory.createTitledBorder(iTitle)); | |
for (int i=0; i<iGroups.length; i++) { | |
FieldGroup fg = iGroups[i]; | |
panel.add(fg.iCheckbox); | |
setCheckboxConstraints(layout, fg.iCheckbox, 0, i); | |
panel.add(fg.iResult); | |
setResultConstraints(layout, fg.iResult, 1, i); | |
} | |
container.add(fixedHeight(panel)); | |
} | |
private void setCheckboxConstraints(GridBagLayout layout, Component c, | |
int x, int y) | |
{ | |
GridBagConstraints cons = new GridBagConstraints(); | |
cons.gridx = x; | |
cons.gridy = y; | |
cons.weightx = 0.1; | |
cons.anchor = GridBagConstraints.WEST; | |
layout.setConstraints(c, cons); | |
} | |
private void setResultConstraints(GridBagLayout layout, Component c, | |
int x, int y) | |
{ | |
GridBagConstraints cons = new GridBagConstraints(); | |
cons.gridx = x; | |
cons.gridy = y; | |
cons.weightx = 1.0; | |
cons.anchor = GridBagConstraints.WEST; | |
cons.fill = GridBagConstraints.HORIZONTAL; | |
layout.setConstraints(c, cons); | |
} | |
} | |
} |