2 *******************************************************************************
3 * Copyright (C) 1997-2007, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
8 package com.ibm.icu.dev.demo.calendar;
10 import java.awt.Canvas;
11 import java.awt.Color;
12 import java.awt.Dimension;
13 import java.awt.FontMetrics;
14 import java.awt.Graphics;
15 import java.awt.Point;
16 import java.util.Date;
17 import java.util.Locale;
19 import com.ibm.icu.dev.demo.impl.DemoUtility;
20 import com.ibm.icu.text.DateFormatSymbols;
21 import com.ibm.icu.util.Calendar;
22 import com.ibm.icu.util.SimpleTimeZone;
24 class CalendarPanel extends Canvas {
29 private static final long serialVersionUID = 625400018027387141L;
31 public CalendarPanel( Locale locale ) {
35 public void setLocale(Locale locale) {
36 if (fDisplayLocale == null || !fDisplayLocale.equals(locale)) {
37 fDisplayLocale = locale;
40 for (int i = 0; i < fCalendar.length; i++) {
41 if (fCalendar[i] != null) {
42 fSymbols[i] = new DateFormatSymbols(fCalendar[i],
46 String lang = locale.getLanguage();
47 leftToRight = !(lang.equals("iw") || lang.equals("ar"));
53 public void setDate(Date date) {
59 public void add(int field, int delta)
61 synchronized(fCalendar) {
62 fCalendar[0].setTime(fStartOfMonth);
63 fCalendar[0].add(field, delta);
64 fStartOfMonth = fCalendar[0].getTime();
70 public void setColor(int index, Color c) {
75 public void setCalendar(int index, Calendar c) {
76 Date date = (fCalendar[index] == null) ? new Date()
77 : fCalendar[index].getTime();
80 fCalendar[index].setTime(date);
82 fSymbols[index] = new DateFormatSymbols(c, fDisplayLocale);
87 public Calendar getCalendar(int index) {
88 return fCalendar[index];
91 public Locale getDisplayLocale() {
92 return fDisplayLocale;
95 public Date firstOfMonth() {
99 private Date startOfMonth(Date dateInMonth)
101 synchronized(fCalendar) {
102 fCalendar[0].setTime(dateInMonth);
104 int era = fCalendar[0].get(Calendar.ERA);
105 int year = fCalendar[0].get(Calendar.YEAR);
106 int month = fCalendar[0].get(Calendar.MONTH);
108 fCalendar[0].clear();
109 fCalendar[0].set(Calendar.ERA, era);
110 fCalendar[0].set(Calendar.YEAR, year);
111 fCalendar[0].set(Calendar.MONTH, month);
112 fCalendar[0].set(Calendar.DATE, 1);
114 return fCalendar[0].getTime();
118 private void calculate()
121 // As a workaround for JDK 1.1.3 and below, where Calendars and time
122 // zones are a bit goofy, always set my calendar's time zone to UTC.
123 // You would think I would want to do this in the "set" function above,
124 // but if I do that, the program hangs when this class is loaded,
125 // perhaps due to some sort of static initialization ordering problem.
126 // So I do it here instead.
128 fCalendar[0].setTimeZone(new SimpleTimeZone(0, "UTC"));
130 Calendar c = (Calendar)fCalendar[0].clone(); // Temporary copy
132 fStartOfMonth = startOfMonth(fStartOfMonth);
134 // Stash away a few useful constants for this calendar and display
135 minDay = c.getMinimum(Calendar.DAY_OF_WEEK);
136 daysInWeek = c.getMaximum(Calendar.DAY_OF_WEEK) - minDay + 1;
138 firstDayOfWeek = Calendar.getInstance(fDisplayLocale).getFirstDayOfWeek();
140 // Stash away a Date for the start of this month
142 // Find the day of week of the first day in this month
143 c.setTime(fStartOfMonth);
144 firstDayInMonth = c.get(Calendar.DAY_OF_WEEK);
145 int firstWeek = c.get(Calendar.WEEK_OF_MONTH);
147 // Now find the # of days in the month
148 c.roll(Calendar.DATE, false);
149 daysInMonth = c.get(Calendar.DATE);
151 // Finally, find the end of the month, i.e. the start of the next one
152 c.roll(Calendar.DATE, true);
153 c.add(Calendar.MONTH, 1);
154 c.getTime(); // JDK 1.1.2 bug workaround
155 c.add(Calendar.SECOND, -1);
156 Date endOfMonth = c.getTime();
157 if(endOfMonth==null){
161 int lastWeek = c.get(Calendar.WEEK_OF_MONTH);
163 // Calculate the number of full or partial weeks in this month.
164 numWeeks = lastWeek - firstWeek + 1;
169 static final int XINSET = 4;
170 static final int YINSET = 2;
173 * Convert from the day number within a month (1-based)
174 * to the cell coordinates on the calendar (0-based)
176 private void dateToCell(int date, Point pos)
178 int cell = (date + firstDayInMonth - firstDayOfWeek - minDay);
179 if (firstDayInMonth < firstDayOfWeek) {
183 pos.x = cell % daysInWeek;
184 pos.y = cell / daysInWeek;
186 //private Point dateToCell(int date) {
187 // Point p = new Point(0,0);
188 // dateToCell(date, p);
192 public void paint(Graphics g) {
198 Point cellPos = new Point(0,0); // Temporary variable
199 Dimension d = this.getSize();
201 g.setColor(Color.lightGray);
202 g.fillRect(0,0,d.width,d.height);
204 // Draw the day names at the top
205 g.setColor(Color.black);
206 g.setFont(DemoUtility.labelFont);
207 FontMetrics fm = g.getFontMetrics();
208 int labelHeight = fm.getHeight() + YINSET * 2;
210 int v = fm.getAscent() + YINSET;
211 for (int i = 0; i < daysInWeek; i++) {
212 int dayNum = (i + minDay + firstDayOfWeek - 2) % daysInWeek + 1;
213 String dayName = fSymbols[0].getWeekdays()[dayNum];
218 h = d.width*(i + 0.5) / daysInWeek;
220 h = d.width*(daysInWeek - i - 0.5) / daysInWeek;
222 h -= fm.stringWidth(dayName) / 2;
224 g.drawString(dayName, (int)h, v);
227 double cellHeight = (d.height - labelHeight - 1) / numWeeks;
228 double cellWidth = (double)(d.width - 1) / daysInWeek;
230 // Draw a white background in the part of the calendar
231 // that displays this month.
232 // First figure out how much of the first week should be shaded.
234 g.setColor(Color.white);
235 dateToCell(1, cellPos);
236 int width = (int)(cellPos.x*cellWidth); // Width of unshaded area
239 g.fillRect((int)(width), labelHeight ,
240 d.width - width, (int)cellHeight);
242 g.fillRect(0, labelHeight ,
243 d.width - width, (int)cellHeight);
246 // All of the intermediate weeks get shaded completely
247 g.fillRect(0, (int)(labelHeight + cellHeight),
248 d.width, (int)(cellHeight * (numWeeks - 2)));
250 // Now figure out the last week.
251 dateToCell(daysInMonth, cellPos);
252 width = (int)((cellPos.x+1)*cellWidth); // Width of shaded area
255 g.fillRect(0, (int)(labelHeight + (numWeeks-1) * cellHeight),
256 width, (int)cellHeight);
258 g.fillRect(d.width - width, (int)(labelHeight + (numWeeks-1) * cellHeight),
259 width, (int)cellHeight);
263 // Draw the X/Y grid lines
264 g.setColor(Color.black);
265 for (int i = 0; i <= numWeeks; i++) {
266 int y = (int)(labelHeight + i * cellHeight);
267 g.drawLine(0, y, d.width - 1, y);
269 for (int i = 0; i <= daysInWeek; i++) {
270 int x = (int)(i * cellWidth);
271 g.drawLine(x, labelHeight, x, d.height - 1);
274 // Now loop through all of the days in the month, figure out where
275 // they go in the grid, and draw the day # for each one
277 // Figure out the date of the first cell in the calendar display
278 int cell = (1 + firstDayInMonth - firstDayOfWeek - minDay);
279 if (firstDayInMonth < firstDayOfWeek) {
283 Calendar c = (Calendar)fCalendar[0].clone();
284 c.setTime(fStartOfMonth);
285 c.add(Calendar.DATE, -cell);
287 StringBuffer buffer = new StringBuffer();
289 for (int row = 0; row < numWeeks; row++) {
290 for (int col = 0; col < daysInWeek; col++) {
292 g.setFont(DemoUtility.numberFont);
293 g.setColor(Color.black);
294 fm = g.getFontMetrics();
298 cellx = (int)((col) * cellWidth);
300 cellx = (int)((daysInWeek - col - 1) * cellWidth);
303 int celly = (int)(row * cellHeight + labelHeight);
305 for (int i = 0; i < 2; i++) {
306 fCalendar[i].setTime(c.getTime());
308 int date = fCalendar[i].get(Calendar.DATE);
311 String dayNum = buffer.toString();
316 x = cellx + (int)cellWidth - XINSET - fm.stringWidth(dayNum);
320 int y = celly + + fm.getAscent() + YINSET + i * fm.getHeight();
322 if (fColor[i] != null) {
323 g.setColor(fColor[i]);
325 g.drawString(dayNum, x, y);
327 if (date == 1 || row == 0 && col == 0) {
328 g.setFont(DemoUtility.numberFont);
329 String month = fSymbols[i].getMonths()[
330 fCalendar[i].get(Calendar.MONTH)];
335 x = cellx + (int)cellWidth - XINSET - fm.stringWidth(month);
337 g.drawString(month, x, y);
341 c.add(Calendar.DATE, 1);
346 // Important state variables
347 private Calendar[] fCalendar = new Calendar[4];
348 private Color[] fColor = new Color[4];
350 private Locale fDisplayLocale;
351 private DateFormatSymbols[] fSymbols = new DateFormatSymbols[4];
353 private Date fStartOfMonth = new Date(); // 00:00:00 on first day of month
355 // Cached calculations to make drawing faster.
356 private transient int minDay; // Minimum legal day #
357 private transient int daysInWeek; // # of days in a week
358 private transient int firstDayOfWeek; // First day to display in week
359 private transient int numWeeks; // # full or partial weeks in month
360 private transient int daysInMonth; // # days in this month
361 private transient int firstDayInMonth; // Day of week of first day in month
362 private transient boolean leftToRight;
364 private transient boolean dirty = true;