home *** CD-ROM | disk | FTP | other *** search
/ Symantec Visual Cafe for Java 2.5 / symantec-visual-cafe-2.5-database-dev-edition.iso / VCafe / Source.bin / Spinner.java < prev    next >
Encoding:
Java Source  |  1998-09-14  |  30.2 KB  |  1,043 lines

  1. package symantec.itools.awt.util.spinner;
  2.  
  3.  
  4. import java.awt.*;
  5. import java.awt.event.*;
  6. import java.beans.PropertyChangeEvent;
  7. import java.beans.PropertyChangeListener;
  8. import java.beans.PropertyVetoException;
  9. import java.beans.VetoableChangeListener;
  10. import java.io.Serializable;
  11. import java.util.ResourceBundle;
  12. import symantec.itools.awt.Orientation;
  13. import symantec.itools.beans.*;
  14.  
  15.  
  16. //     01/29/97    TWB    Integrated changes from Macintosh
  17. //    01/30/97    RKM    Changed updateText to check if the text has changed, to avoid flicker
  18. //                    Also changed paint to first call updateText and removed ifdef MAC
  19. //    06/02/97    MSH Updated to Java 1.1
  20. //    06/03/97    LAB Polished update to Java 1.1.
  21. //                    Changed the package to symantec.itools.awt.util.spinner.
  22. //    07/18/97    LAB Added add/removeNotify to handle event listener registration.
  23. //                    Made sourceActionEvent protected instead of public.
  24. //  07/30/97    CAR Inner adaptor class implements java.io.Serializable
  25. //    09/02/97    RKM    Better code in updateText()
  26. //                    Added getEntryFieldText() as per request from newsgroup
  27. //  08/24/87    CAR hooked up actionlistener to textfield to listen for changes to the text
  28. //                  call updateText() from actionPerformed when textField's text changes
  29. //                  call invalidate/validate in setOrientation
  30. //  08/28/97    LAB    Made the spinner buttons disable and enable according to the value.  Implemented
  31. //                    getPreferredSize and getMinimumSize (Addresses Mac Bug #7518).  Changed the
  32. //                    property name strings in bound and constrained event messages to match the Bean
  33. //                    Spec naming conventions.
  34. //  09/11/97    LAB    Added listener registration code to setOrientation to remove and add our
  35. //                    listener to the newly created horizontal or vertical spin button panel.
  36. //                    Fixes a problem when you switched orientations and the spinner no longer
  37. //                    spun (Addresses Mac Bug#7822).
  38. //  10/05/97    LAB    Added mechanism for internally constrained properties to be validated
  39. //                    after the component is added to the form to avoid code-gen order specific
  40. //                    dependencies.
  41. //  10/06/97    LAB    Changed addNotify to call it's super after listeners are hooked up so
  42. //                    verifyContstrainedPropertyValues will be called after the listeners
  43. //                    are hooked up.  Changed order of calls in verifyContstrainedPropertyValues
  44. //                    method to reflect dependancy correctly.  Changed setMax, setMin, and
  45. //                    setCurrent to set the temp values to the current values when changing the
  46. //                    current values.  Changed getMax, getMin, and getCurrent to return the temp
  47. //                    values if the component is not added. This fixes a problem at design time
  48. //                    where the component would revert to it's default state after a back run.
  49. //  10/12/97    LAB    Changed doLayout so if the component is sized smaller than the preferred
  50. //                    size for the textfield and buttons, the textfield is shortened (Addresses
  51. //                    Mac Bug #9051).  When the textField fires an action event, the focus is
  52. //                    now requested by the Spinner (this takes the focus away from the textField).
  53. //                    Rearranged addNotify to correctly add the action listener to the textField
  54. //                    (Addresses Mac Bug #9200).
  55. //  02/05/98    DS  Re-write of GUI
  56.  
  57. /**
  58.  * This abstract class is used to create spinners. A spinner is a component
  59.  * with two small direction buttons that lets the user scroll a list of
  60.  * predetermined values to select one, or possibly enter a new legal value.
  61.  * @see symantec.itools.awt.util.spinner.ListSpinner
  62.  * @see symantec.itools.awt.util.spinner.NumericSpinner
  63.  * @version 1.1, June 2, 1997
  64.  * @author Symantec
  65.  */
  66. public abstract class Spinner
  67.     extends    Panel
  68.     implements Orientation,
  69.                Serializable
  70. {
  71.     class Action
  72.         implements ActionListener,
  73.                    java.io.Serializable
  74.     {
  75.         public void actionPerformed(ActionEvent e)
  76.         {
  77.             if(e.getSource() instanceof TextField)
  78.             {
  79.                    if(((TextField)e.getSource()) == textFld)
  80.                    {
  81.                      updateText(false);
  82.                     //Take the focus away from the edit box
  83.                     requestFocus();
  84.                        return;
  85.                 }
  86.             }
  87.  
  88.             String cmdStr = "";
  89.             String actionCommand = e.getActionCommand();
  90.  
  91.             if(actionCommand.equals("Increment"))
  92.             {
  93.                 scrollUp();
  94.                 cmdStr = "ScrollUp";
  95.                 sourceActionEvent(cmdStr);
  96.             }
  97.             else if(actionCommand.equals("Decrement"))
  98.             {
  99.                 scrollDown();
  100.                 cmdStr = "ScrollDown";
  101.                 sourceActionEvent(cmdStr);
  102.             }
  103.         }
  104.     }
  105.  
  106.     /**
  107.      * This is the PropertyChangeEvent handling inner class for the constrained Current property.
  108.      * Handles vetoing Current values that are not valid.
  109.      */
  110.     class CurrentVeto
  111.         implements VetoableChangeListener,
  112.                    java.io.Serializable
  113.     {
  114.         /**
  115.          * This method gets called when an attempt to change the constrained Current property is made.
  116.          * Ensures the given Current value is valid for this component.
  117.          *
  118.          * @param     e a <code>PropertyChangeEvent</code> object describing the
  119.          *             event source and the property that has changed.
  120.          * @exception PropertyVetoException if the recipient wishes the property
  121.          *              change to be rolled back.
  122.          */
  123.         public void vetoableChange(PropertyChangeEvent e)
  124.             throws PropertyVetoException
  125.         {
  126.             int i = ((Integer)e.getNewValue()).intValue();
  127.  
  128.             if(!isValidCurrentValue(i))
  129.             {
  130.                 throw new PropertyVetoException(errors.getString("InvalidCurrentValue") + i, e);
  131.             }
  132.         }
  133.     }
  134.  
  135.     /**
  136.      * This is the PropertyChangeEvent handling inner class for the constrained Max property.
  137.      * Handles vetoing Max values that are not valid.
  138.      */
  139.     class MaxVeto
  140.         implements VetoableChangeListener,
  141.                    Serializable
  142.     {
  143.         /**
  144.          * This method gets called when an attempt to change the constrained Current property is made.
  145.          * Ensures the given Max value is valid for this component.
  146.          *
  147.          * @param     e a <code>PropertyChangeEvent</code> object describing the
  148.          *             event source and the property that has changed.
  149.          * @exception PropertyVetoException if the recipient wishes the property
  150.          *              change to be rolled back.
  151.          */
  152.         public void vetoableChange(PropertyChangeEvent e)
  153.             throws PropertyVetoException
  154.         {
  155.             int i = ((Integer)e.getNewValue()).intValue();
  156.  
  157.             if(!isValidMaxValue(i))
  158.             {
  159.                 throw new PropertyVetoException(errors.getString("InvalidMaxValue") + i, e);
  160.             }
  161.         }
  162.     }
  163.  
  164.     /**
  165.      * This is the PropertyChangeEvent handling inner class for the constrained Min property.
  166.      * Handles vetoing Min values that are not valid.
  167.      */
  168.     class MinVeto
  169.         implements VetoableChangeListener,
  170.                    java.io.Serializable
  171.     {
  172.         /**
  173.          * This method gets called when an attempt to change the constrained Current property is made.
  174.          * Ensures the given Min value is valid for this component.
  175.          *
  176.          * @param     e a <code>PropertyChangeEvent</code> object describing the
  177.          *             event source and the property that has changed.
  178.          * @exception PropertyVetoException if the recipient wishes the property
  179.          *              change to be rolled back.
  180.          */
  181.         public void vetoableChange(PropertyChangeEvent e)
  182.             throws PropertyVetoException
  183.         {
  184.             int i = ((Integer)e.getNewValue()).intValue();
  185.  
  186.             if(!isValidMinValue(i))
  187.             {
  188.                 throw new PropertyVetoException(errors.getString("InvalidMinValue") + i, e);
  189.             }
  190.         }
  191.     }
  192.  
  193.     protected static int ORIENTATION_DEFAULT = ORIENTATION_VERTICAL;
  194.  
  195.     protected String                text;
  196.     protected int                   textWidth;
  197.     protected int                   orientation;
  198.     protected boolean               wrappable;
  199.     protected boolean               editable;
  200.     protected int                   min;
  201.     protected int                   max;
  202.     protected int                   current;
  203.     protected int                   increment;
  204.     protected VetoableChangeSupport vetos;
  205.     protected PropertyChangeSupport changes;
  206.     protected ResourceBundle        errors;
  207.     protected ActionListener        actionListener;
  208.     protected CurrentVeto            currentVeto;
  209.     protected MaxVeto                maxVeto;
  210.     protected MinVeto                minVeto;
  211.     protected Action                action;
  212.     protected boolean               added;
  213.  
  214.     {
  215.         min       = 0;
  216.         max       = 0;
  217.         increment = 1;
  218.         current   = 0;
  219.         textWidth = 0;
  220.         vetos     = new VetoableChangeSupport(this);
  221.         changes   = new PropertyChangeSupport(this);
  222.         added     = false;
  223.     }
  224.  
  225.     public Spinner()
  226.     {
  227.         //{{INIT_CONTROLS
  228.         GridBagLayout gridBagLayout;
  229.         gridBagLayout = new GridBagLayout();
  230.         super.setLayout(gridBagLayout);
  231.         setSize(61,20);
  232.         textFld = new java.awt.TextField();
  233.         textFld.setBounds(0,0,100,20);
  234.         GridBagConstraints gbc;
  235.         gbc = new GridBagConstraints();
  236.         gbc.gridx = 0;
  237.         gbc.gridy = 0;
  238.         gbc.weightx = 1.0;
  239.         gbc.weighty = 1.0;
  240.         gbc.fill = GridBagConstraints.HORIZONTAL;
  241.         gbc.insets = new Insets(0,0,0,0);
  242.         ((GridBagLayout)getLayout()).setConstraints(textFld, gbc);
  243.         add(textFld);
  244.         buttons = new symantec.itools.awt.util.spinner.SpinButtonPanel();
  245.         buttons.setLayout(new GridLayout(2,1,0,0));
  246.         buttons.setBounds(100,0,3,20);
  247.         gbc = new GridBagConstraints();
  248.         gbc.gridx = 1;
  249.         gbc.gridy = 0;
  250.         gbc.weightx = 0.05;
  251.         gbc.weighty = 1.0;
  252.         gbc.fill = GridBagConstraints.BOTH;
  253.         gbc.insets = new Insets(0,0,0,0);
  254.         ((GridBagLayout)getLayout()).setConstraints(buttons, gbc);
  255.         add(buttons);
  256.         //}}
  257.  
  258.         try
  259.         {
  260.             setWrappable(false);
  261.             setOrientation(ORIENTATION_DEFAULT);
  262.         }
  263.         catch(PropertyVetoException e)
  264.         {
  265.         }
  266.     }
  267.  
  268.     //{{DECLARE_CONTROLS
  269.     java.awt.TextField textFld;
  270.     symantec.itools.awt.util.spinner.SpinButtonPanel buttons;
  271.     //}}
  272.  
  273.     /**
  274.      * Conditionally enables editing of the Spinner's TextField.
  275.      * @param f true = allow editing;
  276.      *          false = disallow editing
  277.      *
  278.      * @exception PropertyVetoException
  279.      * if the specified property value is unacceptable
  280.      */
  281.     public void setEditable(boolean f) throws PropertyVetoException
  282.     {
  283.         if(editable != f)
  284.         {
  285.             Boolean oldValue;
  286.             Boolean newValue;
  287.  
  288.             oldValue = new Boolean(editable);
  289.             newValue = new Boolean(f);
  290.             vetos.fireVetoableChange("editable", oldValue, newValue);
  291.             editable = f;
  292.             textFld.setEditable(editable);
  293.             changes.firePropertyChange("editable", oldValue, newValue);
  294.         }
  295.     }
  296.  
  297.     /**
  298.      * Returns whether the Spinner's TextField is editable.
  299.      * @return true if the TextField can be edited, false otherwise
  300.      */
  301.     public boolean getEditable()
  302.     {
  303.         return editable;
  304.     }
  305.  
  306.     /**
  307.      * Returns whether the Spinner's TextField is editable.
  308.      * @return true if the TextField can be edited, false otherwise
  309.      */
  310.     public boolean isEditable()
  311.     {
  312.         return editable;
  313.     }
  314.  
  315.     public void setOrientation(int o)
  316.         throws PropertyVetoException
  317.     {
  318.         if(orientation != o)
  319.         {
  320.             Integer oldValue;
  321.             Integer newValue;
  322.  
  323.             oldValue = new Integer(orientation);
  324.             newValue = new Integer(o);
  325.             vetos.fireVetoableChange("orientation", oldValue, newValue);
  326.             orientation = o;
  327.             buttons.setOrientation(orientation);
  328.             changes.firePropertyChange("orientation", oldValue, newValue);
  329.         }
  330.     }
  331.  
  332.     public int getOrientation()
  333.     {
  334.         return (orientation);
  335.     }
  336.  
  337.     public void setWrappable(boolean f)
  338.         throws PropertyVetoException
  339.     {
  340.         if(wrappable != f)
  341.         {
  342.             Boolean oldValue;
  343.             Boolean newValue;
  344.  
  345.             oldValue = new Boolean(wrappable);
  346.             newValue = new Boolean(f);
  347.             vetos.fireVetoableChange("wrappable", oldValue, newValue);
  348.             wrappable = f;
  349.             updateButtonStatus();
  350.             changes.firePropertyChange("wrappable", oldValue, newValue);
  351.         }
  352.     }
  353.  
  354.     public boolean getWrappable()
  355.     {
  356.         return (wrappable);
  357.     }
  358.  
  359.     public boolean isWrappable()
  360.     {
  361.         return (wrappable);
  362.     }
  363.  
  364.     public Dimension getPreferredSize()
  365.     {
  366.         Dimension   textFldDim;
  367.         Dimension   btnsDim;
  368.         
  369.         textFldDim  = textFld.getPreferredSize();
  370.         btnsDim     = buttons.getPreferredSize();
  371.  
  372.         return (new Dimension(textFldDim.width + btnsDim.width, Math.max(textFldDim.height, btnsDim.height)));
  373.     }
  374.  
  375.     public Dimension getMinimumSize()
  376.     {
  377.         return (getPreferredSize());
  378.     }
  379.  
  380.     /**
  381.      * Sets the minimum value the spinner may have.
  382.      * @param i the new minimum value
  383.      * @see #getMin
  384.      *
  385.      * @exception PropertyVetoException
  386.      * if the specified property value is unacceptable
  387.      */
  388.     public void setMin(int i)
  389.         throws PropertyVetoException
  390.     {
  391.         if(min != i)
  392.         {
  393.             Integer oldValue;
  394.             Integer newValue;
  395.  
  396.             oldValue = new Integer(min);
  397.             newValue = new Integer(i);
  398.             vetos.fireVetoableChange("min", oldValue, newValue);
  399.             min = i;
  400.  
  401.             if(getCurrent() < min)
  402.             {
  403.                    setCurrent(min);
  404.             }
  405.             else
  406.             {
  407.                 updateButtonStatus();
  408.             }
  409.  
  410.             changes.firePropertyChange("min", oldValue, newValue);
  411.         }
  412.     }
  413.  
  414.     /**
  415.      * Gets the current minimum value the spinner may have.
  416.      * @return the current minimum value
  417.      * @see #setMin
  418.      */
  419.     public int getMin()
  420.     {
  421.         return (min);
  422.     }
  423.  
  424.     /**
  425.      * Sets the maximum value the spinner may have.
  426.      * @param i the new maximum value
  427.      * @see #getMax
  428.      *
  429.      * @exception PropertyVetoException
  430.      * if the specified property value is unacceptable
  431.      */
  432.     public void setMax(int i) throws PropertyVetoException
  433.     {
  434.         if(max != i)
  435.         {
  436.             Integer oldValue;
  437.             Integer newValue;
  438.  
  439.             oldValue = new Integer(max);
  440.             newValue = new Integer(i);
  441.             vetos.fireVetoableChange("max", oldValue, newValue);
  442.             max = i;
  443.  
  444.             if(getCurrent() > max)
  445.             {
  446.                 setCurrent(max);
  447.             }
  448.             else
  449.             {
  450.                 updateButtonStatus();
  451.             }
  452.  
  453.             changes.firePropertyChange("max", oldValue, newValue);
  454.         }
  455.     }
  456.  
  457.     /**
  458.      * Gets the current maximum value the spinner may have.
  459.      * @return the current maximum value
  460.      * @see #setMax
  461.      */
  462.     public int getMax()
  463.     {
  464.         return (max);
  465.     }
  466.  
  467.     /**
  468.      * Sets the value of the spinner.
  469.      * @param i the new value
  470.      * @see #getCurrent
  471.      *
  472.      * @exception PropertyVetoException
  473.      * if the specified property value is unacceptable
  474.      */
  475.     public void setCurrent(int i) throws PropertyVetoException
  476.     {
  477.         if(current != i)
  478.         {
  479.                Integer oldValue;
  480.             Integer newValue;
  481.  
  482.                oldValue = new Integer(current);
  483.             newValue = new Integer(i);
  484.             vetos.fireVetoableChange("current", oldValue, newValue);
  485.             current = i;
  486.             updateText(false);
  487.             updateButtonStatus();
  488.             changes.firePropertyChange("current", oldValue, newValue);
  489.         }
  490.     }
  491.  
  492.     /**
  493.      * Gets the current value of the spinner.
  494.      * @return the current spinner value
  495.      * @see #setCurrent
  496.      */
  497.     public int getCurrent()
  498.     {
  499.         return (current);
  500.     }
  501.  
  502.     /**
  503.      * Sets whether the spinner buttons will continually post notify events
  504.      * while pressed.
  505.      * @param f true = send messages; false = do not send messages
  506.      * @see #isNotifyWhilePressed
  507.      * @see #setDelay
  508.      * @see #getDelay
  509.      *
  510.      * @exception PropertyVetoException
  511.      * if the specified property value is unacceptable
  512.      */
  513.     public void setNotifyWhilePressed(boolean f)
  514.         throws PropertyVetoException
  515.     {
  516.         if(f != buttons.getNotifyWhilePressed())
  517.         {
  518.             Boolean oldValue;
  519.             Boolean newValue;
  520.  
  521.             oldValue = new Boolean(getNotifyWhilePressed());
  522.             newValue = new Boolean(f);
  523.             vetos.fireVetoableChange("notifyWhilePressed", oldValue, newValue);
  524.             buttons.setNotifyWhilePressed(f);
  525.             changes.firePropertyChange("notifyWhilePressed", oldValue, newValue);
  526.         }
  527.     }
  528.  
  529.     /**
  530.      * Gets the current notifyWhilePressed status.
  531.      * @return true if notify events posted while pressed, false otherwise
  532.      * @see #setNotifyWhilePressed
  533.      * @see #setDelay
  534.      * @see #getDelay
  535.      */
  536.     public boolean isNotifyWhilePressed()
  537.     {
  538.         return (buttons.isNotifyWhilePressed());
  539.     }
  540.  
  541.     /**
  542.      * @deprecated
  543.      * @see #isNotifyWhilePressed
  544.      */
  545.     public boolean getNotifyWhilePressed()
  546.     {
  547.         return isNotifyWhilePressed();
  548.     }
  549.  
  550.     /**
  551.      * Sets the notification event delay of the spinner buttons in milliseconds.
  552.      * @param d the delay between notification events in milliseconds
  553.      * @see #setNotifyWhilePressed
  554.      * @see #getDelay
  555.      *
  556.      * @exception PropertyVetoException
  557.      * if the specified property value is unacceptable
  558.      */
  559.     public void setDelay(int d) throws PropertyVetoException
  560.     {
  561.         if(d != buttons.getDelay())
  562.         {
  563.             Integer oldValue;
  564.             Integer newValue;
  565.  
  566.             oldValue = new Integer(buttons.getDelay());
  567.             newValue = new Integer(d);
  568.  
  569.             vetos.fireVetoableChange("delay", oldValue, newValue);
  570.             buttons.setDelay(d);
  571.             changes.firePropertyChange("delay", oldValue, newValue);
  572.         }
  573.     }
  574.  
  575.     /**
  576.      * Returns the current delay between notification events of the spinner
  577.      * buttons in milliseconds.
  578.      * @see #setNotifyWhilePressed
  579.      * @see #setDelay
  580.      */
  581.     public int getDelay()
  582.     {
  583.         return buttons.getDelay();
  584.     }
  585.  
  586.     /**
  587.      * Returns the text that is in the entry TextField.
  588.      */
  589.     public String getEntryFieldText()
  590.     {
  591.         return (textFld.getText());
  592.     }
  593.  
  594.     /**
  595.      * Takes no action.
  596.      * This is a standard Java AWT method which gets called to specify
  597.      * which layout manager should be used to layout the components in
  598.      * standard containers.
  599.      *
  600.      * Since layout managers CANNOT BE USED with this container the standard
  601.      * setLayout has been OVERRIDDEN for this container and does nothing.
  602.      *
  603.      * @param l the layout manager to use to layout this container's components
  604.      * (IGNORED)
  605.      * @see java.awt.Container#getLayout
  606.      **/
  607.     public void setLayout(LayoutManager lm)
  608.     {
  609.     }
  610.  
  611.     /**
  612.      * Tells this component that it has been added to a container.
  613.      * This is a standard Java AWT method which gets called by the AWT when
  614.      * this component is added to a container. Typically, it is used to
  615.      * create this component's peer.
  616.      *
  617.      * It has been overridden here to hook-up event listeners.
  618.      * It is also used to setup the component, creating the TextField as needed.
  619.      *
  620.      * @see #removeNotify
  621.      */
  622.     public synchronized void addNotify()
  623.     {
  624.         super.addNotify();
  625.         added = true;
  626.         
  627.         try
  628.         {
  629.             errors = ResourceBundle.getBundle("symantec.itools.resources.ErrorsBundle");
  630.         }
  631.         catch(Throwable ex)
  632.         {
  633.             errors = new symantec.itools.resources.ErrorsBundle();
  634.         }
  635.  
  636.         //Hook up listeners
  637.         if(action == null)
  638.         {
  639.             action = new Action();
  640.             buttons.addActionListener(action);
  641.             textFld.addActionListener(action);
  642.         }
  643.  
  644.         if(currentVeto == null)
  645.         {
  646.             currentVeto = new CurrentVeto();
  647.             addCurrentListener(currentVeto);
  648.         }
  649.  
  650.         if(maxVeto == null)
  651.         {
  652.             maxVeto = new MaxVeto();
  653.             addMaxListener(maxVeto);
  654.         }
  655.  
  656.         if(minVeto == null)
  657.         {
  658.             minVeto = new MinVeto();
  659.             addMinListener(minVeto);
  660.         }
  661.  
  662.         updateText(true);
  663.     }
  664.  
  665.     /**
  666.      * Tells this component that it is being removed from a container.
  667.      * This is a standard Java AWT method which gets called by the AWT when
  668.      * this component is removed from a container. Typically, it is used to
  669.      * destroy the peers of this component and all its subcomponents.
  670.      *
  671.      * It has been overridden here to unhook event listeners.
  672.      *
  673.      * @see #addNotify
  674.      */
  675.     public synchronized void removeNotify()
  676.     {
  677.         //Unhook listeners
  678.         if(action != null)
  679.         {
  680.             textFld.removeActionListener(action);
  681.             buttons.removeActionListener(action);
  682.             action = null;
  683.         }
  684.  
  685.         if(currentVeto != null)
  686.         {
  687.             removeCurrentListener(currentVeto);
  688.             currentVeto = null;
  689.         }
  690.  
  691.         if(maxVeto != null)
  692.         {
  693.             removeMaxListener(maxVeto);
  694.             maxVeto = null;
  695.         }
  696.  
  697.         if(minVeto != null)
  698.         {
  699.             removeMinListener(minVeto);
  700.             minVeto = null;
  701.         }
  702.  
  703.         super.removeNotify();
  704.     }
  705.  
  706.       /**
  707.      * Adds the specified action listener to receive action events
  708.      * from this button.
  709.      * @param l the action listener
  710.      */
  711.     public synchronized void addActionListener(ActionListener l)
  712.     {
  713.         actionListener = AWTEventMulticaster.add(actionListener, l);
  714.     }
  715.  
  716.     /**
  717.      * Removes the specified action listener so it no longer receives
  718.      * action events from this component.
  719.      * @param l the action listener
  720.      */
  721.     public synchronized void removeActionListener(ActionListener l)
  722.     {
  723.         actionListener = AWTEventMulticaster.remove(actionListener, l);
  724.     }
  725.  
  726.     /**
  727.      * Adds a listener for all property change events.
  728.      * @param listener the listener to add
  729.      * @see #removePropertyChangeListener
  730.      */
  731.     public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
  732.     {
  733.         changes.addPropertyChangeListener(listener);
  734.     }
  735.  
  736.     /**
  737.      * Removes a listener for all property change events.
  738.      * @param listener the listener to remove
  739.      * @see #addPropertyChangeListener
  740.      */
  741.     public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
  742.     {
  743.         changes.removePropertyChangeListener(listener);
  744.     }
  745.  
  746.     /**
  747.      * Adds a listener for all vetoable property change events.
  748.      * @param listener the listener to add
  749.      * @see #removeVetoableChangeListener
  750.      */
  751.     public synchronized void addVetoableChangeListener(VetoableChangeListener listener)
  752.     {
  753.         vetos.addVetoableChangeListener(listener);
  754.     }
  755.  
  756.     /**
  757.      * Removes a listener for all vetoable property change events.
  758.      * @param listener the listener to remove
  759.      * @see #addVetoableChangeListener
  760.      */
  761.     public synchronized void removeVetoableChangeListener(VetoableChangeListener listener)
  762.     {
  763.         vetos.removeVetoableChangeListener(listener);
  764.     }
  765.  
  766.     /**
  767.      * Adds a listener for the current property changes.
  768.      * @param listener the listener to add.
  769.      * @see #removeCurrentListener(java.beans.PropertyChangeListener)
  770.      */
  771.     public synchronized void addCurrentListener(PropertyChangeListener listener)
  772.     {
  773.         changes.addPropertyChangeListener("current", listener);
  774.     }
  775.  
  776.     /**
  777.      * Removes a listener for the current property changes.
  778.      * @param listener the listener to remove.
  779.      * @see #addCurrentListener(java.beans.PropertyChangeListener)
  780.      */
  781.     public synchronized void removeCurrentListener(PropertyChangeListener listener)
  782.     {
  783.         changes.removePropertyChangeListener("current", listener);
  784.     }
  785.  
  786.     /**
  787.      * Adds a vetoable listener for the current property changes.
  788.      * @param listener the listener to add.
  789.      * @see #removeCurrentListener(java.beans.VetoableChangeListener)
  790.      */
  791.     public synchronized void addCurrentListener(VetoableChangeListener listener)
  792.     {
  793.         vetos.addVetoableChangeListener("current", listener);
  794.     }
  795.  
  796.     /**
  797.      * Removes a vetoable listener for the current property changes.
  798.      * @param listener the listener to remove.
  799.      * @see #addCurrentListener(java.beans.VetoableChangeListener)
  800.      */
  801.     public synchronized void removeCurrentListener(VetoableChangeListener listener)
  802.     {
  803.         vetos.removeVetoableChangeListener("current", listener);
  804.     }
  805.  
  806.     /**
  807.      * Adds a listener for the max property changes.
  808.      * @param listener the listener to add.
  809.      * @see #removeMaxListener(java.beans.PropertyChangeListener)
  810.      */
  811.     public synchronized void addMaxListener(PropertyChangeListener listener)
  812.     {
  813.         changes.addPropertyChangeListener("max", listener);
  814.     }
  815.  
  816.     /**
  817.      * Removes a listener for the max property changes.
  818.      * @param listener the listener to remove.
  819.      * @see #addMaxListener(java.beans.PropertyChangeListener)
  820.      */
  821.     public synchronized void removeMaxListener(PropertyChangeListener listener)
  822.     {
  823.         changes.removePropertyChangeListener("max", listener);
  824.     }
  825.  
  826.     /**
  827.      * Adds a vetoable listener for the max property changes.
  828.      * @param listener the listener to add.
  829.      * @see #removeMaxListener(java.beans.VetoableChangeListener)
  830.      */
  831.     public synchronized void addMaxListener(VetoableChangeListener listener)
  832.     {
  833.         vetos.addVetoableChangeListener("max", listener);
  834.     }
  835.  
  836.     /**
  837.      * Removes a vetoable listener for the max property changes.
  838.      * @param listener the listener to remove.
  839.      * @see #addMaxListener(java.beans.VetoableChangeListener)
  840.      */
  841.     public synchronized void removeMaxListener(VetoableChangeListener listener)
  842.     {
  843.         vetos.removeVetoableChangeListener("max", listener);
  844.     }
  845.  
  846.     /**
  847.      * Adds a listener for the min property changes.
  848.      * @param listener the listener to add.
  849.      * @see #removeMinListener(java.beans.PropertyChangeListener)
  850.      */
  851.     public synchronized void addMinListener(PropertyChangeListener listener)
  852.     {
  853.         changes.addPropertyChangeListener("min", listener);
  854.     }
  855.  
  856.     /**
  857.      * Removes a listener for the min property changes.
  858.      * @param listener the listener to remove.
  859.      * @see #addMinListener(java.beans.PropertyChangeListener)
  860.      */
  861.     public synchronized void removeMinListener(PropertyChangeListener listener)
  862.     {
  863.         changes.removePropertyChangeListener("min", listener);
  864.     }
  865.  
  866.     /**
  867.      * Adds a vetoable listener for the min property changes.
  868.      * @param listener the listener to add.
  869.      * @see #removeMinListener(java.beans.VetoableChangeListener)
  870.      */
  871.     public synchronized void addMinListener(VetoableChangeListener listener)
  872.     {
  873.         vetos.addVetoableChangeListener("min", listener);
  874.     }
  875.  
  876.     /**
  877.      * Removes a vetoable listener for the min property changes.
  878.      * @param listener the listener to remove.
  879.      * @see #addMinListener(java.beans.VetoableChangeListener)
  880.      */
  881.     public synchronized void removeMinListener(VetoableChangeListener listener)
  882.     {
  883.         vetos.removeVetoableChangeListener("min", listener);
  884.     }
  885.  
  886.     /**
  887.      * Is the given value valid for the Current property .
  888.      * @param i the given value
  889.      * @return true if the given value is acceptable, false if not.
  890.      */
  891.     protected boolean isValidCurrentValue(int i)
  892.     {
  893.         if (i > max || i < min)
  894.             return false;
  895.         else
  896.             return true;
  897.     }
  898.  
  899.     /**
  900.      * Is the given value valid for the Max property .
  901.      * @param i the given value
  902.      * @return true if the given value is acceptable, false if not.
  903.      */
  904.     protected boolean isValidMaxValue(int i)
  905.     {
  906.         return (i >= min);
  907.     }
  908.  
  909.     /**
  910.      * Is the given value valid for the Min property .
  911.      * @param i the given value
  912.      * @return true if the given value is acceptable, false if not.
  913.      */
  914.     protected boolean isValidMinValue(int i)
  915.     {
  916.         return (i <= max);
  917.     }
  918.  
  919.     /**
  920.     * Fire an action event to the listeners
  921.     */
  922.     protected void sourceActionEvent( String s)
  923.     {
  924.         if (actionListener != null)
  925.             actionListener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, s));
  926.     }
  927.  
  928.     /**
  929.      * Increments the spinner's value and handles wrapping as needed.
  930.      * @see #scrollDown
  931.      * @see #increment
  932.      */
  933.     protected void scrollUp()
  934.     {
  935.         try
  936.         {
  937.             setCurrent(current + increment);
  938.         }
  939.         catch (PropertyVetoException exc)
  940.         {
  941.             if(wrappable)
  942.             {
  943.                 try { setCurrent(min); } catch (PropertyVetoException ex) {}
  944.             }
  945.             else
  946.             {
  947.                 try { setCurrent(max); } catch (PropertyVetoException ex) {}
  948.             }
  949.         }
  950.  
  951.         updateText(false);
  952.     }
  953.  
  954.     /**
  955.      * Decrements the spinner's value and handles wrapping as needed.
  956.      * @see #scrollUp
  957.      * @see #increment
  958.      */
  959.     protected void scrollDown()
  960.     {
  961.         try
  962.         {
  963.             setCurrent(current - increment);
  964.         }
  965.         catch (PropertyVetoException exc)
  966.         {
  967.             if (wrappable)
  968.             {
  969.                 try { setCurrent(max); } catch (PropertyVetoException exc1) {}
  970.             }
  971.             else
  972.             {
  973.                 try { setCurrent(min); } catch (PropertyVetoException exc1) {}
  974.             }
  975.         }
  976.  
  977.         updateText(false);
  978.     }
  979.  
  980.     /**
  981.      * Updates the text field with the current text, as needed or depending on the force flag.
  982.      * @param force If true, causes the text field to update even if the value has not changed.
  983.      * @see #updateText()
  984.      * @see #getCurrentText
  985.      */
  986.     protected void updateText(boolean force)
  987.     {
  988.         String currentText;
  989.  
  990.         currentText = getCurrentText();
  991.  
  992.         //If the text has changed, put the new text into the text field
  993.         if(force || !textFld.getText().equals(currentText))
  994.         {
  995.               textFld.setText(currentText);
  996.         }
  997.     }
  998.  
  999.     /**
  1000.      * Handles enabling or disabling the spinner buttons as needed.
  1001.      */
  1002.     protected void updateButtonStatus()
  1003.     {
  1004.         if(buttons != null)
  1005.         {
  1006.             if(wrappable)
  1007.             {
  1008.                 buttons.setUpButtonEnabled(true);
  1009.                 buttons.setDownButtonEnabled(true);
  1010.             }
  1011.             else
  1012.             {
  1013.                 if(current == max && current == min)
  1014.                 {
  1015.                     buttons.setUpButtonEnabled(false);
  1016.                     buttons.setDownButtonEnabled(false);
  1017.                 }
  1018.                 else if(current == max)
  1019.                 {
  1020.                     buttons.setUpButtonEnabled(false);
  1021.                     buttons.setDownButtonEnabled(true);
  1022.                 }
  1023.                 else if(current == min)
  1024.                 {
  1025.                     buttons.setUpButtonEnabled(true);
  1026.                     buttons.setDownButtonEnabled(false);
  1027.                 }
  1028.                 else
  1029.                 {
  1030.                     buttons.setUpButtonEnabled(true);
  1031.                     buttons.setDownButtonEnabled(true);
  1032.                 }
  1033.             }
  1034.         }
  1035.     }
  1036.  
  1037.     /**
  1038.      * Gets the currently selected string from the list.
  1039.      * @return the string currently visible in the Spinner
  1040.      * @see #updateText
  1041.      */
  1042.     protected abstract String getCurrentText();
  1043. }