Swing: Date Time Editor
/*
Swing, Second Edition
by Matthew Robinson, Pavel Vorobiev
*/
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.DateFormat;
import java.text.FieldPosition;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.NoSuchElementException;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.basic.BasicArrowButton;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Caret;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.JTextComponent;
import javax.swing.text.Keymap;
import javax.swing.text.PlainDocument;
import javax.swing.text.TextAction;
public class DateTimeEditor extends JPanel {
public static final long ONE_SECOND = 1000;
public static final long ONE_MINUTE = 60 * ONE_SECOND;
public static final long ONE_HOUR = 60 * ONE_MINUTE;
public static final long ONE_DAY = 24 * ONE_HOUR;
public static final long ONE_WEEK = 7 * ONE_DAY;
public final static int TIME = 0;
public final static int DATE = 1;
public final static int DATETIME = 2;
private int m_timeOrDateType;
private int m_lengthStyle;
private DateFormat m_format;
private Calendar m_calendar = Calendar.getInstance();
private ArrayList m_fieldPositions = new ArrayList();
private Date m_lastDate = new Date();
private Caret m_caret;
private int m_curField = -1;
private JTextField m_textField;
private Spinner m_spinner;
private AbstractAction m_upAction = new UpDownAction(1, "up");
private AbstractAction m_downAction = new UpDownAction(-1, "down");
private boolean m_settingDateText = false; // BUG FIX
private int[] m_fieldTypes = { DateFormat.ERA_FIELD, DateFormat.YEAR_FIELD,
DateFormat.MONTH_FIELD, DateFormat.DATE_FIELD,
DateFormat.HOUR_OF_DAY1_FIELD, DateFormat.HOUR_OF_DAY0_FIELD,
DateFormat.MINUTE_FIELD, DateFormat.SECOND_FIELD,
DateFormat.MILLISECOND_FIELD, DateFormat.DAY_OF_WEEK_FIELD,
DateFormat.DAY_OF_YEAR_FIELD,
DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD,
DateFormat.WEEK_OF_YEAR_FIELD, DateFormat.WEEK_OF_MONTH_FIELD,
DateFormat.AM_PM_FIELD, DateFormat.HOUR1_FIELD,
DateFormat.HOUR0_FIELD };
public DateTimeEditor() {
m_timeOrDateType = DATETIME;
m_lengthStyle = DateFormat.SHORT;
init();
}
public DateTimeEditor(int timeOrDateType) {
m_timeOrDateType = timeOrDateType;
m_lengthStyle = DateFormat.FULL;
init();
}
public DateTimeEditor(int timeOrDateType, int lengthStyle) {
m_timeOrDateType = timeOrDateType;
m_lengthStyle = lengthStyle;
init();
}
private void init() {
setLayout(new BorderLayout());
m_textField = new JTextField();
m_textField.setDocument(new DateTimeDocument()); // BUG FIX
m_spinner = new Spinner();
m_spinner.getIncrementButton().addActionListener(m_upAction);
m_spinner.getDecrementButton().addActionListener(m_downAction);
add(m_textField, "Center");
add(m_spinner, "East");
m_caret = m_textField.getCaret();
m_caret.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent evt) {
setCurField();
}
});
setupKeymap();
reinit();
}
protected class DateTimeDocument extends PlainDocument {
public void insertString(int offset, String str, AttributeSet a)
throws BadLocationException {
if (m_settingDateText)
super.insertString(offset, str, a);
}
} // BUG FIX
public int getTimeOrDateType() {
return m_timeOrDateType;
}
public void setTimeOrDateType(int timeOrDateType) {
m_timeOrDateType = timeOrDateType;
reinit();
}
public int getLengthStyle() {
return m_lengthStyle;
}
public void setLengthStyle(int lengthStyle) {
m_lengthStyle = lengthStyle;
reinit();
}
public Date getDate() {
return (m_lastDate);
}
// public void setDate(Date date)
// {
// m_lastDate = date;
// m_calendar.setTime(m_lastDate);
// m_textField.setText(m_format.format(m_lastDate));
// getFieldPositions();
// }
public void setDate(Date date) {
m_lastDate = date;
m_calendar.setTime(m_lastDate);
m_settingDateText = true;
m_textField.setText(m_format.format(m_lastDate));
m_settingDateText = false;
getFieldPositions();
} // BUG FIX
private int getFieldBeginIndex(int fieldNum) {
int beginIndex = -1;
for (Iterator iter = m_fieldPositions.iterator(); iter.hasNext();) {
FieldPosition fieldPos = (FieldPosition) iter.next();
if (fieldPos.getField() == fieldNum) {
beginIndex = fieldPos.getBeginIndex();
break;
}
}
return (beginIndex);
}
private FieldPosition getFieldPosition(int fieldNum) {
FieldPosition result = null;
for (Iterator iter = m_fieldPositions.iterator(); iter.hasNext();) {
FieldPosition fieldPosition = (FieldPosition) iter.next();
if (fieldPosition.getField() == fieldNum) {
result = fieldPosition;
break;
}
}
return (result);
}
private void reinit() {
setupFormat();
setDate(m_lastDate);
m_caret.setDot(0);
setCurField();
repaint();
}
protected void setupFormat() {
switch (m_timeOrDateType) {
case TIME:
m_format = DateFormat.getTimeInstance(m_lengthStyle);
break;
case DATE:
m_format = DateFormat.getDateInstance(m_lengthStyle);
break;
case DATETIME:
m_format = DateFormat.getDateTimeInstance(m_lengthStyle,
m_lengthStyle);
break;
}
}
protected class UpDownAction extends AbstractAction {
int m_direction; // +1 = up; -1 = down
public UpDownAction(int direction, String name) {
super(name);
m_direction = direction;
}
public void actionPerformed(ActionEvent evt) {
if (!this.isEnabled())
return;
boolean dateSet = true;
switch (m_curField) {
case DateFormat.AM_PM_FIELD:
m_lastDate.setTime(m_lastDate.getTime()
+ (m_direction * 12 * ONE_HOUR));
break;
case DateFormat.DATE_FIELD:
case DateFormat.DAY_OF_WEEK_FIELD:
case DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD:
case DateFormat.DAY_OF_YEAR_FIELD:
m_lastDate.setTime(m_lastDate.getTime()
+ (m_direction * ONE_DAY));
break;
case DateFormat.ERA_FIELD:
dateSet = false;
break;
case DateFormat.HOUR0_FIELD:
case DateFormat.HOUR1_FIELD:
case DateFormat.HOUR_OF_DAY0_FIELD:
case DateFormat.HOUR_OF_DAY1_FIELD:
m_lastDate.setTime(m_lastDate.getTime()
+ (m_direction * ONE_HOUR));
break;
case DateFormat.MILLISECOND_FIELD:
m_lastDate.setTime(m_lastDate.getTime() + (m_direction * 1));
break;
case DateFormat.MINUTE_FIELD:
m_lastDate.setTime(m_lastDate.getTime()
+ (m_direction * ONE_MINUTE));
break;
case DateFormat.MONTH_FIELD:
m_calendar.set(Calendar.MONTH, m_calendar.get(Calendar.MONTH)
+ m_direction);
m_lastDate = m_calendar.getTime();
break;
case DateFormat.SECOND_FIELD:
m_lastDate.setTime(m_lastDate.getTime()
+ (m_direction * ONE_SECOND));
break;
case DateFormat.WEEK_OF_MONTH_FIELD:
m_calendar.set(Calendar.WEEK_OF_MONTH, m_calendar
.get(Calendar.WEEK_OF_MONTH)
+ m_direction);
m_lastDate = m_calendar.getTime();
break;
case DateFormat.WEEK_OF_YEAR_FIELD:
m_calendar.set(Calendar.WEEK_OF_MONTH, m_calendar
.get(Calendar.WEEK_OF_MONTH)
+ m_direction);
m_lastDate = m_calendar.getTime();
break;
case DateFormat.YEAR_FIELD:
m_calendar.set(Calendar.YEAR, m_calendar.get(Calendar.YEAR)
+ m_direction);
m_lastDate = m_calendar.getTime();
break;
default:
dateSet = false;
}
if (dateSet) {
int fieldId = m_curField;
setDate(m_lastDate);
FieldPosition fieldPosition = getFieldPosition(fieldId);
m_caret.setDot(fieldPosition.getBeginIndex());
m_textField.requestFocus();
repaint();
}
}
}
protected class BackwardAction extends TextAction {
BackwardAction(String name) {
super(name);
}
public void actionPerformed(ActionEvent e) {
JTextComponent target = getTextComponent(e);
if (target != null) {
int dot = target.getCaretPosition();
if (dot > 0) {
FieldPosition position = getPrevField(dot);
if (position != null)
target.setCaretPosition(position.getBeginIndex());
else {
position = getFirstField();
if (position != null)
target.setCaretPosition(position.getBeginIndex());
}
} else
target.getToolkit().beep();
target.getCaret().setMagicCaretPosition(null);
}
}
}
protected class ForwardAction extends TextAction {
ForwardAction(String name) {
super(name);
}
public void actionPerformed(ActionEvent e) {
JTextComponent target = getTextComponent(e);
if (target != null) {
FieldPosition position = getNextField(target.getCaretPosition());
if (position != null)
target.setCaretPosition(position.getBeginIndex());
else {
position = getLastField();
if (position != null)
target.setCaretPosition(position.getBeginIndex());
}
target.getCaret().setMagicCaretPosition(null);
}
}
}
protected class BeginAction extends TextAction {
BeginAction(String name) {
super(name);
}
public void actionPerformed(ActionEvent e) {
JTextComponent target = getTextComponent(e);
if (target != null) {
FieldPosition position = getFirstField();
if (position != null)
target.setCaretPosition(position.getBeginIndex());
}
}
}
protected class EndAction extends TextAction {
EndAction(String name) {
super(name);
}
public void actionPerformed(ActionEvent e) {
JTextComponent target = getTextComponent(e);
if (target != null) {
FieldPosition position = getLastField();
if (position != null)
target.setCaretPosition(position.getBeginIndex());
}
}
}
protected void setupKeymap() {
Keymap keymap = m_textField.addKeymap("DateTimeKeymap", null);
keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
m_upAction);
keymap.addActionForKeyStroke(KeyStroke
.getKeyStroke(KeyEvent.VK_DOWN, 0), m_downAction);
keymap.addActionForKeyStroke(KeyStroke
.getKeyStroke(KeyEvent.VK_LEFT, 0), new BackwardAction(
DefaultEditorKit.backwardAction));
keymap.addActionForKeyStroke(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,
0), new ForwardAction(DefaultEditorKit.forwardAction));
keymap.addActionForKeyStroke(KeyStroke
.getKeyStroke(KeyEvent.VK_HOME, 0), new BeginAction(
DefaultEditorKit.beginAction));
keymap.addActionForKeyStroke(
KeyStroke.getKeyStroke(KeyEvent.VK_END, 0), new EndAction(
DefaultEditorKit.endAction));
m_textField.setKeymap(keymap);
}
private void getFieldPositions() {
m_fieldPositions.clear();
for (int ctr = 0; ctr < m_fieldTypes.length; ++ctr) {
int fieldId = m_fieldTypes[ctr];
FieldPosition fieldPosition = new FieldPosition(fieldId);
StringBuffer formattedField = new StringBuffer();
m_format.format(m_lastDate, formattedField, fieldPosition);
if (fieldPosition.getEndIndex() > 0)
m_fieldPositions.add(fieldPosition);
}
m_fieldPositions.trimToSize();
Collections.sort(m_fieldPositions, new Comparator() {
public int compare(Object o1, Object o2) {
return (((FieldPosition) o1).getBeginIndex() - ((FieldPosition) o2)
.getBeginIndex());
}
});
}
private FieldPosition getField(int caretLoc) {
FieldPosition fieldPosition = null;
for (Iterator iter = m_fieldPositions.iterator(); iter.hasNext();) {
FieldPosition chkFieldPosition = (FieldPosition) iter.next();
if ((chkFieldPosition.getBeginIndex() <= caretLoc)
&& (chkFieldPosition.getEndIndex() > caretLoc)) {
fieldPosition = chkFieldPosition;
break;
}
}
return (fieldPosition);
}
private FieldPosition getPrevField(int caretLoc) {
FieldPosition fieldPosition = null;
for (int ctr = m_fieldPositions.size() - 1; ctr > -1; --ctr) {
FieldPosition chkFieldPosition = (FieldPosition) m_fieldPositions
.get(ctr);
if (chkFieldPosition.getEndIndex() <= caretLoc) {
fieldPosition = chkFieldPosition;
break;
}
}
return (fieldPosition);
}
private FieldPosition getNextField(int caretLoc) {
FieldPosition fieldPosition = null;
for (Iterator iter = m_fieldPositions.iterator(); iter.hasNext();) {
FieldPosition chkFieldPosition = (FieldPosition) iter.next();
if (chkFieldPosition.getBeginIndex() > caretLoc) {
fieldPosition = chkFieldPosition;
break;
}
}
return (fieldPosition);
}
private FieldPosition getFirstField() {
FieldPosition result = null;
try {
result = ((FieldPosition) m_fieldPositions.get(0));
} catch (NoSuchElementException ex) {
}
return (result);
}
private FieldPosition getLastField() {
FieldPosition result = null;
try {
result = ((FieldPosition) m_fieldPositions.get(m_fieldPositions
.size() - 1));
} catch (NoSuchElementException ex) {
}
return (result);
}
private void setCurField() {
FieldPosition fieldPosition = getField(m_caret.getDot());
if (fieldPosition != null) {
if (m_caret.getDot() != fieldPosition.getBeginIndex())
m_caret.setDot(fieldPosition.getBeginIndex());
} else {
fieldPosition = getPrevField(m_caret.getDot());
if (fieldPosition != null)
m_caret.setDot(fieldPosition.getBeginIndex());
else {
fieldPosition = getFirstField();
if (fieldPosition != null)
m_caret.setDot(fieldPosition.getBeginIndex());
}
}
if (fieldPosition != null)
m_curField = fieldPosition.getField();
else
m_curField = -1;
}
public void setEnabled(boolean enable) {
m_textField.setEnabled(enable);
m_spinner.setEnabled(enable);
}
public boolean isEnabled() {
return (m_textField.isEnabled() && m_spinner.isEnabled());
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent evt) {
System.exit(0);
}
});
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(new EmptyBorder(5, 5, 5, 5));
frame.setContentPane(panel);
final DateTimeEditor field = new DateTimeEditor(
DateTimeEditor.DATETIME, DateFormat.FULL);
panel.add(field, "North");
JPanel buttonBox = new JPanel(new GridLayout(2, 2));
JButton showDateButton = new JButton("Show Date");
buttonBox.add(showDateButton);
final JComboBox timeDateChoice = new JComboBox();
timeDateChoice.addItem("Time");
timeDateChoice.addItem("Date");
timeDateChoice.addItem("Date/Time");
timeDateChoice.setSelectedIndex(2);
timeDateChoice.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
field.setTimeOrDateType(timeDateChoice.getSelectedIndex());
}
});
buttonBox.add(timeDateChoice);
JButton toggleButton = new JButton("Toggle Enable");
buttonBox.add(toggleButton);
showDateButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.out.println(field.getDate());
}
});
toggleButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
field.setEnabled(!field.isEnabled());
}
});
panel.add(buttonBox, "South");
final JComboBox lengthStyleChoice = new JComboBox();
lengthStyleChoice.addItem("Full");
lengthStyleChoice.addItem("Long");
lengthStyleChoice.addItem("Medium");
lengthStyleChoice.addItem("Short");
lengthStyleChoice.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
field.setLengthStyle(lengthStyleChoice.getSelectedIndex());
}
});
buttonBox.add(lengthStyleChoice);
frame.pack();
Dimension dim = frame.getToolkit().getScreenSize();
frame.setLocation(dim.width / 2 - frame.getWidth() / 2, dim.height / 2
- frame.getHeight() / 2);
frame.show();
}
}
class Spinner extends JPanel
{
private int m_orientation = SwingConstants.VERTICAL;
private BasicArrowButton m_incrementButton;
private BasicArrowButton m_decrementButton;
public Spinner() { createComponents(); }
public Spinner(int orientation)
{
m_orientation = orientation;
createComponents();
}
public void setEnabled(boolean enable)
{
m_incrementButton.setEnabled(enable);
m_decrementButton.setEnabled(enable);
}
public boolean isEnabled()
{
return (m_incrementButton.isEnabled() &&
m_decrementButton.isEnabled());
}
protected void createComponents()
{
if (m_orientation == SwingConstants.VERTICAL)
{
setLayout(new GridLayout(2, 1));
m_incrementButton = new BasicArrowButton(
SwingConstants.NORTH);
m_decrementButton = new BasicArrowButton(
SwingConstants.SOUTH);
add(m_incrementButton);
add(m_decrementButton);
}
else if (m_orientation == SwingConstants.HORIZONTAL)
{
setLayout(new GridLayout(1, 2));
m_incrementButton = new BasicArrowButton(
SwingConstants.EAST);
m_decrementButton = new BasicArrowButton(
SwingConstants.WEST);
add(m_decrementButton);
add(m_incrementButton);
}
}
public JButton getIncrementButton() {
return (m_incrementButton); }
public JButton getDecrementButton() {
return (m_decrementButton); }
public static void main(String[] args)
{
JFrame frame = new JFrame();
JPanel panel = (JPanel) frame.getContentPane();
panel.setLayout(new BorderLayout());
JTextField field = new JTextField(20);
Spinner spinner = new Spinner();
panel.add(field, "Center");
panel.add(spinner, "East");
Dimension dim = frame.getToolkit().getScreenSize();
frame.setLocation(dim.width/2 - frame.getWidth()/2,
dim.height/2 - frame.getHeight()/2);
frame.pack();
frame.show();
}
}
Related examples in the same category