home *** CD-ROM | disk | FTP | other *** search
/ CD Ware Multimedia 1999 February / CDW0299.iso / Demos / Cafe / Source.bin / Calendar.java < prev    next >
Encoding:
Java Source  |  1998-03-18  |  24.6 KB  |  850 lines

  1. package symantec.itools.awt.util;
  2.  
  3. import java.awt.Panel;
  4. import java.awt.Dimension;
  5. import java.awt.Color;
  6. import java.awt.Font;
  7. import java.awt.Rectangle;
  8. import java.awt.Graphics;
  9. import java.awt.FontMetrics;
  10. import java.awt.Container;
  11. import java.util.Date;
  12. import java.text.DateFormat;
  13. import symantec.itools.awt.ComboBox;
  14. import symantec.itools.awt.util.spinner.NumericSpinner;
  15. import java.beans.PropertyVetoException;
  16. import java.beans.PropertyChangeListener;
  17. import java.beans.VetoableChangeListener;
  18. import java.awt.event.MouseEvent;
  19. import java.awt.event.ActionEvent;
  20. import java.awt.event.ActionListener;
  21. import java.awt.AWTEvent;
  22. import java.awt.AWTEventMulticaster;
  23. import java.awt.LayoutManager;
  24.  
  25. //    01/29/97    TWB    Integrated changes from Windows
  26. //    01/30/97    RKM    Changed invalidates to repaint
  27. //                    Changed logic in paint
  28. //                        1)sc.setBackground is called, only if the colors are different
  29. //                        2)sc.paint is called instead of repaint
  30. //                    Made setDate actually work
  31. //    06/05/97    LAB    Updated to Java 1.1.  Changed most data members to protected, from private.
  32. //    07/14/97    RKM    Added empty override to setLayout, so users could not change it on us
  33. //    07/18/97    LAB    Added add/removeNotify to handle event listener registration.
  34. //                    Updated version number to 1.1.
  35. //  08/25/97    CAR getDate now returns a nicely formatted string
  36. //  09/14/97    RKM Removed hard coded month strings
  37. //  10/03/97    LAB Made paint use ComboBox's preferred size.  This was preventing the ComboBox from
  38. //                    displaying properly (Addresses Mac Bug #7491).  Reworked the way the component
  39. //                    lays its self out and paints itself in an attempt to make it less hard coded
  40. //                    and more dynamic.  Made paint use NumericSpinner's preferred size.  This did
  41. //                    away with the need for resize to be overridden.
  42.  
  43. /**
  44.  * Calendar component.  Creates a graphic calendar displaying a month of dates.
  45.  * A combo box controls the month displayed, a numeric spin control changes the
  46.  * year displayed.
  47.  *
  48.  *
  49.  * @version 1.1, July 18, 1997
  50.  *
  51.  * @author  Symantec
  52.  *
  53.  */
  54. public class Calendar extends Panel
  55. {
  56.     /**
  57.      * Creates a default calendar with today's
  58.      * date initialized.
  59.      */
  60.     public Calendar()
  61.     {
  62.         this(new Date());
  63.     }
  64.  
  65.     /**
  66.      * Creates a calendar with the specified date initialized.
  67.      * @param defaultdate the date to be shown initially
  68.      */
  69.     public Calendar(Date defaultdate)
  70.     {
  71.         super.setLayout(null);
  72.  
  73.         bNeedsPlatformHelp = ComboBox.needsPlatformHelp();  // help comboBar change state
  74.  
  75.         dCurrent = defaultdate;
  76.         dLast = dCurrent;
  77.         combo = new ComboBox();
  78.         try
  79.         {
  80.             java.text.DateFormatSymbols dfs = new java.text.DateFormatSymbols();
  81.             String months[] = dfs.getMonths();
  82.  
  83.             //??? LAB ??? The last item is blank, why?
  84.             int length = months.length > 12 ? 12 : months.length;
  85.  
  86.             for(int i = 0; i < length; ++i)
  87.                 combo.addItem(months[i]);
  88.         }
  89.         catch(PropertyVetoException e) {}
  90.         add(combo);
  91.         sc = new NumericSpinner();
  92.         add(sc);
  93.  
  94.         try
  95.         {
  96.             sc.setMin(1900);
  97.             sc.setMax(9999);
  98.             sc.setCurrent(1900 + dCurrent.getYear());
  99.             sc.setEditable(false);
  100.             combo.select(dCurrent.getMonth());
  101.         }
  102.         catch(PropertyVetoException e) {}
  103.  
  104.         if (symantec.itools.lang.OS.isMacintosh())
  105.             selectedColor = Color.black;
  106.         else
  107.             selectedColor = Color.blue;
  108.  
  109.         if (!symantec.itools.lang.OS.isMacintosh())  //12/18/96  Andy McFarland some platforms don't want their fonts hardwired...
  110.         {
  111.             if (bNeedsPlatformHelp)  // different fonts to help display problems.
  112.                 setFont(new Font("Dialog", Font.PLAIN, 9));
  113.             else
  114.                 setFont(new Font("Dialog", Font.BOLD, 10));
  115.         }
  116.     }
  117.  
  118.     /**
  119.      * Sets the date selected on the calendar.
  120.      * @param date the date that the calendar is to be set to
  121.      *
  122.      * @exception PropertyVetoException
  123.      * if the specified property value is unacceptable
  124.      */
  125.     public void setDate(String date) throws PropertyVetoException
  126.     {
  127.         String oldValue = getDate();
  128.  
  129.         if(!symantec.itools.util.GeneralUtils.objectsEqual(oldValue, date))
  130.         {
  131.             vetos.fireVetoableChange("Date", oldValue, date);
  132.  
  133.             //Convert string to Date
  134.             Date newDate;
  135.             try {
  136.                 newDate = new Date(date);
  137.             } catch (Exception e) {
  138.                 newDate = new Date();
  139.             }
  140.  
  141.             if (!dCurrent.equals(newDate))
  142.             {
  143.                 dCurrent = newDate;
  144.  
  145.                 combo.select(dCurrent.getMonth());
  146.                 sc.setCurrent(1900 + dCurrent.getYear());
  147.  
  148.                 //Trigger re calculation
  149.                 firstDay = -1;
  150.                 lastSelectedDate = -1;
  151.  
  152.                 repaint();
  153.             }
  154.             changes.firePropertyChange("Date", oldValue, date);
  155.         }
  156.     }
  157.  
  158.     /**
  159.      * Returns the date that the calendar is set to.
  160.      * @return the current value of the calendar.
  161.      */
  162.     public String getDate()
  163.     {
  164.         String str;
  165.         DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
  166.         str = df.format(dCurrent);
  167.         return str;
  168.     }
  169.  
  170.     /**
  171.      * Sets the color used to highlight the selected date on the calendar.
  172.      * @param c the color that the selected color is to be set to
  173.      *
  174.      * @exception PropertyVetoException
  175.      * if the specified property value is unacceptable
  176.      */
  177.     public void setSelectedColor(Color c) throws PropertyVetoException
  178.     {
  179.         Color oldValue = selectedColor;
  180.  
  181.         if(!symantec.itools.util.GeneralUtils.objectsEqual(oldValue, c))
  182.         {
  183.             vetos.fireVetoableChange("SelectedColor", oldValue, c);
  184.  
  185.             selectedColor = c;
  186.             repaint();
  187.  
  188.             changes.firePropertyChange("SelectedColor", oldValue, c);
  189.         }
  190.     }
  191.  
  192.     /**
  193.      * Returns the color that highlights the selected date on the calendar.
  194.      * @return the current selected color.
  195.      */
  196.     public Color getSelectedColor()
  197.     {
  198.         return selectedColor;
  199.     }
  200.  
  201.     /**
  202.      * Tells this component that it has been added to a container.
  203.      * This is a standard Java AWT method which gets called by the AWT when
  204.      * this component is added to a container. Typically, it is used to
  205.      * create this component's peer.
  206.      *
  207.      * It has been overridden here to hook-up event listeners.
  208.      *
  209.      * @see #removeNotify
  210.      */
  211.     public synchronized void addNotify()
  212.     {
  213.         super.addNotify();
  214.  
  215.         //Hook up listeners
  216.         if (mouse == null)
  217.         {
  218.             mouse = new Mouse();
  219.             addMouseListener(mouse);
  220.         }
  221.         if (action == null)
  222.         {
  223.             action = new Action();
  224.             sc.addActionListener(action);
  225.             combo.addActionListener(action);
  226.         }
  227.     }
  228.  
  229.     /**
  230.      * Tells this component that it is being removed from a container.
  231.      * This is a standard Java AWT method which gets called by the AWT when
  232.      * this component is removed from a container. Typically, it is used to
  233.      * destroy the peers of this component and all its subcomponents.
  234.      *
  235.      * It has been overridden here to unhook event listeners.
  236.      *
  237.      * @see #addNotify
  238.      */
  239.     public synchronized void removeNotify()
  240.     {
  241.         //Unhook listeners
  242.         if (mouse != null)
  243.         {
  244.             removeMouseListener(mouse);
  245.             mouse = null;
  246.         }
  247.         if (action != null)
  248.         {
  249.             sc.removeActionListener(action);
  250.             combo.removeActionListener(action);
  251.             action = null;
  252.         }
  253.  
  254.         super.removeNotify();
  255.     }
  256.  
  257.     /**
  258.      * Handles redrawing of this component on the screen.
  259.      * This is a standard Java AWT method which gets called by the Java
  260.      * AWT (repaint()) to handle repainting this component on the screen.
  261.      * The graphics context clipping region is set to the bounding rectangle
  262.      * of this component and its <0,0> coordinate is this component's
  263.      * top-left corner.
  264.      * Typically this method paints the background color to clear the
  265.      * component's drawing space, sets graphics context to be the foreground
  266.      * color, and then calls paint() to draw the component.
  267.      *
  268.      * It is overridden here to reduce flicker by eliminating the uneeded
  269.      * clearing of the background.
  270.      *
  271.      * @param g the graphics context
  272.      * @see java.awt.Component#repaint
  273.      * @see #paint
  274.      */
  275.     public void update(Graphics g)
  276.     {
  277.         paint(g);
  278.     }
  279.  
  280.     /**
  281.      * Paints this component using the given graphics context.
  282.      * This is a standard Java AWT method which typically gets called
  283.      * by the AWT to handle painting this component. It paints this component
  284.      * using the given graphics context. The graphics context clipping region
  285.      * is set to the bounding rectangle of this component and its <0,0>
  286.      * coordinate is this component's top-left corner.
  287.      *
  288.      * @param g the graphics context used for painting
  289.      * @see java.awt.Component#repaint
  290.      * @see #update
  291.      */
  292.     public void paint(Graphics g)
  293.     {
  294.         //If the background of the sc is different, set it
  295.         if (!sc.getBackground().equals(getBackground()))
  296.             sc.setBackground(getBackground());
  297.  
  298.         Dimension spinnerSize = sc.getPreferredSize();
  299.         sc.setBounds(getSize().width - spinnerSize.width - edgePad, edgePad, spinnerSize.width, spinnerSize.height);
  300.  
  301.         FontMetrics fm = getFontMetrics(getFont());
  302.  
  303.         Rectangle r = bounds();
  304.  
  305.         if (bNeedsPlatformHelp)
  306.         {   // Solaris parameters
  307.             combo.reshape(12, 20, 100, 34);
  308.             //sc.reshape(r.width - 90, 20, 80, 34);
  309.             topRow = 70;
  310.             selectHeight = fm.getHeight() + 2;
  311.             centerNumber = 14;
  312.             heightAdjust = 6;
  313.             numberAdjust = 6;
  314.         }
  315.         else    //Macintosh and Windows parameters
  316.         {
  317.             Dimension comboSize = combo.getPreferredSize();
  318.             combo.setBounds(edgePad, edgePad, comboSize.width, comboSize.height);
  319.             topRow = spinnerSize.height + edgePad + 2;
  320.             selectHeight = fm.getHeight();
  321.             centerNumber = 14;
  322.             heightAdjust = 2;
  323.             numberAdjust = 0;
  324.         }
  325.  
  326.         int widthWith2EdgeAdj = r.width - (2 * edgePad);
  327.  
  328.         int blockwidth = widthWith2EdgeAdj / 7;            // 7 columns
  329.         int blockheight = ((r.height - topRow - edgePad) / 7);    // 7 rows
  330.         int halfBlockwidth = blockwidth / 2;
  331.         int xloc = halfBlockwidth  - (fm.stringWidth("S") / 2);        //average location in block
  332.         int yloc = topRow + centerNumber;
  333.         if (dateSelectedx < 0)
  334.         {
  335.             int widthWithEdgeAdj = r.width - edgePad;
  336.             int topRowBlockHeight = topRow + (7 * blockheight);
  337.  
  338.             // top
  339.             g.setColor(Color.black);
  340.             g.drawLine(edgePad, topRow, r.width - edgePad - 2, topRow);
  341.  
  342.             // bottom
  343.             g.setColor(Color.lightGray);
  344.             g.drawLine(edgePad, topRowBlockHeight, widthWithEdgeAdj - 3, topRowBlockHeight);
  345.             g.setColor(Color.white);
  346.             g.drawLine(edgePad + 1, topRowBlockHeight + 1, widthWithEdgeAdj - 2, topRowBlockHeight + 1);
  347.  
  348.             // left
  349.             g.setColor(Color.black);
  350.             g.drawLine(edgePad, topRow, edgePad, topRowBlockHeight);
  351.  
  352.             // right
  353.             g.setColor(Color.lightGray);
  354.             g.drawLine(widthWithEdgeAdj - 2, topRow, widthWithEdgeAdj - 2, topRowBlockHeight);
  355.             g.setColor(Color.white);
  356.             g.drawLine(widthWithEdgeAdj - 1, topRow, widthWithEdgeAdj - 1, topRowBlockHeight);
  357.  
  358.             // fill box
  359.             g.fillRect(edgePad + 1, topRow + blockheight , widthWith2EdgeAdj - 3, (6 * blockheight) );
  360.             g.setColor(Color.gray);
  361.             g.fillRect(edgePad + 1, topRow + 1, widthWith2EdgeAdj - 3, blockheight + 1 );
  362.  
  363.             // letters on top
  364.             g.setColor(Color.white);
  365.  
  366.             if (symantec.itools.lang.OS.isMacintosh())
  367.             {
  368.                 yloc += (blockheight+1)/2 - fm.getHeight()/2; // Lets have the day labels track resizes
  369.                                                            // in the component like the numbers do...
  370.             }
  371.  
  372.             g.drawString("S", xloc, yloc - 1);
  373.             xloc = blockwidth + (halfBlockwidth - (fm.stringWidth("M") / 2));
  374.             g.drawString("M", xloc, yloc - 1);
  375.             xloc = (blockwidth * 2) + (halfBlockwidth - (fm.stringWidth("T") / 2));
  376.             g.drawString("T", xloc, yloc - 1);
  377.             xloc = (blockwidth * 3) + (halfBlockwidth - (fm.stringWidth("W") / 2));
  378.             g.drawString("W", xloc, yloc - 1);
  379.             xloc = (blockwidth * 4) + (halfBlockwidth - (fm.stringWidth("T") / 2));
  380.             g.drawString("T", xloc, yloc - 1);
  381.             xloc = (blockwidth * 5) + (halfBlockwidth - (fm.stringWidth("FM") / 2));
  382.             g.drawString("F", xloc, yloc - 1);
  383.             xloc = (blockwidth * 6) + (halfBlockwidth - (fm.stringWidth("S") / 2));
  384.             g.drawString("S", xloc, yloc - 1);
  385.         }
  386.  
  387.         Date dMonthStart;
  388.         // must be run twice for Solaris
  389.         dMonthStart = new Date(dCurrent.getYear(), dCurrent.getMonth(), 1);
  390.         dMonthStart = new Date(dCurrent.getYear(), dCurrent.getMonth(), 1);
  391.  
  392.         // which date does month begin?
  393.         if (firstDay < 0)
  394.             firstDay = dMonthStart.getDay();
  395.         int initdate = -1;
  396.         int caldate = 1;
  397.         int templastdate = -1;
  398.         int month = dCurrent.getMonth() + 1;
  399.  
  400.         // which date already selected
  401.         if (lastSelectedDate < 1) initdate = dCurrent.getDate();
  402.         else if (dateSelectedx < 0) initdate = lastSelectedDate;
  403.  
  404.         // paint calendar
  405.         g.setColor(Color.black);
  406.  
  407.     calendar:
  408.  
  409.         for (int j = 0; j < 6; j++)
  410.         {
  411.             for (int i = 0; i < 7; i++)
  412.             {
  413.                 if ((maxMonthy < dateSelectedy) || (maxMonthy == dateSelectedy && maxMonthx < dateSelectedx))
  414.                 {   //click after end date
  415.                     dateSelectedx = -1;
  416.                     dateSelectedy = -1;
  417.                     break calendar;
  418.                  }
  419.                 if (j == 0 && i < firstDay)
  420.                 {   // click before the start day
  421.                     if (dateSelectedx == i && dateSelectedy == j)
  422.                     {
  423.                         dateSelectedx = -1;
  424.                         dateSelectedy = -1;
  425.                         break calendar;
  426.                     }
  427.                     else
  428.                     continue;
  429.                 }
  430.  
  431.                 // calculate where to draw
  432.                 xloc = (i * blockwidth) + (halfBlockwidth - (fm.stringWidth(Integer.toString(caldate)) / 2));
  433.                 yloc = topRow + heightAdjust + 4 + numberAdjust + (((j+2) * blockheight) - fm.getHeight());
  434.  
  435.                 // draw one digit numbers differently from two digit
  436.                 if (dateSelectedx < 0 && initdate != caldate)
  437.                 {
  438.                     if (caldate < 10)
  439.                         g.drawString((Integer.toString(caldate)), xloc , yloc);
  440.                     else
  441.                         g.drawString(Integer.toString(caldate), xloc , yloc);
  442.                 }
  443.                 else if (dateSelectedx == i && dateSelectedy == j || initdate == caldate)
  444.                 {
  445.                     if (dateSelectedx == i && dateSelectedy == j)
  446.                     {
  447.                         int tempYear = dCurrent.getYear();
  448.                         int tempMonth = dCurrent.getMonth();
  449.                         // must be run twice for Solaris
  450.                         dCurrent = new Date();
  451.                         dCurrent = new Date();
  452.                         dCurrent.setDate(caldate);
  453.                         dCurrent.setYear(tempYear);
  454.                         dCurrent.setMonth(tempMonth);
  455.                     }
  456.                     //draw selected number
  457.                     g.setColor(selectedColor);
  458.                     if (caldate < 10)
  459.                         g.fillRect(xloc, yloc - selectHeight + heightAdjust, fm.stringWidth(Integer.toString(caldate)) + 2, selectHeight);
  460.                     else
  461.                         g.fillRect(xloc, yloc - selectHeight + heightAdjust, fm.stringWidth(Integer.toString(caldate)), selectHeight);
  462.                     g.setColor(Color.white);
  463.                     if (caldate < 10)
  464.                         g.drawString(Integer.toString(caldate), xloc , yloc);
  465.                     else
  466.                         g.drawString(Integer.toString(caldate), xloc , yloc);
  467.                     templastdate = caldate;
  468.                     g.setColor(Color.black);
  469.                 }
  470.                 else if (caldate == lastSelectedDate)
  471.                 {   // unselected previously selected number
  472.                     g.setColor(Color.white);
  473.                     if (caldate < 10)
  474.                         g.fillRect(xloc, yloc - selectHeight + heightAdjust, fm.stringWidth(Integer.toString(caldate)) + 2, selectHeight);
  475.                     else
  476.                         g.fillRect(xloc, yloc - selectHeight + heightAdjust, fm.stringWidth(Integer.toString(caldate)), selectHeight);
  477.                     g.setColor(Color.black);
  478.                     if (caldate < 10)
  479.                         g.drawString(Integer.toString(caldate), xloc , yloc);
  480.                     else
  481.                         g.drawString(Integer.toString(lastSelectedDate), xloc, yloc);
  482.                     lastSelectedDate = -1;
  483.                 }
  484.                 if (caldate >= 31)
  485.                 {
  486.                     maxMonthx = i;
  487.                     maxMonthy = j;
  488.                     break calendar;
  489.                 }
  490.                 else if ((caldate >= 30) && ((month == 4) || (month == 6) || (month == 9) || (month == 11)))
  491.                 {
  492.                     maxMonthx = i;
  493.                     maxMonthy = j;
  494.                     break calendar;
  495.                 }
  496.                 else if ((caldate >= 29) && (month == 2))
  497.                 {
  498.                     maxMonthx = i;
  499.                     maxMonthy = j;
  500.                     break calendar;
  501.                 }
  502.                 else if ((caldate >= 28) && (month == 2) && (!isLeapYear(dCurrent.getYear())))
  503.                 {
  504.                     maxMonthx = i;
  505.                     maxMonthy = j;
  506.                     break calendar;
  507.                 }
  508.                 caldate++;
  509.             }
  510.         }
  511.  
  512.         if (lastSelectedDate < 0)
  513.             lastSelectedDate = templastdate;
  514.  
  515.         dateSelectedx = -1;
  516.         dateSelectedy = -1;
  517.  
  518.         if (!dLast.equals(dCurrent))
  519.         {
  520.             dLast = dCurrent;
  521.             sourceActionEvent();
  522.         }
  523.     }
  524.  
  525.     /**
  526.      * Returns the recommended dimensions to properly display this component.
  527.      * This is a standard Java AWT method which gets called to determine
  528.      * the recommended size of this component.
  529.      *
  530.      * @return the preferred dimensions for the calender (250 x 200 pixels).
  531.      *
  532.      * @see #minimumSize
  533.      */
  534.     public Dimension preferredSize()
  535.     {
  536.         return (new Dimension(250,200));
  537.     }
  538.  
  539.     /**
  540.      * Returns the minimum dimensions to properly display this component.
  541.      * This is a standard Java AWT method which gets called to determine
  542.      * the minimum size of this component.
  543.      *
  544.      * @return the minimum dimensions needed for the calender (250 x 200 pixels).
  545.      *
  546.      * @see #preferredSize
  547.      */
  548.     public Dimension minimumSize()
  549.     {
  550.         return (new Dimension(250,200));
  551.     }
  552.  
  553.     /**
  554.      * Adds a listener for all property change events.
  555.      * @param listener the listener to add
  556.      * @see #removePropertyChangeListener
  557.      */
  558.     public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
  559.     {
  560.         changes.addPropertyChangeListener(listener);
  561.     }
  562.  
  563.     /**
  564.      * Removes a listener for all property change events.
  565.      * @param listener the listener to remove
  566.      * @see #addPropertyChangeListener
  567.      */
  568.     public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
  569.     {
  570.         changes.removePropertyChangeListener(listener);
  571.     }
  572.  
  573.     /**
  574.      * Adds a listener for all vetoable property change events.
  575.      * @param listener the listener to add
  576.      * @see #removeVetoableChangeListener
  577.      */
  578.     public synchronized void addVetoableChangeListener(VetoableChangeListener listener)
  579.     {
  580.         vetos.addVetoableChangeListener(listener);
  581.     }
  582.  
  583.     /**
  584.      * Removes a listener for all vetoable property change events.
  585.      * @param listener the listener to remove
  586.      * @see #addVetoableChangeListener
  587.      */
  588.     public synchronized void removeVetoableChangeListener(VetoableChangeListener listener)
  589.     {
  590.         vetos.removeVetoableChangeListener(listener);
  591.     }
  592.  
  593.     /**
  594.      * Sets the command name of the action event fired by this button.
  595.      * @param command The name of the action event command fired by this button
  596.      *
  597.      * @exception PropertyVetoException
  598.      * if the specified property value is unacceptable
  599.      */
  600.     public void setActionCommand(String command) throws PropertyVetoException
  601.     {
  602.         String oldValue = actionCommand;
  603.  
  604.         vetos.fireVetoableChange("ActionCommand", oldValue, command);
  605.         actionCommand = command;
  606.         changes.firePropertyChange("ActionCommand", oldValue, command);
  607.     }
  608.  
  609.     /**
  610.      * @returns the command name of the action event fired by this button.
  611.      */
  612.     public String getActionCommand()
  613.     {
  614.         return actionCommand;
  615.     }
  616.  
  617.     /**
  618.      * Adds the specified action listener to receive action events
  619.      * from this button.
  620.      * @param l the action listener
  621.      */
  622.     public synchronized void addActionListener(ActionListener l)
  623.     {
  624.         actionListener = AWTEventMulticaster.add(actionListener, l);
  625.     }
  626.  
  627.     /**
  628.      * Removes the specified action listener so it no longer receives
  629.      * action events from this button.
  630.      * @param l the action listener
  631.      */
  632.     public synchronized void removeActionListener(ActionListener l)
  633.     {
  634.         actionListener = AWTEventMulticaster.remove(actionListener, l);
  635.     }
  636.  
  637.     /**
  638.      * Fire an action event to the listeners
  639.      */
  640.     public void sourceActionEvent()
  641.     {
  642.         if (actionListener != null)
  643.             actionListener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, actionCommand));
  644.     }
  645.  
  646.     /**
  647.      * This is the Mouse Event handling innerclass.
  648.      */
  649.     class Mouse extends java.awt.event.MouseAdapter
  650.     {
  651.         /**
  652.          * Handles Mouse Pressed events
  653.          * @param e the MouseEvent
  654.          */
  655.         synchronized public void mousePressed(MouseEvent e)
  656.         {
  657.             int topRow = -1;
  658.             int x = e.getX();
  659.             int y = e.getY();
  660.             if (bNeedsPlatformHelp) // Solaris machines have different drawing levels
  661.             {
  662.                 topRow = 70;
  663.                 centerNumber = 14;
  664.                 heightAdjust = 6;
  665.                 numberAdjust = 6;
  666.             }
  667.             else
  668.             {
  669.                 topRow = 40;        // needed for Windows drawing
  670.                 numberAdjust = 0;
  671.             }
  672.             Rectangle r = bounds();
  673.             int blockheight = ((r.height - topRow - 14) / 7);   // 7 rows
  674.             int blockwidth = (r.width - 32) / 7;                // 7 columns
  675.  
  676.             if ( ((x >= 15) && (x < r.width - 15)) &&   // if event in calendar window
  677.                  ((y >= topRow + blockheight) && (y < r.height - 14)))
  678.             {
  679.                 dateSelectedx = ((x - 16) / blockwidth);
  680.                 dateSelectedy = ((y  - topRow - blockheight) / blockheight);
  681.                 repaint();
  682.                 firstDay = -1;
  683.             }
  684.         }
  685.     }
  686.  
  687.     /**
  688.      * This is the Adjustment Event handling innerclass.
  689.      */
  690.     class Action implements java.awt.event.ActionListener
  691.     {
  692.         /**
  693.          * Handles Action events
  694.          * @param e the ActionEvent
  695.          */
  696.         public void actionPerformed(ActionEvent e)
  697.         {
  698.             Object target = e.getSource();
  699.  
  700.             // ComboBox list items == month type events
  701.             if (target instanceof ComboBox)
  702.             {
  703.                 int dy = dCurrent.getDate();
  704.                 int mo = combo.getSelectedIndex();
  705.                 int yr = dCurrent.getYear();
  706.                 dCurrent = new Date(yr, mo, dy);
  707.                 while (dCurrent.getMonth() != mo)
  708.                 {
  709.                     dCurrent = new Date(yr, mo, --dy);
  710.                     lastSelectedDate = -1;
  711.                 }
  712.                 firstDay = -1;
  713.                 repaint();
  714.             }
  715.  
  716.             // Spin Control list items == year type events
  717.             if (target == sc)
  718.             {
  719.                 int dy = dCurrent.getDate();
  720.                 int mo = dCurrent.getMonth();
  721.                 int yr = sc.getCurrent() - 1900;
  722.                 dCurrent = new Date(yr, mo, dy);
  723.                 while (dCurrent.getMonth() != mo)
  724.                 {
  725.                     dCurrent = new Date(yr, mo, --dy);
  726.                     lastSelectedDate = -1;
  727.                 }
  728.                 firstDay = -1;
  729.                 repaint();
  730.             }
  731.         }
  732.     }
  733.  
  734.     /**
  735.      * Takes no action.
  736.      * This is a standard Java AWT method which gets called to specify
  737.      * which layout manager should be used to layout the components in
  738.      * standard containers.
  739.      *
  740.      * Since layout managers CANNOT BE USED with this container the standard
  741.      * setLayout has been OVERRIDDEN for this container and does nothing.
  742.      *
  743.      * @param lm the layout manager to use to layout this container's components
  744.      * (IGNORED)
  745.      * @see java.awt.Container#getLayout
  746.      **/
  747.     public void setLayout(LayoutManager lm)
  748.     {
  749.     }
  750.  
  751.     boolean isLeapYear(int year)
  752.     {
  753.         if (year% 4 == 0 && (year != 2100))
  754.             return true;
  755.         else
  756.             return false;
  757.     }
  758.  
  759.     String actionCommand;
  760.     ActionListener actionListener = null;
  761.  
  762.     /**
  763.      * The ComboBox that displays/controls the month.
  764.      */
  765.     protected ComboBox combo;
  766.     /**
  767.      * True if the ComboBox needs help changing state.
  768.      * @see #combo
  769.      * @see symantec.itools.awt.ComboBox#needsPlatformHelp
  770.      */
  771.     protected boolean bNeedsPlatformHelp;
  772.     /**
  773.      * The spinner that displays/controls the year.
  774.      */
  775.     protected NumericSpinner sc;
  776.     /**
  777.      * The date that the calendar is set to.
  778.      * @see #setDate
  779.      * @see #getDate
  780.      */
  781.     protected Date dCurrent;
  782.     /**
  783.      * The current date when the Calendar was last painted.
  784.      */
  785.     protected Date dLast;
  786.     /**
  787.      * The color used to highlight the selected date on the calendar.
  788.      * @see #setSelectedColor
  789.      * @see #getSelectedColor
  790.      */
  791.     protected Color selectedColor;
  792.     /**
  793.      * Not used.
  794.      */
  795.     protected String cal[][];
  796.     /**
  797.      * The number of pixels to offset the internal components from the edges.
  798.      */
  799.     protected int edgePad = 2;
  800.     /**
  801.      * The column index of the currently selected day.
  802.      */
  803.     protected int dateSelectedx = -1;
  804.     /**
  805.      * The row index of the currently selected day.
  806.      */
  807.     protected int dateSelectedy = -1;
  808.     /**
  809.      * The day selected when the Caledar was last painted.
  810.      */
  811.     protected int lastSelectedDate = -1;
  812.     /**
  813.      * The column index of the last day in the month.
  814.      */
  815.     protected int maxMonthx = -1;
  816.     /**
  817.      * The row index of the last day in the month.
  818.      */
  819.     protected int maxMonthy = -1;
  820.     /**
  821.      * The day of the week the month starts on.
  822.      */
  823.     protected int firstDay = -1;
  824.     /**
  825.      * Internal drawing calibration value. The height of the topmost row of the Calendar, in pixels.
  826.      */
  827.     protected int topRow = -1;
  828.     /**
  829.      * Internal drawing calibration value. The height of a selected area in the Calendar, in pixels.
  830.      */
  831.     protected int selectHeight = -1;
  832.     /**
  833.      * Internal drawing calibration value.
  834.      */
  835.     protected int centerNumber = -1;
  836.     /**
  837.      * Internal drawing calibration value.
  838.      */
  839.     protected int heightAdjust = -1;
  840.     /**
  841.      * Internal drawing calibration value.
  842.      */
  843.     protected int numberAdjust = -1;
  844.  
  845.     private Action    action    = null;
  846.     private Mouse    mouse    = null;
  847.     private symantec.itools.beans.VetoableChangeSupport vetos = new symantec.itools.beans.VetoableChangeSupport(this);
  848.     private symantec.itools.beans.PropertyChangeSupport changes = new symantec.itools.beans.PropertyChangeSupport(this);
  849. }
  850.