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