| // © 2016 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html#License |
| /* |
| ******************************************************************************* |
| * 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; |
| } |