1 /* 2 ******************************************************************************* 3 * Copyright (C) 1997-2007, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7 8 package com.ibm.icu.dev.demo.calendar; 9 10 import java.awt.BorderLayout; 11 import java.awt.Button; 12 import java.awt.Choice; 13 import java.awt.Color; 14 import java.awt.Component; 15 import java.awt.Container; 16 import java.awt.Dimension; 17 import java.awt.FlowLayout; 18 import java.awt.Font; 19 import java.awt.FontMetrics; 20 import java.awt.Frame; 21 import java.awt.Graphics; 22 import java.awt.GridBagConstraints; 23 import java.awt.GridBagLayout; 24 import java.awt.Label; 25 import java.awt.Panel; 26 import java.awt.Rectangle; 27 import java.awt.event.ActionEvent; 28 import java.awt.event.ActionListener; 29 import java.awt.event.ItemEvent; 30 import java.awt.event.ItemListener; 31 import java.awt.event.WindowAdapter; 32 import java.awt.event.WindowEvent; 33 import java.util.Date; 34 import java.util.Locale; 35 36 import com.ibm.icu.dev.demo.impl.DemoApplet; 37 import com.ibm.icu.dev.demo.impl.DemoUtility; 38 import com.ibm.icu.text.DateFormat; 39 import com.ibm.icu.util.BuddhistCalendar; 40 import com.ibm.icu.util.Calendar; 41 import com.ibm.icu.util.GregorianCalendar; 42 import com.ibm.icu.util.HebrewCalendar; 43 import com.ibm.icu.util.IslamicCalendar; 44 import com.ibm.icu.util.JapaneseCalendar; 45 import com.ibm.icu.util.SimpleTimeZone; 46 47 /** 48 * A Frame is a top-level window with a title. The default layout for a frame 49 * is BorderLayout. The CalendarFrame class defines the window layout of 50 * CalendarDemo. 51 */ 52 class CalendarFrame extends Frame 53 { 54 /** 55 * For serialization 56 */ 57 private static final long serialVersionUID = -4289697663503820619L; 58 59 private static final boolean DEBUG = false; 60 61 private DemoApplet applet; 62 63 /** 64 * Constructs a new CalendarFrame that is initially invisible. 65 */ CalendarFrame(DemoApplet myApplet)66 public CalendarFrame(DemoApplet myApplet) 67 { 68 super("Calendar Demo"); 69 this.applet = myApplet; 70 init(); 71 72 // When the window is closed, we want to shut down the applet or application 73 addWindowListener( 74 new WindowAdapter() { 75 public void windowClosing(WindowEvent e) { 76 setVisible(false); 77 dispose(); 78 79 if (applet != null) { 80 applet.demoClosed(); 81 } else System.exit(0); 82 } 83 } ); 84 } 85 86 private Choice displayMenu; 87 private Locale[] locales = DemoUtility.getG7Locales(); 88 89 private Calendar calendars[] = new Calendar[2]; 90 private Choice calMenu[] = new Choice[2]; 91 private ColoredLabel monthLabel[] = new ColoredLabel[2]; 92 private DateFormat monthFormat[] = new DateFormat[2]; 93 94 private Button prevYear; 95 private Button prevMonth; 96 private Button gotoToday; 97 private Button nextMonth; 98 private Button nextYear; 99 private CalendarPanel calendarPanel; 100 add(Container container, Component component, GridBagLayout g, GridBagConstraints c, int gridwidth, int weightx)101 private static void add(Container container, Component component, 102 GridBagLayout g, GridBagConstraints c, 103 int gridwidth, int weightx) 104 { 105 c.gridwidth = gridwidth; 106 c.weightx = weightx; 107 g.setConstraints(component, c); 108 container.add(component); 109 } 110 111 /** 112 * Initializes the applet. You never need to call this directly, it 113 * is called automatically by the system once the applet is created. 114 */ init()115 public void init() { 116 setBackground(DemoUtility.bgColor); 117 setLayout(new BorderLayout(10,10)); 118 119 Panel topPanel = new Panel(); 120 GridBagLayout g = new GridBagLayout(); 121 topPanel.setLayout(g); 122 GridBagConstraints c = new GridBagConstraints(); 123 c.fill = GridBagConstraints.HORIZONTAL; 124 125 // Build the two menus for selecting which calendar is displayed, 126 // plus the month/year label for each calendar 127 for (int i = 0; i < 2; i++) { 128 calMenu[i] = new Choice(); 129 for (int j = 0; j < CALENDARS.length; j++) { 130 calMenu[i].addItem(CALENDARS[j].name); 131 } 132 calMenu[i].setBackground(DemoUtility.choiceColor); 133 calMenu[i].select(i); 134 calMenu[i].addItemListener(new CalMenuListener()); 135 136 // Label for the current month name 137 monthLabel[i] = new ColoredLabel("", COLORS[i]); 138 monthLabel[i].setFont(DemoUtility.titleFont); 139 140 // And the default calendar to use for this slot 141 calendars[i] = CALENDARS[i].calendar; 142 143 add(topPanel, calMenu[i], g, c, 5, 0); 144 add(topPanel, monthLabel[i], g, c, GridBagConstraints.REMAINDER, 1); 145 } 146 147 // Now add the next/previous year/month buttons: 148 prevYear = new Button("<<"); 149 prevYear.addActionListener(new AddAction(Calendar.YEAR, -1)); 150 151 prevMonth = new Button("<"); 152 prevMonth.addActionListener(new AddAction(Calendar.MONTH, -1)); 153 154 gotoToday = new Button("Today"); 155 gotoToday.addActionListener( new ActionListener() 156 { 157 public void actionPerformed(ActionEvent e) { 158 calendarPanel.setDate( new Date() ); 159 updateMonthName(); 160 } 161 } ); 162 163 nextMonth = new Button(">"); 164 nextMonth.addActionListener(new AddAction(Calendar.MONTH, 1)); 165 166 nextYear = new Button(">>"); 167 nextYear.addActionListener(new AddAction(Calendar.YEAR, 1)); 168 169 c.fill = GridBagConstraints.NONE; 170 add(topPanel, prevYear, g, c, 1, 0); 171 add(topPanel, prevMonth, g, c, 1, 0); 172 add(topPanel, gotoToday, g, c, 1, 0); 173 add(topPanel, nextMonth, g, c, 1, 0); 174 add(topPanel, nextYear, g, c, 1, 0); 175 176 // Now add the menu for selecting the display language 177 Panel displayPanel = new Panel(); 178 { 179 displayMenu = new Choice(); 180 Locale defaultLocale = Locale.getDefault(); 181 int bestMatch = -1, thisMatch = -1; 182 int selectMe = 0; 183 184 for (int i = 0; i < locales.length; i++) { 185 if (i > 0 && 186 locales[i].getLanguage().equals(locales[i-1].getLanguage()) || 187 i < locales.length - 1 && 188 locales[i].getLanguage().equals(locales[i+1].getLanguage())) 189 { 190 displayMenu.addItem( locales[i].getDisplayName() ); 191 } else { 192 displayMenu.addItem( locales[i].getDisplayLanguage()); 193 } 194 195 thisMatch = DemoUtility.compareLocales(locales[i], defaultLocale); 196 197 if (thisMatch >= bestMatch) { 198 bestMatch = thisMatch; 199 selectMe = i; 200 } 201 } 202 203 displayMenu.setBackground(DemoUtility.choiceColor); 204 displayMenu.select(selectMe); 205 206 displayMenu.addItemListener( new ItemListener() 207 { 208 public void itemStateChanged(ItemEvent e) { 209 Locale loc = locales[displayMenu.getSelectedIndex()]; 210 calendarPanel.setLocale( loc ); 211 monthFormat[0] = monthFormat[1] = null; 212 updateMonthName(); 213 repaint(); 214 } 215 } ); 216 217 Label l1 = new Label("Display Language:", Label.RIGHT); 218 l1.setFont(DemoUtility.labelFont); 219 220 displayPanel.setLayout(new FlowLayout()); 221 displayPanel.add(l1); 222 displayPanel.add(displayMenu); 223 224 } 225 c.fill = GridBagConstraints.NONE; 226 c.anchor = GridBagConstraints.EAST; 227 228 add(topPanel, displayPanel, g, c, GridBagConstraints.REMAINDER, 0); 229 230 // The title, buttons, etc. go in a panel at the top of the window 231 add("North", topPanel); 232 233 // The copyright notice goes at the bottom of the window 234 Label copyright = new Label(DemoUtility.copyright1, Label.LEFT); 235 copyright.setFont(DemoUtility.creditFont); 236 add("South", copyright); 237 238 // Now create the big calendar panel and stick it in the middle 239 calendarPanel = new CalendarPanel( locales[displayMenu.getSelectedIndex()] ); 240 add("Center", calendarPanel); 241 242 for (int i = 0; i < 2; i++) { 243 calendarPanel.setCalendar(i, calendars[i]); 244 calendarPanel.setColor(i, COLORS[i]); 245 } 246 247 updateMonthName(); 248 } 249 250 updateMonthName()251 private void updateMonthName() 252 { 253 for (int i = 0; i < 2; i++) { 254 try { 255 if (monthFormat[i] == null) { // TODO: optimize 256 DateFormat f = DateFormat.getDateTimeInstance( 257 calendars[i], DateFormat.MEDIUM, -1, 258 locales[displayMenu.getSelectedIndex()]); 259 if (f instanceof com.ibm.icu.text.SimpleDateFormat) { 260 com.ibm.icu.text.SimpleDateFormat f1 = (com.ibm.icu.text.SimpleDateFormat) f; 261 f1.applyPattern("MMMM, yyyy G"); 262 f1.setTimeZone(new SimpleTimeZone(0, "UTC")); 263 } 264 monthFormat[i] = f; 265 } 266 } catch (ClassCastException e) { 267 //hey {lw} - there's something wrong in this routine that cuases exceptions. 268 System.out.println(e); 269 } 270 271 monthLabel[i].setText( monthFormat[i].format( calendarPanel.firstOfMonth() )); 272 } 273 } 274 275 /** 276 * CalMenuListener responds to events in the two popup menus that select 277 * the calendar systems to be used in the display. It figures out which 278 * of the two menus the event occurred in and updates the corresponding 279 * element of the calendars[] array to match the new selection. 280 */ 281 private class CalMenuListener implements ItemListener 282 { itemStateChanged(ItemEvent e)283 public void itemStateChanged(ItemEvent e) 284 { 285 for (int i = 0; i < calMenu.length; i++) 286 { 287 if (e.getItemSelectable() == calMenu[i]) 288 { 289 // We found the menu that the event happened in. 290 // Figure out which new calendar they selected. 291 Calendar newCal = CALENDARS[ calMenu[i].getSelectedIndex() ].calendar; 292 293 if (newCal != calendars[i]) 294 { 295 // If any of the other menus are set to the same new calendar 296 // we're about to use for this menu, set them to the current 297 // calendar from *this* menu so we won't have two the same 298 for (int j = 0; j < calendars.length; j++) { 299 if (j != i && calendars[j] == newCal) { 300 calendars[j] = calendars[i]; 301 calendarPanel.setCalendar(j, calendars[j]); 302 monthFormat[j] = null; 303 304 for (int k = 0; k < CALENDARS.length; k++) { 305 if (calendars[j] == CALENDARS[k].calendar) { 306 calMenu[j].select(k); 307 break; 308 } 309 } 310 } 311 } 312 // Now update this menu to use the new calendar the user selected 313 calendars[i] = newCal; 314 calendarPanel.setCalendar(i, newCal); 315 monthFormat[i] = null; 316 317 updateMonthName(); 318 } 319 break; 320 } 321 } 322 } 323 } 324 325 /** 326 * AddAction handles the next/previous year/month buttons... 327 */ 328 private class AddAction implements ActionListener { AddAction(int field, int amount)329 AddAction(int field, int amount) { 330 this.field = field; 331 this.amount = amount; 332 } 333 actionPerformed(ActionEvent e)334 public void actionPerformed(ActionEvent e) { 335 calendarPanel.add(field, amount); 336 updateMonthName(); 337 } 338 339 private int field, amount; 340 } 341 342 /** 343 * ColoredLabel is similar to java.awt.Label, with two differences: 344 * 345 * - You can set its text color 346 * 347 * - It draws text using drawString rather than using a host-specific 348 * "Peer" object like AWT does. On 1.2, using drawString gives 349 * us Bidi reordering for free. 350 */ 351 static private class ColoredLabel extends Component { 352 /** 353 * For serialization 354 */ 355 private static final long serialVersionUID = 5004484960341875722L; ColoredLabel(String label)356 public ColoredLabel(String label) { 357 text = label; 358 } 359 ColoredLabel(String label, Color c)360 public ColoredLabel(String label, Color c) { 361 text = label; 362 color = c; 363 } 364 setText(String label)365 public void setText(String label) { 366 text = label; 367 repaint(); 368 } 369 setFont(Font f)370 public void setFont(Font f) { 371 font = f; 372 repaint(); 373 } 374 paint(Graphics g)375 public void paint(Graphics g) { 376 FontMetrics fm = g.getFontMetrics(font); 377 378 Rectangle bounds = getBounds(); 379 380 g.setColor(color); 381 g.setFont(font); 382 g.drawString(text, fm.stringWidth("\u00a0"), 383 bounds.height/2 + fm.getHeight() 384 - fm.getAscent() + fm.getLeading()/2); 385 } 386 getPreferredSize()387 public Dimension getPreferredSize() { 388 return getMinimumSize(); 389 } 390 getMinimumSize()391 public Dimension getMinimumSize() { 392 FontMetrics fm = getFontMetrics(font); 393 394 return new Dimension( fm.stringWidth(text) + 2*fm.stringWidth("\u00a0"), 395 fm.getHeight() + fm.getLeading()*2); 396 } 397 398 String text; 399 Color color = Color.black; 400 Font font = DemoUtility.labelFont; 401 } 402 403 /** 404 * Print out the error message while debugging this program. 405 */ errorText(String s)406 public void errorText(String s) 407 { 408 if (DEBUG) 409 { 410 System.out.println(s); 411 } 412 } 413 414 class CalendarRec { CalendarRec(String nameStr, Calendar cal)415 public CalendarRec(String nameStr, Calendar cal) 416 { 417 name = nameStr; 418 calendar = cal; 419 } 420 421 Calendar calendar; 422 String name; 423 } 424 425 private final CalendarRec[] CALENDARS = { 426 new CalendarRec("Gregorian Calendar", new GregorianCalendar()), 427 new CalendarRec("Hebrew Calendar", new HebrewCalendar()), 428 new CalendarRec("Islamic Calendar", makeIslamic(false)), 429 new CalendarRec("Islamic Civil Calendar ", makeIslamic(true)), 430 new CalendarRec("Buddhist Calendar", new BuddhistCalendar()), 431 new CalendarRec("Japanese Calendar", new JapaneseCalendar()), 432 }; 433 makeIslamic(boolean civil)434 static private final Calendar makeIslamic(boolean civil) { 435 IslamicCalendar cal = new IslamicCalendar(); 436 cal.setCivil(civil); 437 return cal; 438 } 439 440 static final Color[] COLORS = { Color.blue, Color.black }; 441 } 442 443