12d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// © 2016 and later: Unicode, Inc. and others.
22d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
3bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert/*
4bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert *******************************************************************************
5bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * Copyright (C) 1996-2014, International Business Machines Corporation and    *
6bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * others. All Rights Reserved.                                                *
7bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert *******************************************************************************
8bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */
9bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
10bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertpackage com.ibm.icu.dev.demo.holiday;
11bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
12bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.BorderLayout;
13bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Button;
14bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Canvas;
15bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Choice;
16bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Color;
17bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Component;
18bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Container;
19bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Dimension;
20bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Font;
21bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.FontMetrics;
22bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Frame;
23bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Graphics;
24bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.GridBagConstraints;
25bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.GridBagLayout;
26bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Label;
27bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Panel;
28bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.Point;
29bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.event.ActionEvent;
30bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.event.ActionListener;
31bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.event.ItemEvent;
32bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.event.ItemListener;
33bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.awt.event.WindowEvent;
34bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.text.DateFormatSymbols;
35bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.Date;
36bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.Locale;
37bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport java.util.Vector;
38bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
39bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport com.ibm.icu.dev.demo.impl.DemoApplet;
40bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport com.ibm.icu.dev.demo.impl.DemoTextBox;
41bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport com.ibm.icu.dev.demo.impl.DemoUtility;
42bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport com.ibm.icu.text.DateTimePatternGenerator;
43bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport com.ibm.icu.text.SimpleDateFormat;
44bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport com.ibm.icu.util.Calendar;
45bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertimport com.ibm.icu.util.Holiday;
46bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
47bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert/**
48bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * CalendarDemo demonstrates how Calendar works.
49bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert */
50bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubertpublic class HolidayCalendarDemo extends DemoApplet
51bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert{
52bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    /**
53bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * For serialization
54bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     */
55bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static final long serialVersionUID = 4546085430817359372L;
56bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
57bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    /**
58bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * The main function which defines the behavior of the CalendarDemo
59bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     * applet when an applet is started.
60bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert     */
61bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    public static void main(String argv[]) {
62bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
63bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        new HolidayCalendarDemo().showDemo();
64bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
65bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
66bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    /* This creates a CalendarFrame for the demo applet. */
67bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    public Frame createDemoFrame(DemoApplet applet) {
68bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        return new CalendarFrame(applet);
69bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
70bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
71bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    /**
72bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    * A Frame is a top-level window with a title. The default layout for a frame
73bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    * is BorderLayout.  The CalendarFrame class defines the window layout of
74bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    * CalendarDemo.
75bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    */
76bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static class CalendarFrame extends Frame implements ActionListener,
77bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                                                                ItemListener
78bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    {
79bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        /**
80bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert         * For serialization
81bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert         */
82bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private static final long serialVersionUID = -7023296782393042761L;
83bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
84bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private static final boolean DEBUG = false;
85bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
86bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        //private Locale curLocale = Locale.US; // unused
87bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
88bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private DemoApplet applet;
89bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
90bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private static final Locale[] calendars = {
91bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            //new Locale("de","AT"),
92bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Locale.CANADA,
93bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Locale.CANADA_FRENCH,
94bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Locale.FRANCE,
95bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Locale.GERMANY,
96bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            new Locale("iw","IL"),
97bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            new Locale("el","GR"),
98bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            //new Locale("es","MX"),
99bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Locale.UK,
100bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Locale.US,
101bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        };
102bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private static final Locale[] displays = {
103bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Locale.CANADA,
104bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Locale.UK,
105bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Locale.US,
106bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Locale.FRANCE,
107bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Locale.CANADA_FRENCH,
108bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            //new Locale("de","AT"),
109bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Locale.GERMAN,
110bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            new Locale("el","GR"),
111bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            //new Locale("iw","IL"),
112bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            new Locale("es","MX"),
113bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        };
114bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
115bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        /**
116bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        * Constructs a new CalendarFrame that is initially invisible.
117bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        */
118bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public CalendarFrame(DemoApplet applet)
119bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
120bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            super("Calendar Demo");
121bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            this.applet = applet;
122bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            init();
123bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            start();
124bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            enableEvents(WindowEvent.WINDOW_CLOSING);
125bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
126bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
127bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        /**
128bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        * Initializes the applet. You never need to call this directly, it
129bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        * is called automatically by the system once the applet is created.
130bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        */
131bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public void init()
132bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
133bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Get G7 locales only for demo purpose. To get all the locales
134bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // supported, switch to calling Calendar.getAvailableLocales().
135bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // commented
136bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            locales = displays;
137bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
138bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            buildGUI();
139bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
140bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
141bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        //------------------------------------------------------------
142bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // package private
143bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        //------------------------------------------------------------
144bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        void addWithFont(Container container, Component foo, Font font) {
145bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (font != null)
146bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                foo.setFont(font);
147bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            container.add(foo);
148bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
149bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
150bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        /**
151bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        * Called to start the applet. You never need to call this method
152bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        * directly, it is called when the applet's document is visited.
153bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        */
154bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public void start()
155bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
156bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // do nothing
157bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
158bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
159bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Choice          localeMenu;
160bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Choice          displayMenu;
161bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Locale[]        locales;
162bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
163bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Label           monthLabel;
164bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Button          prevYear;
165bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Button          prevMonth;
166bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Button          gotoToday;
167bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Button          nextMonth;
168bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Button          nextYear;
169bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private CalendarPanel   calendarPanel;
170bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
171bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private static final Locale kFirstLocale = Locale.US;
172bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
173bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private static void add(Container container, Component component,
174bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                                GridBagLayout g, GridBagConstraints c)
175bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
176bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            g.setConstraints(component, c);
177bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            container.add(component);
178bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
179bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
180bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public void buildGUI()
181bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
182bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            setBackground(DemoUtility.bgColor);
183bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            setLayout(new BorderLayout(10,10));
184bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
185bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Label for the demo's title
186bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Label titleLabel = new Label("Calendar Demo", Label.CENTER);
187bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            titleLabel.setFont(DemoUtility.titleFont);
188bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
189bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Label for the current month name
190bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            monthLabel = new Label("", Label.LEFT);
191bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            monthLabel.setFont(new Font(DemoUtility.titleFont.getName(),
192bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                                        DemoUtility.titleFont.getStyle(),
193bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                                        (DemoUtility.titleFont.getSize() * 3)/2));
194bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
195bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Make the locale popup menus
196bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            localeMenu= new Choice();
197bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            localeMenu.addItemListener(this);
198bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            int selectMe = 0;
199bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
200bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            for (int i = 0; i < calendars.length; i++) {
201bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (i > 0 &&
202bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        calendars[i].getCountry().equals(calendars[i-1].getCountry()) ||
203bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    i < calendars.length - 1 &&
204bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        calendars[i].getCountry().equals(calendars[i+1].getCountry()))
205bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                {
206bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    localeMenu.addItem(calendars[i].getDisplayCountry() + " (" +
207bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                                    calendars[i].getDisplayLanguage() + ")");
208bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                } else {
209bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    localeMenu.addItem( calendars[i].getDisplayCountry() );
210bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
211bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
212bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (calendars[i].equals(kFirstLocale)) {
213bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    selectMe = i;
214bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
215bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
216bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
217bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            localeMenu.setBackground(DemoUtility.choiceColor);
218bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            localeMenu.select(selectMe);
219bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
220bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            displayMenu = new Choice();
221bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            displayMenu.addItemListener(this);
222bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
223bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            selectMe = 0;
224bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            for (int i = 0; i < locales.length; i++) {
225bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (i > 0 &&
226bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        locales[i].getLanguage().equals(locales[i-1].getLanguage()) ||
227bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    i < locales.length - 1 &&
228bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        locales[i].getLanguage().equals(locales[i+1].getLanguage()))
229bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                {
230bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    displayMenu.addItem( locales[i].getDisplayName() );
231bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                } else {
232bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    displayMenu.addItem( locales[i].getDisplayLanguage());
233bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
234bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
235bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (locales[i].equals(kFirstLocale)) {
236bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    selectMe = i;
237bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
238bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
239bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
240bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            displayMenu.setBackground(DemoUtility.choiceColor);
241bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            displayMenu.select(selectMe);
242bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
243bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Make all the next/previous/today buttons
244bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            prevYear = new Button("<<");
245bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            prevYear.addActionListener(this);
246bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            prevMonth = new Button("<");
247bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            prevMonth.addActionListener(this);
248bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            gotoToday = new Button("Today");
249bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            gotoToday.addActionListener(this);
250bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            nextMonth = new Button(">");
251bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            nextMonth.addActionListener(this);
252bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            nextYear = new Button(">>");
253bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            nextYear.addActionListener(this);
254bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
255bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // The month name and the control buttons are bunched together
256bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Panel monthPanel = new Panel();
257bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {
258bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                GridBagLayout g = new GridBagLayout();
259bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                GridBagConstraints c = new GridBagConstraints();
260bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                monthPanel.setLayout(g);
261bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
262bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.weightx = 1;
263bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.weighty = 1;
264bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
265bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.gridwidth = 1;
266bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.fill = GridBagConstraints.HORIZONTAL;
267bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.gridwidth = GridBagConstraints.REMAINDER;
268bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                add(monthPanel, monthLabel, g, c);
269bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
270bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.gridwidth = 1;
271bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                add(monthPanel, prevYear, g, c);
272bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                add(monthPanel, prevMonth, g, c);
273bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                add(monthPanel, gotoToday, g, c);
274bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                add(monthPanel, nextMonth, g, c);
275bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.gridwidth = GridBagConstraints.REMAINDER;
276bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                add(monthPanel, nextYear, g, c);
277bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
278bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
279bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Stick the menu and buttons in a little "control panel"
280bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Panel menuPanel = new Panel();
281bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {
282bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                GridBagLayout g = new GridBagLayout();
283bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                GridBagConstraints c = new GridBagConstraints();
284bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                menuPanel.setLayout(g);
285bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
286bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.weightx = 1;
287bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.weighty = 1;
288bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
289bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.fill = GridBagConstraints.HORIZONTAL;
290bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
291bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.gridwidth = GridBagConstraints.RELATIVE;
292bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                Label l1 = new Label("Holidays");
293bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                l1.setFont(DemoUtility.labelFont);
294bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                add(menuPanel, l1, g, c);
295bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
296bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.gridwidth = GridBagConstraints.REMAINDER;
297bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                add(menuPanel, localeMenu, g, c);
298bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
299bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.gridwidth = GridBagConstraints.RELATIVE;
300bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                Label l2 = new Label("Display:");
301bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                l2.setFont(DemoUtility.labelFont);
302bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                add(menuPanel, l2, g, c);
303bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
304bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                c.gridwidth = GridBagConstraints.REMAINDER;
305bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                add(menuPanel, displayMenu, g, c);
306bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
307bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
308bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // The title, buttons, etc. go in a panel at the top of the window
309bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Panel topPanel = new Panel();
310bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {
311bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                topPanel.setLayout(new BorderLayout());
312bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
313bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                //topPanel.add("North", titleLabel);
314bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                topPanel.add("Center", monthPanel);
315bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                topPanel.add("East", menuPanel);
316bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
317bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            add("North", topPanel);
318bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
319bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // The copyright notice goes at the bottom of the window
320bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Label copyright = new Label(DemoUtility.copyright1, Label.LEFT);
321bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            copyright.setFont(DemoUtility.creditFont);
322bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            add("South", copyright);
323bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
324bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Now create the big calendar panel and stick it in the middle
325bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            calendarPanel = new CalendarPanel( kFirstLocale );
326bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            add("Center", calendarPanel);
327bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
328bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            updateMonthName();
329bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
330bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
331bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private void updateMonthName()
332bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
333bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            final Locale displayLocale = calendarPanel.getDisplayLocale();
334bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            final String pattern = DateTimePatternGenerator.
335bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    getInstance(displayLocale).getBestPattern("MMMMy");
336bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            SimpleDateFormat f = new SimpleDateFormat(pattern,
337bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                                                        displayLocale);
338bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            f.setCalendar(calendarPanel.getCalendar());
339bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            monthLabel.setText( f.format( calendarPanel.firstOfMonth() ));
340bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
341bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
342bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        /**
343bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        * Handles the event. Returns true if the event is handled and should not
344bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        * be passed to the parent of this component. The default event handler
345bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        * calls some helper methods to make life easier on the programmer.
346bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        */
347bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public void actionPerformed(ActionEvent e)
348bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
349bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Object obj = e.getSource();
350bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
351bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // *** Button events are handled here.
352bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (obj instanceof Button) {
353bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (obj == nextMonth) {
354bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    calendarPanel.add(Calendar.MONTH, +1);
355bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
356bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                else
357bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (obj == prevMonth) {
358bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    calendarPanel.add(Calendar.MONTH, -1);
359bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
360bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                else
361bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (obj == prevYear) {
362bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    calendarPanel.add(Calendar.YEAR, -1);
363bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
364bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                else
365bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (obj == nextYear) {
366bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    calendarPanel.add(Calendar.YEAR, +1);
367bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
368bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                else
369bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (obj == gotoToday) {
370bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    calendarPanel.set( new Date() );
371bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
372bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                updateMonthName();
373bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
374bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
375bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
376bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public void itemStateChanged(ItemEvent e)
377bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
378bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Object obj = e.getSource();
379bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (obj == localeMenu) {
380bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                calendarPanel.setCalendarLocale(calendars[localeMenu.getSelectedIndex()]);
381bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                updateMonthName();
382bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
383bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            else
384bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (obj == displayMenu) {
385bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    calendarPanel.setDisplayLocale(locales[displayMenu.getSelectedIndex()]);
386bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    updateMonthName();
387bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
388bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
389bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
390bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        /**
391bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        * Print out the error message while debugging this program.
392bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        */
393bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public void errorText(String s)
394bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
395bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (DEBUG)
396bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {
397bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                System.out.println(s);
398bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
399bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
400bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
401bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        protected void processWindowEvent(WindowEvent e)
402bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
403bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            System.out.println("event " + e);
404bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (e.getID() == WindowEvent.WINDOW_CLOSING) {
405bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                this.hide();
406bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                this.dispose();
407bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
408bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                if (applet != null) {
409bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    applet.demoClosed();
410bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                } else {
411bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    System.exit(0);
412bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
413bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
414bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
415bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
416bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
417bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
418bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static class CalendarPanel extends Canvas {
419bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
420bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        /**
421bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert         * For serialization
422bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert         */
423bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private static final long serialVersionUID = 1521099412250120821L;
424bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
425bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public CalendarPanel( Locale locale ) {
426bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            set(locale, locale, new Date());
427bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
428bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
429bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public void setCalendarLocale(Locale locale) {
430bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            set(locale, fDisplayLocale, fCalendar.getTime());
431bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
432bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
433bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public void setDisplayLocale(Locale locale) {
434bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            set(fCalendarLocale, locale, fCalendar.getTime());
435bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
436bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
437bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public void set(Date date) {
438bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            set(fCalendarLocale, fDisplayLocale, date);
439bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
440bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
441bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public void set(Locale loc, Locale display, Date date)
442bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
443bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (fCalendarLocale == null || !loc.equals(fCalendarLocale)) {
444bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fCalendarLocale = loc;
445bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fCalendar = Calendar.getInstance(fCalendarLocale);
446bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fAllHolidays = Holiday.getHolidays(fCalendarLocale);
447bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
448bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (fDisplayLocale == null || !display.equals(fDisplayLocale)) {
449bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fDisplayLocale = display;
450bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fSymbols = new DateFormatSymbols(fDisplayLocale);
451bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
452bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
453bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            fStartOfMonth = date;
454bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
455bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            dirty = true;
456bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            repaint();
457bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
458bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
459bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public void add(int field, int delta)
460bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
461bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            synchronized(fCalendar) {
462bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fCalendar.setTime(fStartOfMonth);
463bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fCalendar.add(field, delta);
464bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fStartOfMonth = fCalendar.getTime();
465bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
466bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            dirty = true;
467bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            repaint();
468bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
469bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
470bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public com.ibm.icu.util.Calendar getCalendar() {
471bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            return fCalendar;
472bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
473bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
474bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public Locale getCalendarLocale() {
475bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            return fCalendarLocale;
476bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
477bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
478bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public Locale getDisplayLocale() {
479bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            return fDisplayLocale;
480bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
481bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
482bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
483bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public Date firstOfMonth() {
484bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            return fStartOfMonth;
485bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
486bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
487bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Date startOfMonth(Date dateInMonth)
488bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
489bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            synchronized(fCalendar) {
490bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fCalendar.setTime(dateInMonth);             // TODO: synchronization
491bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
492bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int era = fCalendar.get(Calendar.ERA);
493bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int year = fCalendar.get(Calendar.YEAR);
494bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int month = fCalendar.get(Calendar.MONTH);
495bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
496bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fCalendar.clear();
497bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fCalendar.set(Calendar.ERA, era);
498bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fCalendar.set(Calendar.YEAR, year);
499bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fCalendar.set(Calendar.MONTH, month);
500bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fCalendar.set(Calendar.DATE, 1);
501bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
502bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                return fCalendar.getTime();
503bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
504bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
505bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
506bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private void calculate()
507bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
508bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Calendar c = (Calendar)fCalendar.clone(); // Temporary copy
509bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
510bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            fStartOfMonth = startOfMonth(fStartOfMonth);
511bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
512bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Stash away a few useful constants for this calendar and display
513bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            minDay = c.getMinimum(Calendar.DAY_OF_WEEK);
514bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            daysInWeek = c.getMaximum(Calendar.DAY_OF_WEEK) - minDay + 1;
515bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
516bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            firstDayOfWeek = Calendar.getInstance(fDisplayLocale).getFirstDayOfWeek();
517bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
518bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Stash away a Date for the start of this month
519bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
520bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Find the day of week of the first day in this month
521bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            c.setTime(fStartOfMonth);
522bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            firstDayInMonth = c.get(Calendar.DAY_OF_WEEK);
523bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
524bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Now find the # of days in the month
525bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            c.roll(Calendar.DATE, false);
526bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            daysInMonth = c.get(Calendar.DATE);
527bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
528bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Finally, find the end of the month, i.e. the start of the next one
529bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            c.roll(Calendar.DATE, true);
530bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            c.add(Calendar.MONTH, 1);
531bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            c.getTime();        // JDK 1.1.2 bug workaround
532bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            c.add(Calendar.SECOND, -1);
533bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Date endOfMonth = c.getTime();
534bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
535bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            //
536bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Calculate the number of full or partial weeks in this month.
537bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // To do this I can just reuse the code that calculates which
538bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // calendar cell contains a given date.
539bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            //
540bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            numWeeks = dateToCell(daysInMonth).y - dateToCell(1).y + 1;
541bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
542bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Remember which holidays fall on which days in this month,
543bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // to save the trouble of having to do it later
544bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            fHolidays.setSize(0);
545bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
546bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            for (int h = 0; h < fAllHolidays.length; h++)
547bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {
548bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                Date d = fStartOfMonth;
549bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                while ( (d = fAllHolidays[h].firstBetween(d, endOfMonth) ) != null)
550bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                {
551bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    if(d.after(endOfMonth)) {
552bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        throw new InternalError("Error: for " + fAllHolidays[h].getDisplayName()+
553bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                                "  #" + h + "/"+fAllHolidays.length+": " + d +" is after end of month " + endOfMonth);
554bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    }
555bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    c.setTime(d);
556bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    fHolidays.addElement( new HolidayInfo(c.get(Calendar.DATE),
557bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                                            fAllHolidays[h],
558bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                                            fAllHolidays[h].getDisplayName(fDisplayLocale) ));
559bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
560bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    d.setTime( d.getTime() + 1000 );    // "d++"
561bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
562bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
563bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            dirty = false;
564bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
565bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
566bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        static final int INSET = 2;
567bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
568bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        /*
569bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        * Convert from the day number within a month (1-based)
570bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        * to the cell coordinates on the calendar (0-based)
571bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        */
572bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private void dateToCell(int date, Point pos)
573bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        {
574bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            int cell = (date + firstDayInMonth - firstDayOfWeek - minDay);
575bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (firstDayInMonth < firstDayOfWeek) {
576bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                cell += daysInWeek;
577bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
578bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
579bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            pos.x = cell % daysInWeek;
580bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            pos.y = cell / daysInWeek;
581bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
582bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Point dateToCell(int date) {
583bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Point p = new Point(0,0);
584bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            dateToCell(date, p);
585bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            return p;
586bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
587bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
588bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public void paint(Graphics g) {
589bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
590bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            if (dirty) {
591bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                calculate();
592bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
593bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
594bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Point cellPos = new Point(0,0);     // Temporary variable
595bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Dimension d = getSize();
596bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
597bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            g.setColor(DemoUtility.bgColor);
598bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            g.fillRect(0,0,d.width,d.height);
599bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
600bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Draw the day names at the top
601bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            g.setColor(Color.black);
602bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            g.setFont(DemoUtility.labelFont);
603bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            FontMetrics fm = g.getFontMetrics();
604bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            int labelHeight = fm.getHeight() + INSET * 2;
605bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
606bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            int v = fm.getAscent() + INSET;
607bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            for (int i = 0; i < daysInWeek; i++) {
608bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int dayNum = (i + minDay + firstDayOfWeek - 2) % daysInWeek + 1;
609bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                String dayName = fSymbols.getWeekdays()[dayNum];
610bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
611bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int h = (int) (d.width * (i + 0.5)) / daysInWeek;
612bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                h -= fm.stringWidth(dayName) / 2;
613bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
614bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                g.drawString(dayName, h, v);
615bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
616bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
617bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            double cellHeight = (d.height - labelHeight - 1) / numWeeks;
618bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            double cellWidth = (double)(d.width - 1) / daysInWeek;
619bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
620bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Draw a white background in the part of the calendar
621bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // that displays this month.
622bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // First figure out how much of the first week should be shaded.
623bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            {
624bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                g.setColor(Color.white);
625bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                dateToCell(1, cellPos);
626bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int width = (int)(cellPos.x*cellWidth);  // Width of unshaded area
627bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
628bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                g.fillRect((int)(width), labelHeight ,
629bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        (int)(d.width - width), (int)cellHeight);
630bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
631bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                // All of the intermediate weeks get shaded completely
632bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                g.fillRect(0, (int)(labelHeight + cellHeight),
633bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                            d.width, (int)(cellHeight * (numWeeks - 2)));
634bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
635bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                // Now figure out the last week.
636bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                dateToCell(daysInMonth, cellPos);
637bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                width = (int)((cellPos.x+1)*cellWidth);  // Width of shaded area
638bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
639bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                g.fillRect(0, (int)(labelHeight + (numWeeks-1) * cellHeight),
640bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                            width, (int)(cellHeight));
641bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
642bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
643bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Draw the X/Y grid lines
644bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            g.setColor(Color.black);
645bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            for (int i = 0; i <= numWeeks; i++) {
646bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int y = (int)(labelHeight + i * cellHeight);
647bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                g.drawLine(0, y, d.width - 1, y);
648bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
649bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            for (int i = 0; i <= daysInWeek; i++) {
650bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int x = (int)(i * cellWidth);
651bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                g.drawLine(x, labelHeight, x, d.height - 1);
652bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
653bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
654bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // Now loop through all of the days in the month, figure out where
655bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // they go in the grid, and draw the day # for each one
656bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Font numberFont = new Font("Helvetica",Font.PLAIN,12);
657bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            // not used Font holidayFont = DemoUtility.creditFont;
658bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
659bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            Calendar c = (Calendar)fCalendar.clone();
660bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            c.setTime(fStartOfMonth);
661bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
662bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            for (int i = 1, h = 0; i <= daysInMonth; i++) {
663bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                g.setFont(numberFont);
664bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                g.setColor(Color.black);
665bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                fm = g.getFontMetrics();
666bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
667bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                dateToCell(i, cellPos);
668bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int x = (int)((cellPos.x + 1) * cellWidth);
669bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                int y = (int)(cellPos.y * cellHeight + labelHeight);
670bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
671bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                StringBuffer buffer = new StringBuffer();
672bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                buffer.append(i);
673bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                String dayNum = buffer.toString();
674bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
675bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                x = x - INSET - fm.stringWidth(dayNum);
676bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                y = y + fm.getAscent() + INSET;
677bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
678bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                g.drawString(dayNum, x, y);
679bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
680bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                // See if any of the holidays land on this day....
681bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                HolidayInfo info = null;
682bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
683bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                // Coordinates of lower-left corner of cell.
684bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                x = (int)((cellPos.x) * cellWidth);
685bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                y = (int)((cellPos.y+1) * cellHeight) + labelHeight;
686bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
687bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                while (h < fHolidays.size() &&
688bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        (info = (HolidayInfo)fHolidays.elementAt(h)).date <= i)
689bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                {
690bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    if (info.date == i) {
691bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        // Draw the holiday here.
692bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        g.setFont(numberFont);
693bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        g.setColor(Color.red);
694bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
695bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        DemoTextBox box = new DemoTextBox(g, info.name, (int)(cellWidth - INSET));
696bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        box.draw(g, x + INSET, y - INSET - box.getHeight());
697bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
698bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                        y -= (box.getHeight() + INSET);
699bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    }
700bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                    h++;
701bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert                }
702bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            }
703bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
704bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
705bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // Important state variables
706bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Locale              fCalendarLocale;    // Whose calendar
707bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Calendar            fCalendar;          // Calendar for calculations
708bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
709bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Locale              fDisplayLocale;     // How to display it
710bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private DateFormatSymbols   fSymbols;           // Symbols for drawing
711bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
712bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private Date                fStartOfMonth;      // 00:00:00 on first day of month
713bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
714bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        // Cached calculations to make drawing faster.
715bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private transient int minDay;           // Minimum legal day #
716bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private transient int daysInWeek;       // # of days in a week
717bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private transient int firstDayOfWeek;   // First day to display in week
718bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private transient int numWeeks;         // # full or partial weeks in month
719bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private transient int daysInMonth;      // # days in this month
720bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private transient int firstDayInMonth;  // Day of week of first day in month
721bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
722bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private transient Holiday[] fAllHolidays;
723bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private transient Vector    fHolidays = new Vector(5,5);
724bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
725bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        private transient boolean dirty = true;
726bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
727bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
728bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    private static class HolidayInfo {
729bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public HolidayInfo(int date, Holiday holiday, String name) {
730bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            this.date = date;
731bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            this.holiday = holiday;
732bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert            this.name = name;
733bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        }
734bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
735bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public Holiday holiday;
736bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public int date;
737bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert        public String name;
738bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert    }
739bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert}
740bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert
741