blob: 8ea94d3f9fad1046fc5f1ad7db0d125d3e972ce7 [file] [log] [blame]
/*
*******************************************************************************
* Copyright (C) 1997-2007, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.dev.demo.calendar;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Date;
import java.util.Locale;
import com.ibm.icu.dev.demo.impl.DemoUtility;
import com.ibm.icu.text.DateFormatSymbols;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.SimpleTimeZone;
class CalendarPanel extends Canvas {
/**
* For serialization
*/
private static final long serialVersionUID = 625400018027387141L;
public CalendarPanel( Locale locale ) {
setLocale(locale);
}
public void setLocale(Locale locale) {
if (fDisplayLocale == null || !fDisplayLocale.equals(locale)) {
fDisplayLocale = locale;
dirty = true;
for (int i = 0; i < fCalendar.length; i++) {
if (fCalendar[i] != null) {
fSymbols[i] = new DateFormatSymbols(fCalendar[i],
fDisplayLocale);
}
}
String lang = locale.getLanguage();
leftToRight = !(lang.equals("iw") || lang.equals("ar"));
repaint();
}
}
public void setDate(Date date) {
fStartOfMonth = date;
dirty = true;
repaint();
}
public void add(int field, int delta)
{
synchronized(fCalendar) {
fCalendar[0].setTime(fStartOfMonth);
fCalendar[0].add(field, delta);
fStartOfMonth = fCalendar[0].getTime();
}
dirty = true;
repaint();
}
public void setColor(int index, Color c) {
fColor[index] = c;
repaint();
}
public void setCalendar(int index, Calendar c) {
Date date = (fCalendar[index] == null) ? new Date()
: fCalendar[index].getTime();
fCalendar[index] = c;
fCalendar[index].setTime(date);
fSymbols[index] = new DateFormatSymbols(c, fDisplayLocale);
dirty = true;
repaint();
}
public Calendar getCalendar(int index) {
return fCalendar[index];
}
public Locale getDisplayLocale() {
return fDisplayLocale;
}
public Date firstOfMonth() {
return fStartOfMonth;
}
private Date startOfMonth(Date dateInMonth)
{
synchronized(fCalendar) {
fCalendar[0].setTime(dateInMonth);
int era = fCalendar[0].get(Calendar.ERA);
int year = fCalendar[0].get(Calendar.YEAR);
int month = fCalendar[0].get(Calendar.MONTH);
fCalendar[0].clear();
fCalendar[0].set(Calendar.ERA, era);
fCalendar[0].set(Calendar.YEAR, year);
fCalendar[0].set(Calendar.MONTH, month);
fCalendar[0].set(Calendar.DATE, 1);
return fCalendar[0].getTime();
}
}
private void calculate()
{
//
// As a workaround for JDK 1.1.3 and below, where Calendars and time
// zones are a bit goofy, always set my calendar's time zone to UTC.
// You would think I would want to do this in the "set" function above,
// but if I do that, the program hangs when this class is loaded,
// perhaps due to some sort of static initialization ordering problem.
// So I do it here instead.
//
fCalendar[0].setTimeZone(new SimpleTimeZone(0, "UTC"));
Calendar c = (Calendar)fCalendar[0].clone(); // Temporary copy
fStartOfMonth = startOfMonth(fStartOfMonth);
// Stash away a few useful constants for this calendar and display
minDay = c.getMinimum(Calendar.DAY_OF_WEEK);
daysInWeek = c.getMaximum(Calendar.DAY_OF_WEEK) - minDay + 1;
firstDayOfWeek = Calendar.getInstance(fDisplayLocale).getFirstDayOfWeek();
// Stash away a Date for the start of this month
// Find the day of week of the first day in this month
c.setTime(fStartOfMonth);
firstDayInMonth = c.get(Calendar.DAY_OF_WEEK);
int firstWeek = c.get(Calendar.WEEK_OF_MONTH);
// Now find the # of days in the month
c.roll(Calendar.DATE, false);
daysInMonth = c.get(Calendar.DATE);
// Finally, find the end of the month, i.e. the start of the next one
c.roll(Calendar.DATE, true);
c.add(Calendar.MONTH, 1);
c.getTime(); // JDK 1.1.2 bug workaround
c.add(Calendar.SECOND, -1);
Date endOfMonth = c.getTime();
if(endOfMonth==null){
//do nothing
}
endOfMonth = null;
int lastWeek = c.get(Calendar.WEEK_OF_MONTH);
// Calculate the number of full or partial weeks in this month.
numWeeks = lastWeek - firstWeek + 1;
dirty = false;
}
static final int XINSET = 4;
static final int YINSET = 2;
/*
* Convert from the day number within a month (1-based)
* to the cell coordinates on the calendar (0-based)
*/
private void dateToCell(int date, Point pos)
{
int cell = (date + firstDayInMonth - firstDayOfWeek - minDay);
if (firstDayInMonth < firstDayOfWeek) {
cell += daysInWeek;
}
pos.x = cell % daysInWeek;
pos.y = cell / daysInWeek;
}
//private Point dateToCell(int date) {
// Point p = new Point(0,0);
// dateToCell(date, p);
// return p;
//}
public void paint(Graphics g) {
if (dirty) {
calculate();
}
Point cellPos = new Point(0,0); // Temporary variable
Dimension d = this.getSize();
g.setColor(Color.lightGray);
g.fillRect(0,0,d.width,d.height);
// Draw the day names at the top
g.setColor(Color.black);
g.setFont(DemoUtility.labelFont);
FontMetrics fm = g.getFontMetrics();
int labelHeight = fm.getHeight() + YINSET * 2;
int v = fm.getAscent() + YINSET;
for (int i = 0; i < daysInWeek; i++) {
int dayNum = (i + minDay + firstDayOfWeek - 2) % daysInWeek + 1;
String dayName = fSymbols[0].getWeekdays()[dayNum];
double h;
if (leftToRight) {
h = d.width*(i + 0.5) / daysInWeek;
} else {
h = d.width*(daysInWeek - i - 0.5) / daysInWeek;
}
h -= fm.stringWidth(dayName) / 2;
g.drawString(dayName, (int)h, v);
}
double cellHeight = (d.height - labelHeight - 1) / numWeeks;
double cellWidth = (double)(d.width - 1) / daysInWeek;
// Draw a white background in the part of the calendar
// that displays this month.
// First figure out how much of the first week should be shaded.
{
g.setColor(Color.white);
dateToCell(1, cellPos);
int width = (int)(cellPos.x*cellWidth); // Width of unshaded area
if (leftToRight) {
g.fillRect((int)(width), labelHeight ,
d.width - width, (int)cellHeight);
} else {
g.fillRect(0, labelHeight ,
d.width - width, (int)cellHeight);
}
// All of the intermediate weeks get shaded completely
g.fillRect(0, (int)(labelHeight + cellHeight),
d.width, (int)(cellHeight * (numWeeks - 2)));
// Now figure out the last week.
dateToCell(daysInMonth, cellPos);
width = (int)((cellPos.x+1)*cellWidth); // Width of shaded area
if (leftToRight) {
g.fillRect(0, (int)(labelHeight + (numWeeks-1) * cellHeight),
width, (int)cellHeight);
} else {
g.fillRect(d.width - width, (int)(labelHeight + (numWeeks-1) * cellHeight),
width, (int)cellHeight);
}
}
// Draw the X/Y grid lines
g.setColor(Color.black);
for (int i = 0; i <= numWeeks; i++) {
int y = (int)(labelHeight + i * cellHeight);
g.drawLine(0, y, d.width - 1, y);
}
for (int i = 0; i <= daysInWeek; i++) {
int x = (int)(i * cellWidth);
g.drawLine(x, labelHeight, x, d.height - 1);
}
// Now loop through all of the days in the month, figure out where
// they go in the grid, and draw the day # for each one
// Figure out the date of the first cell in the calendar display
int cell = (1 + firstDayInMonth - firstDayOfWeek - minDay);
if (firstDayInMonth < firstDayOfWeek) {
cell += daysInWeek;
}
Calendar c = (Calendar)fCalendar[0].clone();
c.setTime(fStartOfMonth);
c.add(Calendar.DATE, -cell);
StringBuffer buffer = new StringBuffer();
for (int row = 0; row < numWeeks; row++) {
for (int col = 0; col < daysInWeek; col++) {
g.setFont(DemoUtility.numberFont);
g.setColor(Color.black);
fm = g.getFontMetrics();
int cellx;
if (leftToRight) {
cellx = (int)((col) * cellWidth);
} else {
cellx = (int)((daysInWeek - col - 1) * cellWidth);
}
int celly = (int)(row * cellHeight + labelHeight);
for (int i = 0; i < 2; i++) {
fCalendar[i].setTime(c.getTime());
int date = fCalendar[i].get(Calendar.DATE);
buffer.setLength(0);
buffer.append(date);
String dayNum = buffer.toString();
int x;
if (leftToRight) {
x = cellx + (int)cellWidth - XINSET - fm.stringWidth(dayNum);
} else {
x = cellx + XINSET;
}
int y = celly + + fm.getAscent() + YINSET + i * fm.getHeight();
if (fColor[i] != null) {
g.setColor(fColor[i]);
}
g.drawString(dayNum, x, y);
if (date == 1 || row == 0 && col == 0) {
g.setFont(DemoUtility.numberFont);
String month = fSymbols[i].getMonths()[
fCalendar[i].get(Calendar.MONTH)];
if (leftToRight) {
x = cellx + XINSET;
} else {
x = cellx + (int)cellWidth - XINSET - fm.stringWidth(month);
}
g.drawString(month, x, y);
}
}
c.add(Calendar.DATE, 1);
}
}
}
// Important state variables
private Calendar[] fCalendar = new Calendar[4];
private Color[] fColor = new Color[4];
private Locale fDisplayLocale;
private DateFormatSymbols[] fSymbols = new DateFormatSymbols[4];
private Date fStartOfMonth = new Date(); // 00:00:00 on first day of month
// Cached calculations to make drawing faster.
private transient int minDay; // Minimum legal day #
private transient int daysInWeek; // # of days in a week
private transient int firstDayOfWeek; // First day to display in week
private transient int numWeeks; // # full or partial weeks in month
private transient int daysInMonth; // # days in this month
private transient int firstDayInMonth; // Day of week of first day in month
private transient boolean leftToRight;
private transient boolean dirty = true;
}