package jas.util; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.Insets; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DecimalFormat; import java.text.Format; import java.util.Calendar; import java.util.Date; import java.util.Enumeration; import java.util.Vector; import javax.swing.AbstractListModel; import javax.swing.ComboBoxModel; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.plaf.basic.BasicComboBoxRenderer; interface DateListener { void dateChanged(); } class DateModel { DateModel(Calendar date) { this.date = date; } DateModel(Date date) { this.date = Calendar.getInstance(); this.date.setTime(date); } synchronized void addDateListener(DateListener l) { listeners.addElement(l); } synchronized void removeDateListener(DateListener l) { listeners.removeElement(l); } synchronized void fireDateChanged() { Enumeration e = listeners.elements(); while (e.hasMoreElements()) { DateListener l = (DateListener) e.nextElement(); l.dateChanged(); } } void set(int field,int value) { date.set(field,value); fireDateChanged(); } void roll(int field, boolean up) { date.roll(field,up); fireDateChanged(); } void add(int field, int delta) { date.add(field,delta); fireDateChanged(); } int get(int field) { return date.get(field); } Calendar getCalendar() { return date; } int getDaysInMonth() { return( date.getActualMaximum( Calendar.DAY_OF_MONTH ) ); } Date getTime() { return date.getTime(); } private Vector listeners = new Vector(); private Calendar date; } class AbstractDateComboModel extends AbstractListModel implements ComboBoxModel, DateListener { AbstractDateComboModel(DateModel model, int field) { this.model = model; this.field = field; model.addDateListener(this); } public void dateChanged() { fireContentsChanged(this,0,100); } public Object getElementAt(int index) { return element[index]; } public int getSize() { return model.getCalendar().getMaximum(field)+1; } public Object getSelectedItem() { int i = model.get(field); return element[i]; } public void setSelectedItem(Object value) { int i = ((Integer) value).intValue(); model.set(field,i); } DateModel model; int field; static Integer[] element; static { element = new Integer[100]; for (int i=0; i<element.length; i++) element[i] = new Integer(i); } } class DateMonthModel extends AbstractDateComboModel { DateMonthModel(DateModel model) { super(model,Calendar.MONTH); } } class MonthCellRenderer extends BasicComboBoxRenderer { public Component getListCellRendererComponent (JList list,Object value,int index,boolean isSelected,boolean cellHasFocus) { int i = ((Integer) value).intValue(); return super.getListCellRendererComponent (list,month[i],index,isSelected,cellHasFocus); } private static final String[] month = { "January" , "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}; } class DateDayModel extends AbstractDateComboModel { DateDayModel(DateModel model) { super(model,Calendar.DAY_OF_MONTH); } public int getSize() { return model.getDaysInMonth(); } public Object getElementAt(int index) { return element[index+1]; } } class DateHourModel extends AbstractDateComboModel { DateHourModel(DateModel model) { super(model,Calendar.HOUR_OF_DAY); } public int getSize() { return 12; } public Object getSelectedItem() { int i = model.get(field); if (i >= 12) i -= 12; return element[i]; } public void setSelectedItem(Object value) { int ampm = model.get(Calendar.AM_PM); int i = ((Integer) value).intValue(); if (ampm > 0) i += 12; model.set(field,i); } } class DateMinuteModel extends AbstractDateComboModel { DateMinuteModel(DateModel model) { super(model,Calendar.MINUTE); } } class DateSecondModel extends AbstractDateComboModel { DateSecondModel(DateModel model) { super(model,Calendar.SECOND); } } class DateAMPMModel extends AbstractDateComboModel { DateAMPMModel(DateModel model) { super(model,Calendar.AM_PM); } public void setSelectedItem(Object value) { int hour = model.get(Calendar.HOUR_OF_DAY); int i = ((Integer) value).intValue(); if (i == 0 && hour >= 12) hour -= 12; if (i == 1 && hour < 12) hour += 12; model.set(Calendar.HOUR_OF_DAY,hour); } } class MinuteCellRenderer extends BasicComboBoxRenderer { public Component getListCellRendererComponent (JList list,Object value,int index,boolean isSelected,boolean cellHasFocus) { String s =f.format(value); return super.getListCellRendererComponent (list,s,index,isSelected,cellHasFocus); } private static Format f = new DecimalFormat("00"); } class HourCellRenderer extends BasicComboBoxRenderer { HourCellRenderer() { setHorizontalAlignment(SwingConstants.RIGHT); } public Component getListCellRendererComponent (JList list,Object value,int index,boolean isSelected,boolean cellHasFocus) { int i = ((Integer) value).intValue(); if (i==0) i = 12; String s = String.valueOf(i); return super.getListCellRendererComponent (list,s,index,isSelected,cellHasFocus); } } class AMPMCellRenderer extends BasicComboBoxRenderer { public Component getListCellRendererComponent (JList list,Object value,int index,boolean isSelected,boolean cellHasFocus) { int i = ((Integer) value).intValue(); return super.getListCellRendererComponent (list,ampm[i],index,isSelected,cellHasFocus); } private static String[] ampm = { "AM" , "PM" }; } class DateYearModel extends AbstractDateComboModel { DateYearModel(DateModel model,int offset) { super(model,Calendar.YEAR); this.offset = offset; } public int getSize() { return element.length; } public Object getSelectedItem() { int i = model.get(field); return element[i-offset]; } public void setSelectedItem(Object value) { int i = ((Integer) value).intValue(); model.set(field,i+offset); } private int offset; } class YearCellRenderer extends BasicComboBoxRenderer { YearCellRenderer(int offset) { this.offset = offset; } public Component getListCellRendererComponent (JList list,Object value,int index,boolean isSelected,boolean cellHasFocus) { int i = ((Integer) value).intValue(); return super.getListCellRendererComponent (list,String.valueOf(i+offset),index,isSelected,cellHasFocus); } private static int offset; } class CalendarHeader extends JComponent { CalendarHeader(DateModel model) { this.model = model; int offset = 1950; setLayout(new FlowLayout()); JComboBox day = new JComboBox(new DateDayModel(model)); JComboBox month = new JComboBox(new DateMonthModel(model)); JComboBox year = new JComboBox(new DateYearModel(model,offset)); month.setRenderer(new MonthCellRenderer()); year.setRenderer(new YearCellRenderer(offset)); JButton down = new JButton("<"); JButton up = new JButton(">"); down.addActionListener(new RollListener(-1)); up.addActionListener(new RollListener(+1)); add(down); add(day); add(month); add(year); add(up); } private DateModel model; private class RollListener implements ActionListener { RollListener(int delta) { this.delta = delta; } public void actionPerformed(ActionEvent evt) { model.add(Calendar.MONTH,delta); } private int delta; } } class TimeHeader extends JComponent { TimeHeader(DateModel model) { this.model = model; setLayout(new FlowLayout()); JComboBox hour = new JComboBox(new DateHourModel(model)); JComboBox minute = new JComboBox(new DateMinuteModel(model)); JComboBox second = new JComboBox(new DateSecondModel(model)); JComboBox ampm = new JComboBox(new DateAMPMModel(model)); hour.setRenderer(new HourCellRenderer()); minute.setRenderer(new MinuteCellRenderer()); second.setRenderer(new MinuteCellRenderer()); ampm.setRenderer(new AMPMCellRenderer()); add(hour); add(minute); add(second); add(ampm); } private DateModel model; } class CalendarPane extends JComponent implements DateListener, ActionListener { CalendarPane(DateModel model) { this.model = model; model.addDateListener(this); setLayout(null); Insets insets = new Insets(1,1,1,1); days = new JButton[31]; for (int i=0; i<31; i++) { days[i] = new JButton(String.valueOf(i+1)); days[i].addActionListener(this); //days[i].setMargin(insets); add(days[i]); } fg = days[30].getForeground(); bg = days[30].getBackground(); buttonSize = days[30].getPreferredSize(); panelSize = new Dimension(buttonSize.width*7,buttonSize.height*7); hidden = new Point(buttonSize.width*10,buttonSize.height*10); for (int i=0; i<31; i++) days[i].setSize(buttonSize); for (int i=0; i<7; i++) { JLabel l = new JLabel(labels[i],SwingConstants.CENTER); add(l); l.setLocation(i*buttonSize.width,0); l.setSize(buttonSize); } layoutCalendar(); } public Dimension getPreferredSize() { return panelSize; } public void actionPerformed(ActionEvent e) { String s = e.getActionCommand(); int day = Integer.valueOf(s).intValue(); model.set(Calendar.DAY_OF_MONTH,day); } public void dateChanged() { layoutCalendar(); } void layoutCalendar() { Calendar selected = model.getCalendar(); int day = selected.get(Calendar.DAY_OF_MONTH)-1; if (selectedButton != days[day]) { if (selectedButton != null) { selectedButton.setForeground(fg); selectedButton.setBackground(bg); selectedButton.repaint(); } selectedButton = days[day]; selectedButton.setForeground(UIManager.getColor("textHighlightText")); selectedButton.setBackground(UIManager.getColor("textHighlight")); selectedButton.repaint(); } Calendar date = (Calendar) selected.clone(); date.set(Calendar.DAY_OF_MONTH,1); int i=0; for (; i<model.getDaysInMonth(); i++) { int x = (date.get(Calendar.DAY_OF_WEEK)-1) * buttonSize.width; int y = (date.get(Calendar.WEEK_OF_MONTH)) * buttonSize.height; days[i].setLocation(x,y); date.add(Calendar.DATE,1); } for (; i<31; i++) days[i].setLocation(hidden); } private JButton selectedButton; private Color fg; private Color bg; private Dimension buttonSize; private Dimension panelSize; private Point hidden; private DateModel model; private JButton[] days; private final static String[] labels = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; } class CalendarTest { public static void main(String[] argv) { JFrame f = new JFrame("test"); DateModel model = new DateModel(Calendar.getInstance()); f.getContentPane().add(new CalendarHeader(model),BorderLayout.NORTH); f.getContentPane().add(new CalendarPane(model),BorderLayout.CENTER); f.getContentPane().add(new TimeHeader(model),BorderLayout.SOUTH); f.pack(); f.show(); } } public class DateChooser extends JASDialog { public DateChooser(Frame f, Date d) { super(f,"Choose Date..."); model = new DateModel(d); getContentPane().add(new CalendarHeader(model),BorderLayout.NORTH); getContentPane().add(new CalendarPane(model),BorderLayout.CENTER); getContentPane().add(new TimeHeader(model),BorderLayout.SOUTH); pack(); } public Date getDate() { return model.getTime(); } private DateModel model; }