This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[FYI] patch to enable basic swing buttons


hi,

I've just committed the following patch, which includes several bits of work which have been independenty approved at various times in the past, reworked slightly (mostly just javadoc'd) to conform to suggestions made on approval. it represents my best current understanding and working implementation of swing buttons. it draws and interacts with the mouse under both the cairo and plain gdk graphics implementations, depending on which system property you run it with.

the cairo version does not currently draw button-label strings perfectly (I had thought this was predicated on my previous patch to attributed strings, but the gdk version draws OK, so I'll have to investigate further). however, the basic work is there and the structure should, I hope, serve as a bit of a reference for further widget development.

further refinements and tests will be forthcoming, I just wanted to put a checkpoint of the work in for others to monitor.

-graydon

2004-01-22  Graydon Hoare  <graydon@redhat.com>
	
	* gnu/java/awt/peer/gtk/GdkClasspathFontPeer.java:
	* gnu/java/awt/peer/gtk/GdkGlyphVector.java:
	Predicate static initialization on GtkToolkit.useGraphics2D().
	* java/awt/Component.java (processPaintEvent): Consume event.
	* javax/swing/AbstractButton.java: Reimplement, document.
	* javax/swing/DefaultButtonModel.java: Reimplement, document.
	* javax/swing/JComponent.java (paint): Use double buffer.
	(listenerList): Enable member.
	* javax/swing/ToggleButtonModel.java: Remove incorrect constructor.
	* javax/swing/JToggleButton.java
	(JToggleButton): Modify model constructor.
	* javax/swing/SwingUtilities.java
	(layoutCompoundLabel): Adjust arithmetic.
	* javax/swing/plaf/basic/BasicButtonUI.java: Reimplement, document.
	* javax/swing/plaf/basic/BasicGraphicsUtils.java
	(getPreferredButtonSize): Include margins in calculation.
	* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c
	(Java_gnu_java_awt_peer_gtk_GtkWindowPeer_connectSignals):
	Receive up events from subordinate layout component.
Index: gnu/java/awt/peer/gtk/GdkClasspathFontPeer.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/awt/peer/gtk/GdkClasspathFontPeer.java,v
retrieving revision 1.2
diff -u -b -w -r1.2 GdkClasspathFontPeer.java
--- gnu/java/awt/peer/gtk/GdkClasspathFontPeer.java	20 Nov 2003 22:44:01 -0000	1.2
+++ gnu/java/awt/peer/gtk/GdkClasspathFontPeer.java	22 Jan 2004 09:53:45 -0000
@@ -70,6 +70,8 @@
       {
         System.loadLibrary("gtkpeer");
       }
+
+    if (GtkToolkit.useGraphics2D ())
     initStaticState ();
   }
   native static void initStaticState ();
Index: gnu/java/awt/peer/gtk/GdkGlyphVector.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/awt/peer/gtk/GdkGlyphVector.java,v
retrieving revision 1.1
diff -u -b -w -r1.1 GdkGlyphVector.java
--- gnu/java/awt/peer/gtk/GdkGlyphVector.java	25 Oct 2003 18:41:45 -0000	1.1
+++ gnu/java/awt/peer/gtk/GdkGlyphVector.java	22 Jan 2004 09:53:45 -0000
@@ -60,6 +60,8 @@
       {
         System.loadLibrary("gtkpeer");
       }
+
+    if (GtkToolkit.useGraphics2D ())
     initStaticState ();
   }
   native static void initStaticState ();
Index: java/awt/Component.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/Component.java,v
retrieving revision 1.32
diff -u -b -w -r1.32 Component.java
--- java/awt/Component.java	22 Jan 2004 00:22:27 -0000	1.32
+++ java/awt/Component.java	22 Jan 2004 09:53:46 -0000
@@ -4252,6 +4252,7 @@
 	  default:
 	    throw new IllegalArgumentException("unknown paint event");
 	  }
+	event.consume ();
       }
     finally
       {
Index: javax/swing/AbstractButton.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/javax/swing/AbstractButton.java,v
retrieving revision 1.3
diff -u -b -w -r1.3 AbstractButton.java
--- javax/swing/AbstractButton.java	14 Jul 2003 05:33:30 -0000	1.3
+++ javax/swing/AbstractButton.java	22 Jan 2004 09:53:46 -0000
@@ -1,5 +1,5 @@
 /* AbstractButton.java -- Provides basic button functionality.
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -35,9 +35,10 @@
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
-
 package javax.swing;
 
+import java.awt.AWTEvent;
+import java.awt.AWTEventMulticaster;
 import java.awt.Graphics;
 import java.awt.Image;
 import java.awt.Insets;
@@ -51,11 +52,15 @@
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.awt.event.MouseEvent;
+import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.io.Serializable;
+import java.util.Vector;
+import java.util.EventListener;
 import javax.accessibility.AccessibleAction;
 import javax.accessibility.AccessibleIcon;
-import javax.accessibility.AccessibleStateSet;
 import javax.accessibility.AccessibleRelationSet;
+import javax.accessibility.AccessibleStateSet;
 import javax.accessibility.AccessibleText;
 import javax.accessibility.AccessibleValue;
 import javax.swing.event.ChangeEvent;
@@ -63,739 +68,1734 @@
 import javax.swing.plaf.ButtonUI;
 import javax.swing.text.AttributeSet;
 
+
 /**
- * Provides basic button functionality
+ * <p>The purpose of this class is to serve as a facade over a number of
+ * classes which collectively represent the semantics of a button: the
+ * button's model, its listeners, its action, and its look and feel. Some
+ * parts of a button's state are stored explicitly in this class, other
+ * parts are delegates to the model. Some methods related to buttons are
+ * implemented in this class, other methods pass through to the current 
+ * model or look and feel.</p>
+ *
+ * <p>Furthermore this class is supposed to serve as a base class for
+ * several kinds of buttons with similar but non-identical semantics:
+ * toggle buttons (radio buttons and checkboxes), simple "push" buttons,
+ * menu items.</p>
+ *
+ * <p>Buttons have many properties, some of which are stored in this class
+ * while others are delegated to the button's model. The following properties
+ * are available:</p>
+ *
+ * <table>
+ * <tr><th>Property               </th><th>Stored in</th><th>Bound?</th></tr>
+ *
+ * <tr><td>action                 </td><td>button</td> <td>no</td></tr>
+ * <tr><td>actionCommand          </td><td>model</td>  <td>no</td></tr>
+ * <tr><td>borderPainted          </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>contentAreaFilled      </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>disabledIcon           </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>disabledSelectedIcon   </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>displayedMnemonicIndex </td><td>button</td> <td>no</td></tr>
+ * <tr><td>enabled                </td><td>model</td>  <td>no</td></tr>
+ * <tr><td>focusPainted           </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>horizontalAlignment    </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>horizontalTextPosition </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>icon                   </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>iconTextGap            </td><td>button</td> <td>no</td></tr>
+ * <tr><td>label (same as text)   </td><td>model</td>  <td>yes</td></tr>
+ * <tr><td>margin                 </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>multiClickThreshold    </td><td>button</td> <td>no</td></tr>
+ * <tr><td>pressedIcon            </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>rolloverEnabled        </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>rolloverIcon           </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>rolloverSelectedIcon   </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>selected               </td><td>model</td>  <td>no</td></tr>
+ * <tr><td>selectedIcon           </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>selectedObjects        </td><td>button</td> <td>no</td></tr>
+ * <tr><td>text                   </td><td>model</td>  <td>yes</td></tr>
+ * <tr><td>UI                     </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>verticalAlignment      </td><td>button</td> <td>yes</td></tr>
+ * <tr><td>verticalTextPosition   </td><td>button</td> <td>yes</td></tr>
+ *
+ * </table>
+ *
+ * <p>The various behavioral aspects of these properties follows:</p>
+ *
+ * <ul> 
+ *
+ * <li>When non-bound properties stored in the button change, the button
+ * fires ChangeEvents to its ChangeListeners.</li>
+ * 
+ * <li>When bound properties stored in the button change, the button fires
+ * PropertyChangeEvents to its PropertyChangeListeners</li>
+ *
+ * <li>If any of the model's properties change, it fires a ChangeEvent to
+ * its ChangeListeners, which include the button.</li>
+ *
+ * <li>If the button receives a ChangeEvent from its model, it will
+ * propagate the ChangeEvent to its ChangeListeners, with the ChangeEvent's
+ * "source" property set to refer to the button, rather than the model. The
+ * the button will request a repaint, to paint its updated state.</li>
+ *
+ * <li>If the model's "selected" property changes, the model will fire an
+ * ItemEvent to its ItemListeners, which include the button, in addition to
+ * the ChangeEvent which models the property change. The button propagates
+ * ItemEvents directly to its ItemListeners.</li>
  *
- * @author Ronald Veldema (rveldema@cs.vu.nl)
+ * <li>If the model's armed and pressed properties are simultaneously
+ * <code>true</code>, the model will fire an ActionEvent to its
+ * ActionListeners, which include the button. The button will propagate
+ * this ActionEvent to its ActionListeners, with the ActionEvent's "source"
+ * property set to refer to the button, rather than the model.</li>
+ *
+ * </ul>
+ *
+ * @author Ronald Veldema (rveldema&064;cs.vu.nl)
+ * @author Graydon Hoare (graydon&064;redhat.com)
  */
+
 public abstract class AbstractButton extends JComponent
   implements ItemSelectable, SwingConstants
 {
-  Icon default_icon, pressed_button, disabled_button,
-    selected_button, disabled_selected_button, current_icon;
+  /** The icon displayed by default. */
+  Icon default_icon;
+
+  /** The icon displayed when the button is pressed. */
+  Icon pressed_icon;
+
+  /** The icon displayed when the button is disabled. */
+  Icon disabled_icon;
+
+  /** The icon displayed when the button is selected. */
+  Icon selected_icon;
+
+  /** The icon displayed when the button is selected but disabled. */
+  Icon disabled_selected_icon;
+
+  /** The icon displayed when the button is rolled over. */
+  Icon rollover_icon;
+
+  /** The icon displayed when the button is selected and rolled over. */
+  Icon rollover_selected_icon;
+
+  /** The icon currently displayed. */
+  Icon current_icon;
+
+  /** The text displayed in the button. */
   String text;
 
+  /** The vertical alignment of the button's text and icon. */
   int vert_align = CENTER;
+
+  /** The horizontal alignment of the button's text and icon. */
   int hori_align = CENTER;
+
+  /** The horizontal position of the button's text relative to its icon. */
   int hori_text_pos = CENTER;
+
+  /** The vertical position of the button's text relative to its icon. */
   int vert_text_pos = CENTER;
 
-  boolean paint_border = true, paint_focus;
-  Action action_taken;
+  /** Whether or not the button paints its border. */
+  boolean paint_border = true;
+
+  /** Whether or not the button paints its focus state. */
+  boolean paint_focus;
+
+  /** Whether or not the button fills its content area. */
+  boolean content_area_filled;
+
+  /** The action taken when the button is clicked. */
+  Action action;
+
+  /** The button's current state. */
   ButtonModel model;
+
+  /** The margin between the button's border and its label. */
   Insets margin;
 
-  public static final String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
+  /** a hint to the look and feel class, suggesting which character in the
+   * button's label should be underlined when drawing the label. */
+  int mnemonicIndex;
 
-  /**
-   * AccessibleAbstractButton
-   */
-  protected abstract class AccessibleAbstractButton 
-    extends AccessibleJComponent 
-    implements AccessibleAction, AccessibleValue, AccessibleText {
+  /** Listener the button uses to receive ActionEvents from its model.  */
+  ActionListener actionListener;
 
-    /**
-     * Constructor AccessibleAbstractButton
-     * @param component TODO
-     */
-    protected AccessibleAbstractButton(AbstractButton component) {
-      super(component);
-      // TODO
-    } // AccessibleAbstractButton()
+  /** Listener the button uses to receive ItemEvents from its model.  */
+  ItemListener itemListener;
+
+  /** Listener the button uses to receive ChangeEvents from its model.  */  
+  ChangeListener changeListener;
+
+  /** Listener the button uses to receive PropertyChangeEvents from its
+      Action. */
+  PropertyChangeListener actionPropertyChangeListener;
+  
+  /** Fired in a PropertyChangeEvent when the "borderPainted" property changes. */
+  public static String BORDER_PAINTED_CHANGED_PROPERTY = "borderPainted";
+  
+  /** Fired in a PropertyChangeEvent when the "contentAreaFilled" property changes. */
+  public static String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled";
+  
+  /** Fired in a PropertyChangeEvent when the "disabledIcon" property changes. */
+  public static String DISABLED_ICON_CHANGED_PROPERTY = "disabledIcon";
+  
+  /** Fired in a PropertyChangeEvent when the "disabledSelectedIcon" property changes. */
+  public static String DISABLED_SELECTED_ICON_CHANGED_PROPERTY = "disabledSelectedIcon";
+  
+  /** Fired in a PropertyChangeEvent when the "focusPainted" property changes. */
+  public static String FOCUS_PAINTED_CHANGED_PROPERTY = "focusPainted";
+
+  /** Fired in a PropertyChangeEvent when the "horizontalAlignment" property changes. */
+  public static String HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY = "horizontalAlignment";
+
+  /** Fired in a PropertyChangeEvent when the "horizontalTextPosition" property changes. */
+  public static String HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY = "horizontalTextPosition";
+
+  /** Fired in a PropertyChangeEvent when the "icon" property changes. */
+  public static String ICON_CHANGED_PROPERTY = "icon";
+
+  /** Fired in a PropertyChangeEvent when the "margin" property changes. */
+  public static String MARGIN_CHANGED_PROPERTY = "margin";
+
+  /** Fired in a PropertyChangeEvent when the "mnemonic" property changes. */
+  public static String MNEMONIC_CHANGED_PROPERTY = "mnemonic";
+
+  /** Fired in a PropertyChangeEvent when the "model" property changes. */
+  public static String MODEL_CHANGED_PROPERTY = "model";
+
+  /** Fired in a PropertyChangeEvent when the "pressedIcon" property changes. */
+  public static String PRESSED_ICON_CHANGED_PROPERTY = "pressedIcon";
+
+  /** Fired in a PropertyChangeEvent when the "rolloverEnabled" property changes. */
+  public static String ROLLOVER_ENABLED_CHANGED_PROPERTY = "rolloverEnabled";
+
+  /** Fired in a PropertyChangeEvent when the "rolloverIcon" property changes. */
+  public static String ROLLOVER_ICON_CHANGED_PROPERTY = "rolloverIcon";
+  
+  /** Fired in a PropertyChangeEvent when the "rolloverSelectedIcon" property changes. */
+  public static String ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY = "rolloverSelectedIcon";
+  
+  /** Fired in a PropertyChangeEvent when the "selectedIcon" property changes. */
+  public static String SELECTED_ICON_CHANGED_PROPERTY = "selectedIcon";
+
+  /** Fired in a PropertyChangeEvent when the "text" property changes. */
+  public static String TEXT_CHANGED_PROPERTY = "text";
+
+  /** Fired in a PropertyChangeEvent when the "verticalAlignment" property changes. */
+  public static String VERTICAL_ALIGNMENT_CHANGED_PROPERTY = "verticalAlignment";
+
+  /** Fired in a PropertyChangeEvent when the "verticalTextPosition" property changes. */
+  public static String VERTICAL_TEXT_POSITION_CHANGED_PROPERTY = "verticalTextPosition";
 
     /**
-     * getAccessibleStateSet
-     * @returns AccessibleStateSet
+   * A Java Accessibility extension of the AbstractButton.
      */
-    public AccessibleStateSet getAccessibleStateSet() {
+  protected abstract class AccessibleAbstractButton
+    extends AccessibleJComponent implements AccessibleAction, AccessibleValue,
+                                            AccessibleText
+  {
+    protected AccessibleAbstractButton(JComponent c)
+    {
+      super(c);
+    }
+
+    public AccessibleStateSet getAccessibleStateSet()
+    {
       return null; // TODO
-    } // getAccessibleStateSet()
+    }
 
-    /**
-     * getAccessibleName
-     * @returns String
-     */
-    public String getAccessibleName() {
+    public String getAccessibleName()
+    {
       return null; // TODO
-    } // getAccessibleName()
+    }
 
-    /**
-     * getAccessibleIcon
-     * @returns AccessibleIcon[]
-     */
-    public AccessibleIcon[] getAccessibleIcon() {
+    public AccessibleIcon[] getAccessibleIcon()
+    {
       return null; // TODO
-    } // getAccessibleIcon()
+    }
 
-    /**
-     * getAccessibleRelationSet
-     * @returns AccessibleRelationSet
-     */
-    public AccessibleRelationSet getAccessibleRelationSet() {
+    public AccessibleRelationSet getAccessibleRelationSet()
+    {
       return null; // TODO
-    } // getAccessibleRelationSet()
+    }
 
-    /**
-     * getAccessibleAction
-     * @returns AccessibleAction
-     */
-    public AccessibleAction getAccessibleAction() {
+    public AccessibleAction getAccessibleAction()
+    {
       return null; // TODO
-    } // getAccessibleAction()
+    }
 
-    /**
-     * getAccessibleValue
-     * @returns AccessibleValue
-     */
-    public AccessibleValue getAccessibleValue() {
+    public AccessibleValue getAccessibleValue()
+    {
       return null; // TODO
-    } // getAccessibleValue()
+    }
 
-    /**
-     * getAccessibleActionCount
-     * @returns int
-     */
-    public int getAccessibleActionCount() {
+    public int getAccessibleActionCount()
+    {
       return 0; // TODO
-    } // getAccessibleActionCount()
+    }
 
-    /**
-     * getAccessibleActionDescription
-     * @param value0 TODO
-     * @returns String
-     */
-    public String getAccessibleActionDescription(int value0) {
+    public String getAccessibleActionDescription(int value0)
+    {
       return null; // TODO
-    } // getAccessibleActionDescription()
+    }
 
-    /**
-     * doAccessibleAction
-     * @param value0 TODO
-     * @returns boolean
-     */
-    public boolean doAccessibleAction(int value0) {
+    public boolean doAccessibleAction(int value0)
+    {
       return false; // TODO
-    } // doAccessibleAction()
+    }
 
-    /**
-     * getCurrentAccessibleValue
-     * @returns Number
-     */
-    public Number getCurrentAccessibleValue() {
+    public Number getCurrentAccessibleValue()
+    {
       return null; // TODO
-    } // getCurrentAccessibleValue()
+    }
 
-    /**
-     * setCurrentAccessibleValue
-     * @param value0 TODO
-     * @returns boolean
-     */
-    public boolean setCurrentAccessibleValue(Number value0) {
+    public boolean setCurrentAccessibleValue(Number value0)
+    {
       return false; // TODO
-    } // setCurrentAccessibleValue()
+    }
 
-    /**
-     * getMinimumAccessibleValue
-     * @returns Number
-     */
-    public Number getMinimumAccessibleValue() {
+    public Number getMinimumAccessibleValue()
+    {
       return null; // TODO
-    } // getMinimumAccessibleValue()
+    }
 
-    /**
-     * getMaximumAccessibleValue
-     * @returns Number
-     */
-    public Number getMaximumAccessibleValue() {
+    public Number getMaximumAccessibleValue()
+    {
       return null; // TODO
-    } // getMaximumAccessibleValue()
+    }
 
-    /**
-     * getAccessibleText
-     * @returns AccessibleText
-     */
-    public AccessibleText getAccessibleText() {
+    public AccessibleText getAccessibleText()
+    {
       return null; // TODO
-    } // getAccessibleText()
+    }
 
-    /**
-     * getIndexAtPoint
-     * @param value0 TODO
-     * @returns int
-     */
-    public int getIndexAtPoint(Point value0) {
+    public int getIndexAtPoint(Point value0)
+    {
       return 0; // TODO
-    } // getIndexAtPoint()
+    }
 
-    /**
-     * getCharacterBounds
-     * @param value0 TODO
-     * @returns Rectangle
-     */
-    public Rectangle getCharacterBounds(int value0) {
+    public Rectangle getCharacterBounds(int value0)
+    {
       return null; // TODO
-    } // getCharacterBounds()
+    }
 
-    /**
-     * getCharCount
-     * @returns int
-     */
-    public int getCharCount() {
+    public int getCharCount()
+    {
       return 0; // TODO
-    } // getCharCount()
+    }
 
-    /**
-     * getCaretPosition
-     * @returns int
-     */
-    public int getCaretPosition() {
+    public int getCaretPosition()
+    {
       return 0; // TODO
-    } // getCaretPosition()
+    }
 
-    /**
-     * getAtIndex
-     * @param value0 TODO
-     * @param value1 TODO
-     * @returns String
-     */
-    public String getAtIndex(int value0, int value1) {
+    public String getAtIndex(int value0, int value1)
+    {
       return null; // TODO
-    } // getAtIndex()
+    }
 
-    /**
-     * getAfterIndex
-     * @param value0 TODO
-     * @param value1 TODO
-     * @returns String
-     */
-    public String getAfterIndex(int value0, int value1) {
+    public String getAfterIndex(int value0, int value1)
+    {
       return null; // TODO
-    } // getAfterIndex()
+    }
 
-    /**
-     * getBeforeIndex
-     * @param value0 TODO
-     * @param value1 TODO
-     * @returns String
-     */
-    public String getBeforeIndex(int value0, int value1) {
+    public String getBeforeIndex(int value0, int value1)
+    {
       return null; // TODO
-    } // getBeforeIndex()
+    }
 
-    /**
-     * getCharacterAttribute
-     * @param value0 TODO
-     * @returns AttributeSet
-     */
-    public AttributeSet getCharacterAttribute(int value0) {
+    public AttributeSet getCharacterAttribute(int value0)
+    {
       return null; // TODO
-    } // getCharacterAttribute()
+    }
 
-    /**
-     * getSelectionStart
-     * @returns int
-     */
-    public int getSelectionStart() {
+    public int getSelectionStart()
+    {
       return 0; // TODO
-    } // getSelectionStart()
+    }
 
-    /**
-     * getSelectionEnd
-     * @returns int
-     */
-    public int getSelectionEnd() {
+    public int getSelectionEnd()
+    {
       return 0; // TODO
-    } // getSelectionEnd()
-
-    /**
-     * getSelectedText
-     * @returns String
-     */
-    public String getSelectedText() {
-      return null; // TODO
-    } // getSelectedText()
-
-    /**
-     * getTextRectangle
-     * @returns Rectangle
-     */
-    private Rectangle getTextRectangle() {
-      return null; // TODO
-    } // getTextRectangle()
-
-
-  } // AccessibleAbstractButton
-
+    }
 
-  static private class JFocusListener implements FocusListener
+    public String getSelectedText()
   {
-    AbstractButton c;
+      return null; // TODO
+    }
 
-    JFocusListener(AbstractButton c)
+    private Rectangle getTextRectangle()
     {
-      this.c = c;
+      return null; // TODO
+    }
     }
 
-    public void focusLost(FocusEvent event)
+  /**
+   * Helper class used to subscribe to FocusEvents received by the button.
+   */
+  private class ButtonFocusListener implements FocusListener
     {
-      c.getModel().setArmed(false);
-
-      System.out.println("LOST FOCUS");
-      if (c.isFocusPainted())
+    /**
+     * Possibly repaint the model in response to loss of focus.
+     *
+     * @param event The loss-of-focus event
+     */
+    public void focusLost(FocusEvent event)
         {
-          c.repaint();
-        }
+      if (AbstractButton.this.isFocusPainted())
+        AbstractButton.this.repaint();
     }
+
+    /**
+     * Possibly repaint the button in response to acquisition of focus.
+     *
+     * @param event The gained-focus event
+     */
     public void focusGained(FocusEvent event)
     {
-      System.out.println("GAIN FOCUS");
+      if (AbstractButton.this.isFocusPainted())
+        AbstractButton.this.repaint();
     }
   }
 
+  /**
+   * Creates a new AbstractButton object.
+   */
   AbstractButton()
   {
     this("",null);
   }
 
-  AbstractButton(String text,
-                 Icon icon)
+  /**
+   * Creates a new AbstractButton object.
+   *
+   * @param txt Value to use for the button's "text" property
+   * @param icon Value to use for the button's "defaultIcon" property
+   */
+  AbstractButton(String txt, Icon icon)
   {
-    this.text    = text;
-    setIcon(icon);
+    text = txt;
+    default_icon = icon;
+    model = new DefaultButtonModel();
+    actionListener = createActionListener();
+    changeListener = createChangeListener();
+    itemListener = createItemListener();
+
+    model.addActionListener(actionListener);
+    model.addChangeListener(changeListener);
+    model.addItemListener(itemListener);
 
     setAlignmentX(LEFT_ALIGNMENT);
     setAlignmentY(CENTER_ALIGNMENT);
-
-    addFocusListener( new JFocusListener(this) );
-
-    setModel(new DefaultButtonModel(this));
-
-    updateUI(); // get a proper ui
+    addFocusListener(new ButtonFocusListener());
+    updateUI();
   }
 
+  /**
+   * Get the model the button is currently using.
+   *
+   * @return The current model
+   */
   public ButtonModel getModel()
-  {	return model;    }
+  {
+    return model;
+  }
 
+  /**
+   * Set the model the button is currently using. This un-registers all 
+   * listeners associated with the current model, and re-registers them
+   * with the new model.
+   *
+   * @param newModel The new model
+   */
   public void setModel(ButtonModel newModel)
-  {	model = newModel;    }
+  {
+    if (newModel == model)
+      return;
 
+    if (model != null)
+      {
+        model.removeActionListener(actionListener);
+        model.removeChangeListener(changeListener);
+        model.removeItemListener(itemListener);
+      }
+    ButtonModel old = model;
+    model = newModel;
+    if (model != null)
+      {
+        model.addActionListener(actionListener);
+        model.addChangeListener(changeListener);
+        model.addItemListener(itemListener);
+      }
+    firePropertyChange(MODEL_CHANGED_PROPERTY, old, model);
+    revalidate();
+    repaint();
+  }
+
+  /**
+   * Get the action command string for this button's model.
+   *
+   * @return The current action command string from the button's model
+   */
   public String getActionCommand()
-  {	return getModel().getActionCommand();    }
+  {
+    return getModel().getActionCommand();
+  }
 
+  /**
+   * Set the action command string for this button's model.
+   *
+   * @param aCommand The new action command string to set in the button's
+   * model.
+   */
   public void setActionCommand(String aCommand)
-  {   getModel().setActionCommand(aCommand);   }
+  {
+    getModel().setActionCommand(aCommand);
+  }
 
+  /**
+   * Adds an ActionListener to the button's listener list. When the
+   * button's model is clicked it fires an ActionEvent, and these
+   * listeners will be called.
+   *
+   * @param l The new listener to add
+   */
   public void addActionListener(ActionListener l)
-  {	getModel().addActionListener(l);    }
+  {
+    listenerList.add(ActionListener.class, l);
+  }
 
+  /**
+   * Removes an ActionListener from the button's listener list.
+   *
+   * @param l The listener to remove
+   */
   public void removeActionListener(ActionListener l)
-  {	getModel().removeActionListener(l);    }
+  {
+    listenerList.remove(ActionListener.class, l);
+  }
+
+  /**
+   * Adds an ItemListener to the button's listener list. When the button's
+   * model changes state (between any of ARMED, ENABLED, PRESSED, ROLLOVER
+   * or SELECTED) it fires an ItemEvent, and these listeners will be
+   * called.
+   *
+   * @param l The new listener to add
+   */
+  public void addItemListener(ItemListener l)
+  {
+    listenerList.add(ItemListener.class, l);
+  }
+
+  /**
+   * Removes an ItemListener from the button's listener list.
+   *
+   * @param l The listener to remove
+   */
+  public void removeItemListener(ItemListener l)
+  {
+    listenerList.remove(ItemListener.class, l);
+  }
 
+  /**
+   * Adds a ChangeListener to the button's listener list. When the button's
+   * model changes any of its (non-bound) properties, these listeners will be
+   * called. 
+   *
+   * @param l The new listener to add
+   */
   public void addChangeListener(ChangeListener l)
-  {   getModel().addChangeListener(l);     }
+  {
+    listenerList.add(ChangeListener.class, l);
+  }
 
+  /**
+   * Removes a ChangeListener from the button's listener list.
+   *
+   * @param l The listener to remove
+   */
   public void removeChangeListener(ChangeListener l)
-  {  getModel().removeChangeListener(l);    }
+  {
+    listenerList.remove(ChangeListener.class, l);
+  }
 
-  public void addItemListener(ItemListener l)
-  {  getModel().addItemListener(l);    }
+  /**
+   * Calls {@link ItemListener.itemStateChanged} on each ItemListener in
+   * the button's listener list.
+   *
+   * @param e The event signifying that the button's model changed state
+   */
+  public void fireItemStateChanged(ItemEvent e)
+  {
+    EventListener[] ll = listenerList.getListeners(ItemListener.class);
+    for (int i = 0; i < ll.length; i++)
+      ((ItemListener)ll[i]).itemStateChanged(e);
+  }
 
-  public void removeItemListener(ItemListener l)
-  {  getModel().removeItemListener(l);  }
+  /**
+   * Calls {@link ActionListener.actionPerformed} on each {@link
+   * ActionListener} in the button's listener list.
+   *
+   * @param e The event signifying that the button's model was clicked
+   */
+  public void fireActionPerformed(ActionEvent e)
+  {
+    EventListener[] ll = listenerList.getListeners(ActionListener.class);
+    for (int i = 0; i < ll.length; i++)
+      ((ActionListener)ll[i]).actionPerformed(e);
+  }
 
-  public int getHorizontalAlignment()
-  {	return hori_align;    }
+  /**
+   * Calls {@link ChangeEvent.stateChanged} on each {@link ChangeListener}
+   * in the button's listener list.
+   *
+   * @param e The event signifying a change in one of the (non-bound)
+   * properties of the button's model.
+   */
+  public void fireStateChanged(ChangeEvent e)
+  {
+    EventListener[] ll = listenerList.getListeners(ChangeListener.class);
+    for (int i = 0; i < ll.length; i++)
+      ((ChangeListener)ll[i]).stateChanged(e);
+  }
 
-  public int getHorizontalTextPosition()
-  {	return hori_text_pos;    }
+  /**
+   * Get the current keyboard mnemonic value. This value corresponds to a
+   * single key code (one of the {@link java.awt.event.KeyEvent} VK_*
+   * codes) and is used to activate the button when pressed in conjunction
+   * with the "mouseless modifier" of the button's look and feel class, and
+   * when focus is in one of the button's ancestors.
+   *
+   * @return The button's current keyboard mnemonic
+   */
+  public int getMnemonic()
+  {
+    return getModel().getMnemonic();
+  }
 
-  public int getVerticalAlignment()
-  {	return vert_align;   }
+  /**
+   * Set the current keyboard mnemonic value. This value corresponds to a
+   * single key code (one of the {@link java.awt.event.KeyEvent} VK_*
+   * codes) and is used to activate the button when pressed in conjunction
+   * with the "mouseless modifier" of the button's look and feel class, and
+   * when focus is in one of the button's ancestors.
+   *
+   * @param mne A new mnemonic to use for the button
+   */
+  public void setMnemonic(char mne)
+  {
+    int old = getModel().getMnemonic();
+    getModel().setMnemonic(mne);
+    if (old != getModel().getMnemonic())
+      {
+        firePropertyChange(MNEMONIC_CHANGED_PROPERTY, old, (int) mne);        
+        revalidate();
+        repaint();
+      }
+  }
 
-  public int getVerticalTextPosition()
-  {	return vert_text_pos;  }
+  /**
+   * Set the current keyboard mnemonic value. This value corresponds to a
+   * single key code (one of the {@link java.awt.event.KeyEvent} VK_*
+   * codes) and is used to activate the button when pressed in conjunction
+   * with the "mouseless modifier" of the button's look and feel class, and
+   * when focus is in one of the button's ancestors.
+   *
+   * @param mne A new mnemonic to use for the button
+   */
+  public void setMnemonic(int mne)
+  {
+    int old = mne;
+    getModel().setMnemonic(mne);
+    if (old != getModel().getMnemonic())
+      {
+        firePropertyChange(MNEMONIC_CHANGED_PROPERTY, old, mne);
+        revalidate();
+        repaint();
+      }
+  }
 
-  protected  void fireItemStateChanged(ItemEvent event)
+  /** 
+   * Sets the button's mnemonic index. The mnemonic index is a hint to the
+   * look and feel class, suggesting which character in the button's label
+   * should be underlined when drawing the label. If the mnemonic index is
+   * -1, no mnemonic will be displayed. 
+   * 
+   * If no mnemonic index is set, the button will choose a mnemonic index
+   * by default, which will be the first occurrence of the mnemonic
+   * character in the button's text.
+   *
+   * @param index An offset into the "text" property of the button
+   * @throws IllegalArgumentException If <code>index</code> is not within the
+   * range of legal offsets for the "text" property of the button.
+   * @since 1.4
+   */
+
+  public void setDisplayedMnemonicIndex(int index)
   {
+    if (index < -1 || index >= text.length())
+      throw new IllegalArgumentException();
+    else
+      mnemonicIndex = index;
   }
   
-  protected  void fireStateChanged(ChangeEvent event)
+  /** 
+   * Get the button's mnemonic index, which is an offset into the button's
+   * "text" property.  The character specified by this offset should be
+   * underlined when the look and feel class draws this button.
+   *
+   * @return An index into the button's "text" property
+   */
+  public int getDisplayedMnemonicIndex(int index)
   {
+    return mnemonicIndex;
   }
   
-  protected void fireActionPerformed(ActionEvent event)
+
+  /**
+   * Set the "rolloverEnabled" property. When rollover is enabled, and the
+   * look and feel supports it, the button will change its icon to
+   * rollover_icon, when the mouse passes over it.
+   *
+   * @param r Whether or not to enable rollover icon changes
+   */
+  public void setRolloverEnabled(boolean r)
+  {
+    boolean old = getModel().isRollover();
+    getModel().setRollover(r);
+    if (old != getModel().isRollover())
   {
+        firePropertyChange(ROLLOVER_ENABLED_CHANGED_PROPERTY, old, r);
+        revalidate();
+        repaint();
+      }
   }
 
-  public void setVerticalAlignment(int alignment)
-  {	vert_align = alignment;    }
+  /**
+   * Returns whether or not rollover icon changes are enabled on the
+   * button.
+   *
+   * @return The state of the "rolloverEnabled" property
+   */
+  public boolean isRolloverEnabled()
+  {
+    return getModel().isRollover();
+  }
 
-  public void setHorizontalAlignment(int alignment)
-  {   hori_align = alignment;   }
+  /**
+   * Set the value of the button's "selected" property. Selection is only
+   * meaningful for toggle-type buttons (check boxes, radio buttons).
+   *
+   * @param s New value for the property
+   */
+  public void setSelected(boolean s)
+  {
+    getModel().setSelected(s);
+  }
 
-  public void setVerticalTextPosition(int textPosition)
-  {	vert_text_pos = textPosition;    }
+  /**
+   * Get the value of the button's "selected" property. Selection is only
+   * meaningful for toggle-type buttons (check boxes, radio buttons).
+   *
+   * @return The value of the property
+   */
+  public boolean isSelected()
+  {
+    return getModel().isSelected();
+  }
 
-  public void setHorizontalTextPosition(int textPosition)
-  {   hori_text_pos = textPosition;   }
+  /**
+   * Enables or disables the button. A button will neither be selectable
+   * nor preform any actions unless it is enabled.
+   *
+   * @param b Whether or not to enable the button
+   */
+  public void setEnabled(boolean b)
+  {
+    super.setEnabled(b);
+    getModel().setEnabled(b);
+  }
 
-  public int getMnemonic()
-  {	return getModel().getMnemonic();    }
+  /** 
+   * Set the horizontal alignment of the button's text and icon. The
+   * alignment is a numeric constant from {@link SwingConstants}. It must
+   * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
+   * <code>LEADING</code> or <code>TRAILING</code>.  The default is
+   * <code>RIGHT</code>.
+   * 
+   * @return The current horizontal alignment
+   */
+  public int getHorizontalAlignment()
+  {
+    return hori_align;
+  }
 
-  public void setMnemonic(char mne)
-  {	getModel().setMnemonic(mne);    }
+  /**
+   * Set the horizontal alignment of the button's text and icon. The
+   * alignment is a numeric constant from {@link SwingConstants}. It must
+   * be one of: <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
+   * <code>LEADING</code> or <code>TRAILING</code>.  The default is
+   * <code>RIGHT</code>.
+   *
+   * @param a The new horizontal alignment
+   * @throws IllegalArgumentException If alignment is not one of the legal
+   * constants.
+   */
+  public void setHorizontalAlignment(int a)
+  {
+    int old = hori_align;
+    hori_align = a;
+    if (old != a)
+      {
+        firePropertyChange(HORIZONTAL_ALIGNMENT_CHANGED_PROPERTY, old, a);
+        revalidate();
+        repaint();
+      }
+  }
 
-  public void setMnemonic(int mne)
-  {	getModel().setMnemonic(mne);    }
+  /**
+   * Get the horizontal position of the button's text relative to its
+   * icon. The position is a numeric constant from {@link
+   * SwingConstants}. It must be one of: <code>RIGHT</code>,
+   * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or
+   * <code>TRAILING</code>.  The default is <code>TRAILING</code>.
+   *
+   * @return The current horizontal text position
+   */
+  public int getHorizontalTextPosition()
+  {
+    return hori_text_pos;
+  }
 
-  public void setRolloverEnabled(boolean b)
-  {    getModel().setRollover(b);    }
+  /**
+   * Set the horizontal position of the button's text relative to its
+   * icon. The position is a numeric constant from {@link
+   * SwingConstants}. It must be one of: <code>RIGHT</code>,
+   * <code>LEFT</code>, <code>CENTER</code>, <code>LEADING</code> or
+   * <code>TRAILING</code>. The default is <code>TRAILING</code>.
+   *
+   * @param t The new horizontal text position
+   * @throws IllegalArgumentException If position is not one of the legal
+   * constants.
+   */
+  public void setHorizontalTextPosition(int t)
+  {
+    int old = hori_text_pos;
+    hori_text_pos = t;
+    if (old != t)
+      {
+        firePropertyChange(HORIZONTAL_TEXT_POSITION_CHANGED_PROPERTY, old, t);
+        revalidate();
+        repaint();
+      }
+  }
 
-  public boolean isRolloverEnabled()
-  {    return getModel().isRollover();     }
+  /**
+   * Get the vertical alignment of the button's text and icon. The
+   * alignment is a numeric constant from {@link SwingConstants}. It must
+   * be one of: <code>CENTER</code>, <code>TOP</code>, or
+   * <code>BOTTOM</code>. The default is <code>CENTER</code>.
+   *
+   * @return The current vertical alignment
+   */
+  public int getVerticalAlignment()
+  {
+    return vert_align;
+  }
 
+  /**
+   * Set the vertical alignment of the button's text and icon. The
+   * alignment is a numeric constant from {@link SwingConstants}. It must
+   * be one of: <code>CENTER</code>, <code>TOP</code>, or
+   * <code>BOTTOM</code>. The default is <code>CENTER</code>.
+   *
+   * @param a The new vertical alignment
+   * @throws IllegalArgumentException If alignment is not one of the legal
+   * constants.
+   */
+  public void setVerticalAlignment(int a)
+  {
+    int old = vert_align;
+    vert_align = a;
+    if (old != a)
+      {
+        firePropertyChange(VERTICAL_ALIGNMENT_CHANGED_PROPERTY, old, a);
+        revalidate();
+        repaint();
+      }
+  }
+
+  /**
+   * Get the vertical position of the button's text relative to its
+   * icon. The alignment is a numeric constant from {@link
+   * SwingConstants}. It must be one of: <code>CENTER</code>,
+   * <code>TOP</code>, or <code>BOTTOM</code>. The default is
+   * <code>CENTER</code>.
+   *
+   * @return The current vertical position
+   */
+  public int getVerticalTextPosition()
+  {
+    return vert_text_pos;
+  }
+
+  /**
+   * Set the vertical position of the button's text relative to its
+   * icon. The alignment is a numeric constant from {@link
+   * SwingConstants}. It must be one of: <code>CENTER</code>,
+   * <code>TOP</code>, or <code>BOTTOM</code>. The default is
+   * <code>CENTER</code>.
+   *
+   * @param t The new vertical position
+   * @throws IllegalArgumentException If position is not one of the legal
+   * constants.
+   */
+  public void setVerticalTextPosition(int t)
+  {
+    int old = vert_text_pos;
+    vert_text_pos = t;
+    if (old != t)
+      {
+        firePropertyChange(VERTICAL_TEXT_POSITION_CHANGED_PROPERTY, old, t);
+        revalidate();
+        repaint();
+      }
+  }
+
+  /**
+   * Set the value of the "borderPainted" property. If set to
+   * <code>false</code>, the button's look and feel class should not paint
+   * a border for the button. The default is <code>true</code>.
+   *
+   * @return The current value of the property.
+   */
   public boolean isBorderPainted()
-  {	return paint_border;    }
+  {
+    return paint_border;
+  }
 
+  /**
+   * Set the value of the "borderPainted" property. If set to
+   * <code>false</code>, the button's look and feel class should not paint
+   * a border for the button. The default is <code>true</code>.
+   *
+   * @param b The new value of the property.
+   */
   public void setBorderPainted(boolean b)
   {
-    if (b != paint_border)
-      {
+    boolean old = paint_border;
         paint_border = b;
+    if (b != old)
+      {
+        firePropertyChange(BORDER_PAINTED_CHANGED_PROPERTY, old, b);
         revalidate();
         repaint();
       }
   }
 
+  /**
+   * Get the value of the "action" property. 
+   *
+   * @return The current value of the "action" property
+   */
   public Action getAction()
-  {	return action_taken;    }
+  {
+    return action;
+  }
 
+  /**
+   * <p>Set the button's "action" property, subscribing the new action to the
+   * button, as an ActionListener, if it is not already subscribed. The old
+   * Action, if it exists, is unsubscribed, and the button is unsubscribed
+   * from the old Action if it was previously subscribed as a
+   * PropertyChangeListener.</p>
+   *
+   * <p>This method also configures several of the button's properties from
+   * the Action, by calling {@link configurePropertiesFromAction}, and
+   * subscribes the button to the Action as a PropertyChangeListener.
+   * Subsequent changes to the Action will thus reconfigure the button 
+   * automatically.</p>
+   *
+   * @param a The new value of the "action" property
+   */
   public void setAction(Action a)
   {
-    action_taken = a;
-    revalidate();
-    repaint();
+    if (action != null)
+      {
+        action.removePropertyChangeListener(actionPropertyChangeListener);
+        removeActionListener(action);
+        if (actionPropertyChangeListener != null)
+          {
+            action.removePropertyChangeListener(actionPropertyChangeListener);
+            actionPropertyChangeListener = null;
+          }
+        actionPropertyChangeListener = createActionPropertyChangeListener(a);
   }
 
-  public void setSelected(boolean b)
-  {	getModel().setSelected(b);    }
+    Action old = action;
+    action = a;
+    configurePropertiesFromAction(action);
 
-  public boolean isSelected()
-  {	return getModel().isSelected();     }
+    if (action != null)
+      {
+        action.addPropertyChangeListener(actionPropertyChangeListener);
+        addActionListener(action);
+      }
+  }
 
+  /**
+   * Return the button's default "icon" property.
+   *
+   * @return The current default icon
+   */
   public Icon getIcon()
-  {	return default_icon;    }
-
-  public void setIcon(Icon defaultIcon)
   {
-    if (default_icon == defaultIcon)
-      return;
+    return default_icon;
+  }
 
-    default_icon = defaultIcon;
-    if (default_icon != null)
+  /**
+   * Set the button's default "icon" property. This icon is used as a basis
+   * for the pressed and disabled icons, if none are explicitly set.
+   *
+   * @param i The new default icon
+   */
+  public void setIcon(Icon i)
       {
-        // XXX FIXME - icons do not know their parent
-        //  			default_icon.setParent(this);
-      }
+    Icon old = default_icon;
+    default_icon = i;
+    if (old != i)
+      {
+        firePropertyChange(ICON_CHANGED_PROPERTY, old, i);
     revalidate();
     repaint();
   }
+  }
 
+  /**
+   * Return the button's "text" property. This property is synonymous with
+   * the "label" property.
+   *
+   * @return The current "text" property
+   */
   public String getText()
-  {	return text;    }
+  {
+    return text;
+  }
 
+  /**
+   * Set the button's "label" property. This property is synonymous with the
+   * "text" property.
+   *
+   * @param label The new "label" property
+   */
   public void setLabel(String label)
-  {	setText(label);    }
+  {
+    setText(label);
+  }
 
+  /**
+   * Return the button's "label" property. This property is synonymous with
+   * the "text" property.
+   *
+   * @return The current "label" property
+   */
   public String getLabel()
-  {	return getText();    }
+  {
+    return getText();
+  }
 
-  public void setText(String text)
+  /**
+   * Set the button's "text" property. This property is synonymous with the
+   * "label" property.
+   *
+   * @param t The new "text" property
+   */
+  public void setText(String t)
   {
-    this.text = text;
+    String old = text;
+    text = t;
+    if (t != old)
+      {
+        firePropertyChange(TEXT_CHANGED_PROPERTY, old, t);
     revalidate();
     repaint();
   }
+  }
 
+  /**
+   * Return the button's "margin" property, which is an {@link Insets} object
+   * describing the distance between the button's border and its text and
+   * icon.
+   *
+   * @return The current "margin" property
+   */
   public 	Insets getMargin()
-  {      return margin; }
-
-  public void setMargin(Insets m)
   {
-    margin = m;
-    revalidate();
-    repaint();
+    return margin;
   }
 
-  public void setEnabled(boolean b)
+  /**
+   * Set the button's "margin" property, which is an {@link Insets} object
+   * describing the distance between the button's border and its text and
+   * icon.
+   *
+   * @param m The new "margin" property
+   */
+  public void setMargin(Insets m)
   {
-    super.setEnabled(b);
-    getModel().setEnabled(b);
+    Insets old = margin;
+    margin = m;
+    if (m != old)
+      {
+        firePropertyChange(MARGIN_CHANGED_PROPERTY, old, m);
+        revalidate();
     repaint();
   }
+  }
 
+  /**
+   * Return the button's "pressedIcon" property. The look and feel class
+   * should paint this icon when the "pressed" property of the button's
+   * {@link ButtonModel} is <code>true</code>. This property may be
+   * <code>null</code>, in which case the default icon is used.
+   *
+   * @return The current "pressedIcon" property
+   */
   public Icon getPressedIcon()
-  {	return pressed_button;    }
+  {
+    return pressed_icon;
+  }
 
+  /**
+   * Set the button's "pressedIcon" property. The look and feel class
+   * should paint this icon when the "pressed" property of the button's
+   * {@link ButtonModel} is <code>true</code>. This property may be
+   * <code>null</code>, in which case the default icon is used.
+   *
+   * @param pressedIcon The new "pressedIcon" property
+   */
   public void setPressedIcon(Icon pressedIcon)
   {
-    pressed_button = pressedIcon;
+    Icon old = pressed_icon;
+    pressed_icon = pressedIcon;
+    if (pressed_icon != old)
+      {
+        firePropertyChange(PRESSED_ICON_CHANGED_PROPERTY, old, pressed_icon);
     revalidate();
     repaint();
   }
+  }
 
+  /**
+   * Return the button's "disabledIcon" property. The look and feel class
+   * should paint this icon when the "enabled" property of the button's
+   * {@link ButtonModel} is <code>false</code>. This property may be
+   * <code>null</code>, in which case an icon is constructed, based on the
+   * default icon.
+   *
+   * @return The current "disabledIcon" property
+   */
   public Icon getDisabledIcon()
-  {	return disabled_button;    }
+  {
+    return disabled_icon;
+  }
 
+  /**
+   * Set the button's "disabledIcon" property. The look and feel class should
+   * paint this icon when the "enabled" property of the button's {@link
+   * ButtonModel} is <code>false</code>. This property may be
+   * <code>null</code>, in which case an icon is constructed, based on the
+   * default icon.
+   *
+   * @param disabledIcon The new "disabledIcon" property
+   */
   public void setDisabledIcon(Icon disabledIcon)
   {
-    disabled_button = disabledIcon;
+    disabled_icon = disabledIcon;
     revalidate();
     repaint();
   }
 
+  /**
+   * Return the button's "paintFocus" property. This property controls
+   * whether or not the look and feel class will paint a special indicator
+   * of focus state for the button. If it is false, the button still paints
+   * when focused, but no special decoration is painted to indicate the
+   * presence of focus.
+   *
+   * @return The current "paintFocus" property
+   */
   public boolean isFocusPainted()
-  {   return paint_focus;   }
+  {
+    return paint_focus;
+  }
 
+  /**
+   * Set the button's "paintFocus" property. This property controls whether
+   * or not the look and feel class will paint a special indicator of focus
+   * state for the button. If it is false, the button still paints when
+   * focused, but no special decoration is painted to indicate the presence
+   * of focus.
+   *
+   * @param b The new "paintFocus" property
+   */
   public void setFocusPainted(boolean b)
   {
     boolean old = paint_focus;
     paint_focus = b;
 
-    firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY,
-                       old,
-                       b);
-    if (hasFocus())
+    if (old != b)
       {
+        firePropertyChange(FOCUS_PAINTED_CHANGED_PROPERTY, old, b);
         revalidate();
         repaint();
       }
   }
 
+  /**
+   * Return the button's "focusTraversable" property. This property controls
+   * whether or not the button can receive focus when the user attempts to
+   * traverse the focus hierarchy.
+   *
+   * @return The current "focusTraversable" property
+   */
   public boolean isFocusTraversable()
   {
-    //Identifies whether or not this component can receive the focus.
     return true;
   }
 
-
+  /**
+   * Verifies that a particular key is one of the valid constants used for
+   * describing horizontal alignment and positioning. The valid constants
+   * are the following members of {@link SwingConstants}:
+   * <code>RIGHT</code>, <code>LEFT</code>, <code>CENTER</code>,
+   * <code>LEADING</code> or <code>TRAILING</code>.
+   *
+   * @param key The key to check
+   * @param exception A message to include in an IllegalArgumentException
+   *
+   * @return the value of key
+   *
+   * @throws IllegalArgumentException If key is not one of the valid constants
+   *
+   * @see setHorizontalTextPosition()
+   * @see setHorizontalAlignment()
+   */
   protected  int checkHorizontalKey(int key, String exception)
   {
-    //       Verify that key is a legal value for the horizontalAlignment properties.
-    return 0;
+    switch (key)
+      {
+      case SwingConstants.RIGHT:
+      case SwingConstants.LEFT:
+      case SwingConstants.CENTER:
+      case SwingConstants.LEADING:
+      case SwingConstants.TRAILING:
+        break;
+      default:
+        throw new IllegalArgumentException(exception);
+      }
+    return key;
   }
 
+  /**
+   * Verifies that a particular key is one of the valid constants used for
+   * describing vertical alignment and positioning. The valid constants are
+   * the following members of {@link SwingConstants}: <code>TOP</code>,
+   * <code>BOTTOM</code> or <code>CENTER</code>.
+   *
+   * @param key The key to check
+   * @param exception A message to include in an IllegalArgumentException
+   *
+   * @return the value of key
+   *
+   * @throws IllegalArgumentException If key is not one of the valid constants
+   *
+   * @see setVerticalTextPosition()
+   * @see setVerticalAlignment()
+   */
   protected  int checkVerticalKey(int key, String exception)
   {
-    //       Ensures that the key is a valid.
-    return 0;
+    switch (key)
+      {
+      case SwingConstants.TOP:
+      case SwingConstants.BOTTOM:
+      case SwingConstants.CENTER:
+        break;
+      default:
+        throw new IllegalArgumentException(exception);
+      }
+    return key;
   }
 
+  /**
+   * Configure various properties of the button by reading properties
+   * of an {@link Action}. The mapping of properties is as follows:
+   *
+   * <table>
+   *
+   * <tr><th>Action keyed property</th> <th>AbstractButton property</th></tr>
+   *
+   * <tr><td>NAME                 </td> <td>text                   </td></tr>
+   * <tr><td>SMALL_ICON           </td> <td>icon                   </td></tr>
+   * <tr><td>SHORT_DESCRIPTION    </td> <td>toolTipText            </td></tr>
+   * <tr><td>MNEMONIC_KEY         </td> <td>mnemonic               </td></tr>
+   * <tr><td>ACTION_COMMAND_KEY   </td> <td>actionCommand          </td></tr>
+   *
+   * </table>
+   *
+   * <p>In addition, this method always sets the button's "enabled" property to
+   * the value of the Action's "enabled" property.</p>
+   *
+   * <p>If the provided Action is <code>null</code>, the text, icon, and
+   * toolTipText properties of the button are set to <code>null</code>, and
+   * the "enabled" property is set to <code>true</code>; the mnemonic and
+   * actionCommand properties are unchanged.</p>
+   *
+   * @param a An Action to configure the button from
+   */
   protected  void configurePropertiesFromAction(Action a)
   {
-    //Factory method which sets the ActionEvent source's properties according to values from the Action instance.
+    if (a == null)
+      {
+        setText(null);
+        setIcon(null);
+        setEnabled(true);
+        setToolTipText(null);
+      }
+    else
+      {
+        setText((String)(a.getValue(Action.NAME)));
+        setIcon((Icon)(a.getValue(Action.SMALL_ICON)));
+        setEnabled(a.isEnabled());
+        setToolTipText((String)(a.getValue(Action.SHORT_DESCRIPTION)));
+        setMnemonic(((Integer)(a.getValue(Action.MNEMONIC_KEY))).intValue());
+        setActionCommand((String)(a.getValue(Action.ACTION_COMMAND_KEY)));
+      }
   }
 
+  /**
+   * <p>A factory method which should return an {@link ActionListener} that
+   * propagates events from the button's {@link ButtonModel} to any of the
+   * button's ActionListeners. By default, this is an inner class which
+   * calls {@link AbstractButton.fireActionPerformed} with a modified copy
+   * of the incoming model {@link ActionEvent}.</p>
+   *
+   * <p>The button calls this method during construction, stores the
+   * resulting ActionListener in its <code>actionListener</code> member
+   * field, and subscribes it to the button's model. If the button's model
+   * is changed, this listener is unsubscribed from the old model and
+   * subscribed to the new one.</p>
+   *
+   * @return A new ActionListener 
+   */
   protected  ActionListener createActionListener()
   {
     return new ActionListener()
       {
-        public void actionPerformed(ActionEvent e) { }
+        public void actionPerformed(ActionEvent e)
+        {
+          e.setSource(AbstractButton.this);
+          AbstractButton.this.fireActionPerformed(e);
+        }
       };
   }
 
+  /**
+   * <p>A factory method which should return a {@link PropertyChangeListener}
+   * that accepts changes to the specified {@link Action} and reconfigure
+   * the {@link AbstractButton}, by default using the {@link
+   * configurePropertiesFromAction} method.</p>
+   *
+   * <p>The button calls this method whenever a new Action is assigned to
+   * the button's "action" property, via {@link setAction}, and stores the
+   * resulting PropertyChangeListener in its
+   * <code>actionPropertyChangeListener</code> member field. The button
+   * then subscribes the listener to the button's new action. If the
+   * button's action is changed subsequently, the listener is unsubscribed
+   * from the old action and subscribed to the new one.</p>
+   *
+   * @param a The Action which will be listened to, and which should be 
+   * the same as the source of any PropertyChangeEvents received by the
+   * new listener returned from this method.
+   *
+   * @return A new PropertyChangeListener
+   */
   protected  PropertyChangeListener createActionPropertyChangeListener(Action a)
   {
-    //Factory method which creates the PropertyChangeListener used to update the ActionEvent source as properties change on its Action instance.
-    return null;
+    return new PropertyChangeListener()
+      {
+        public void propertyChange(PropertyChangeEvent e)
+        {
+          Action act = (Action)(e.getSource());
+          AbstractButton.this.configurePropertiesFromAction(act);
+        }
+      };
   }
 
+  /**
+   * <p>Factory method which creates a {@link ChangeListener}, used to
+   * subscribe to ChangeEvents from the button's model. Subclasses of
+   * AbstractButton may wish to override the listener used to subscribe to
+   * such ChangeEvents. By default, the listener just propagates the
+   * {@link ChangeEvent} to the button's ChangeListeners, via the {@link
+   * AbstractButton.fireStateChanged} method.</p>
+   *
+   * <p>The button calls this method during construction, stores the
+   * resulting ChangeListener in its <code>changeListener</code> member
+   * field, and subscribes it to the button's model. If the button's model
+   * is changed, this listener is unsubscribed from the old model and
+   * subscribed to the new one.</p>
+   *
+   * @return The new ChangeListener
+   */
   protected  ChangeListener createChangeListener()
   {
-    //       Subclasses that want to handle ChangeEvents differently can override this to return another ChangeListener implementation.
     return new ChangeListener()
       {
-        public void stateChanged(ChangeEvent e) { }
+        public void stateChanged(ChangeEvent e)
+        {
+          AbstractButton.this.fireStateChanged(e);
+          AbstractButton.this.revalidate();
+          AbstractButton.this.repaint();          
+        }
       };
   }
 
+  /**
+   * <p>Factory method which creates a {@link ItemListener}, used to
+   * subscribe to ItemEvents from the button's model. Subclasses of
+   * AbstractButton may wish to override the listener used to subscribe to
+   * such ItemEvents. By default, the listener just propagates the
+   * {@link ItemEvent} to the button's ItemListeners, via the {@link
+   * AbstractButton.fireItemStateChanged} method.</p>
+   *
+   * <p>The button calls this method during construction, stores the
+   * resulting ItemListener in its <code>changeListener</code> member
+   * field, and subscribes it to the button's model. If the button's model
+   * is changed, this listener is unsubscribed from the old model and
+   * subscribed to the new one.</p>
+   *
+   * <p>Note that ItemEvents are only generated from the button's model
+   * when the model's <em>selected</em> property changes. If you want to
+   * subscribe to other properties of the model, you must subscribe to
+   * ChangeEvents.
+   *
+   * @return The new ItemListener
+   */
   protected  ItemListener createItemListener()
   {
     return new ItemListener()
       {
-        public void itemStateChanged(ItemEvent e) { }
+        public void itemStateChanged(ItemEvent e)
+        {
+          AbstractButton.this.fireItemStateChanged(e);
+        }
       };
   }
 
+  /**
+   * Programmatically perform a "click" on the button: arming, pressing,
+   * waiting, un-pressing, and disarming the model.
+   */
   public void doClick()
   {
     doClick(100);
   }
 
+  /**
+   * Programmatically perform a "click" on the button: arming, pressing,
+   * waiting, un-pressing, and disarming the model.
+   *
+   * @param pressTime The number of milliseconds to wait in the pressed state
+   */
   public void doClick(int pressTime)
   {
-    //Toolkit.tlkBeep ();
-    //Programmatically perform a "click".
-  }
-
-  public Icon getDisabledSelectedIcon()
+    getModel().setArmed(true);
+    getModel().setPressed(true);
+    try
   {
-    //Returns the icon used by the button when it's disabled and selected.
-    return disabled_selected_button;
+        java.lang.Thread.sleep(pressTime);
   }
-
-  public Icon getRolloverIcon()
+    catch (java.lang.InterruptedException e)
   {
-    //       Returns the rollover icon for the button.
-    return null;
+        // probably harmless
   }
-
-  Icon getRolloverSelectedIcon()
-  {
-    //       Returns the rollover selection icon for the button.
-    return null;
+    getModel().setPressed(false);
+    getModel().setArmed(false);
   }
 
-  Icon getSelectedIcon()
+  /**
+   * Return the button's disabled selected icon. The look and feel class
+   * should paint this icon when the "enabled" property of the button's model
+   * is <code>false</code> and its "selected" property is
+   * <code>true</code>. This icon can be <code>null</code>, in which case
+   * it is synthesized from the button's selected icon.
+   *
+   * @return The current disabled selected icon
+   */
+  public Icon getDisabledSelectedIcon()
   {
-    //       Returns the selected icon for the button.
-    return selected_button;
+    return disabled_selected_icon;
   }
 
-  public Object[] getSelectedObjects()
+  /**
+   * Set the button's disabled selected icon. The look and feel class
+   * should paint this icon when the "enabled" property of the button's model
+   * is <code>false</code> and its "selected" property is
+   * <code>true</code>. This icon can be <code>null</code>, in which case
+   * it is synthesized from the button's selected icon.
+   *
+   * @param disabledSelectedIcon The new disabled selected icon
+   */
+  public void setDisabledSelectedIcon(Icon disabledSelectedIcon)
   {
-    //Returns an array (length 1) containing the label or null if the button is not selected.
-    return null;
-  }
-
-  public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h)
+    Icon old = disabled_selected_icon;
+    disabled_selected_icon = disabledSelectedIcon;
+    if (old != disabledSelectedIcon)
   {
-    //This is overridden to return false if the current Icon's Image is not equal to the passed in Image img.
-    return current_icon == img;
+        firePropertyChange(DISABLED_SELECTED_ICON_CHANGED_PROPERTY, old, 
+                           disabledSelectedIcon);
+        revalidate();
+        repaint();        
   }
-
-  public boolean isContentAreaFilled()
-  {
-    //       Checks whether the "content area" of the button should be filled.
-    return false;
   }
 
-  protected  void paintBorder(Graphics g)
-  {
-    //       Paint the button's border if BorderPainted property is true.
-    if (isBorderPainted())
-      super.paintBorder(g);
-  }
 
-  protected  String paramString()
+  /**
+   * Return the button's rollover icon. The look and feel class should
+   * paint this icon when the "rolloverEnabled" property of the button is
+   * <code>true</code> and the mouse rolls over the button.
+   *
+   * @return The current rollover icon
+   */
+  public Icon getRolloverIcon()
   {
-    //        Returns a string representation of this AbstractButton.
-    return "AbstractButton";
+    return rollover_icon;
   }
 
-  public void setContentAreaFilled(boolean b)
+  /**
+   * Set the button's rollover icon. The look and feel class should
+   * paint this icon when the "rolloverEnabled" property of the button is
+   * <code>true</code> and the mouse rolls over the button.
+   *
+   * @param rolloverIcon The new rollover icon
+   */
+  public void setRolloverIcon(Icon rolloverIcon)
   {
-    //Sets whether the button should paint the content area or leave it transparent.
-  }
-
-  public void setDisabledSelectedIcon(Icon disabledSelectedIcon)
+    Icon old = rollover_icon;
+    rollover_icon = rolloverIcon;
+    if (old != rolloverIcon)
   {
-    //          Sets the disabled selection icon for the button.
+        firePropertyChange(ROLLOVER_ICON_CHANGED_PROPERTY, old, 
+                           rolloverIcon);
+        revalidate();
+        repaint();
+      }
   }
 
-  public void setRolloverIcon(Icon rolloverIcon)
+  /**
+   * Return the button's rollover selected icon. The look and feel class
+   * should paint this icon when the "rolloverEnabled" property of the button
+   * is <code>true</code>, the "selected" property of the button's model is
+   * <code>true</code>, and the mouse rolls over the button.
+   *
+   * @return The current rollover selected icon
+   */
+  Icon getRolloverSelectedIcon()
   {
-    //       Sets the rollover icon for the button.
+    return rollover_selected_icon;
   }
+
+  /**
+   * Set the button's rollover selected icon. The look and feel class
+   * should paint this icon when the "rolloverEnabled" property of the button
+   * is <code>true</code>, the "selected" property of the button's model is
+   * <code>true</code>, and the mouse rolls over the button.
+   *
+   * @param rolloverSelectedIcon The new rollover selected icon
+   */
   public void setRolloverSelectedIcon(Icon rolloverSelectedIcon)
   {
-    //       Sets the rollover selected icon for the button.
-  }
-
-  public void setSelectedIcon(Icon selectedIcon)
+    Icon old = rollover_selected_icon;
+    rollover_selected_icon = rolloverSelectedIcon;
+    if (old != rolloverSelectedIcon)
   {
-    //       Sets the selected icon for the button.
+        firePropertyChange(ROLLOVER_SELECTED_ICON_CHANGED_PROPERTY, old, 
+                           rolloverSelectedIcon);
+        revalidate();
+        repaint();
   }
-
-  public void setUI(ButtonUI ui)
-  {	//       Sets the L&F object that renders this component.
-    super.setUI(ui);
   }
 
-  public ButtonUI getUI()
+
+  /**
+   * Return the button's selected icon. The look and feel class should
+   * paint this icon when the "selected" property of the button's model is
+   * <code>true</code>, and either the "rolloverEnabled" property of the
+   * button is <code>false</code> or the mouse is not currently rolled
+   * over the button.
+   *
+   * @return The current selected icon
+   */
+  Icon getSelectedIcon()
   {
-    //Returns the L&F object that renders this component.
-    return (ButtonUI) ui;
+    return selected_icon;
   }
 
-  public void updateUI()
+  /**
+   * Set the button's selected icon. The look and feel class should
+   * paint this icon when the "selected" property of the button's model is
+   * <code>true</code>, and either the "rolloverEnabled" property of the
+   * button is <code>false</code> or the mouse is not currently rolled
+   * over the button.
+   *
+   * @param selectedIcon The new selected icon
+   */
+  public void setSelectedIcon(Icon selectedIcon)
   {
-    /*
-    //          Notification from the UIFactory that the L&F has changed.
-    if (getUI() == null)
+    Icon old = selected_icon;
+    selected_icon = selectedIcon;
+    if (old != selectedIcon)
     {
-    setUI(getUI());
+        firePropertyChange(SELECTED_ICON_CHANGED_PROPERTY, old, 
+                           selectedIcon);
+        revalidate();
+        repaint();
     }
-    */
   }
 
-  protected void processActionEvent(ActionEvent e)
+  /**
+   * Returns an single-element array containing the "text" property of the
+   * button if the "selected" property of the button's model is
+   * <code>true</code>, otherwise returns <code>null</code>.
+   *
+   * @return The button's "selected object" array
+   */
+  public Object[] getSelectedObjects()
   {
-    System.out.println("PROCESS-ACTION-EVENT: " + e);
+    if (isSelected())
+      {
+        Object[] objs = new Object[1];
+        objs[0] = getText();
+        return objs;
   }
-
-  protected void processMouseEvent(MouseEvent e)
+    else
   {
-    //	System.out.println("PROCESS-MOUSE-EVENT: " + e + ", PRESSED-IN-MODEL="+getModel().isPressed());
+        return null;
+      }
+  }
 
-    switch (e.getID())
-      {
-      case MouseEvent.MOUSE_MOVED:
+  /**
+   * Called when image data becomes available for one of the button's icons.
+   *
+   * @param img The image being updated
+   * @param infoflags One of the constant codes in {@link ImageObserver} used to describe
+   * updated portions of an image.
+   * @param x X coordinate of the region being updated
+   * @param y Y coordinate of the region being updated
+   * @param w Width of the region beign updated
+   * @param h Height of the region being updated
+   *
+   * @return <code>true</code> if img is equal to the button's current
+   * icon, otherwise <code>false</code>
+   */
+  public boolean imageUpdate(Image img, int infoflags, int x, int y, int w,
+                             int h)
         {
-          break;
+    return current_icon == img;
         }
-      case MouseEvent.MOUSE_PRESSED:
-        {
-          if (! isEnabled())
+
+  /**
+   * Returns the value of the button's "contentAreaFilled" property. This
+   * property indicates whether the area surrounding the text and icon of
+   * the button should be filled by the look and feel class.  If this
+   * property is <code>false</code>, the look and feel class should leave
+   * the content area transparent.
+   *
+   * @return The current value of the "contentAreaFilled" property
+   */
+  public boolean isContentAreaFilled()
             {
-              System.out.println("button not enabled, ignoring press");
+    return content_area_filled;
             }
-          else
+
+  /**
+   * Sets the value of the button's "contentAreaFilled" property. This
+   * property indicates whether the area surrounding the text and icon of
+   * the button should be filled by the look and feel class.  If this
+   * property is <code>false</code>, the look and feel class should leave
+   * the content area transparent.
+   *
+   * @param b The new value of the "contentAreaFilled" property
+   */
+  public void setContentAreaFilled(boolean b)
             {
-              System.out.println("telling model:press: " + getModel());
-              getModel().setPressed(true);
+    boolean old = content_area_filled;
+    content_area_filled = b;
+    if (b != old)
+      {
+        firePropertyChange(CONTENT_AREA_FILLED_CHANGED_PROPERTY, old, b);
+        revalidate();
               repaint();
             }
-          break;
         }
 
-      case MouseEvent.MOUSE_RELEASED:
-        {
-          if (! isEnabled())
+  /**
+   * Paints the button's border, if the button's "borderPainted" property is
+   * <code>true</code>, by out calling to the button's look and feel class.
+   *
+   * @param g The graphics context used to paint the border
+   */
+  protected void paintBorder(Graphics g)
             {
-              System.out.println("button not enabled, ignoring release");
+    if (isBorderPainted())
+      super.paintBorder(g);
             }
-          else
-            {
-              int flags = 0;
 
-              System.out.println("        XXX--> " + getActionCommand());
+  /**
+   * Returns a string, used only for debugging, which identifies or somehow
+   * represents this button. The exact value is implementation-defined.
+   *
+   * @return A string representation of the button
+   */
+  protected String paramString()
+  {
+    return "AbstractButton";
+  }
 
-              fireActionPerformed(new ActionEvent(this,
-                                                  ActionEvent.ACTION_PERFORMED,
-                                                  getActionCommand(),
-                                                  flags));
 
-              //System.out.println("telling model:release");
-              getModel().setPressed(false);
-              repaint();
-            }
-          break;
-        }
-      case MouseEvent.MOUSE_CLICKED:
+  /**
+   * Set the "UI" property of the button, which is a look and feel class
+   * responsible for handling the button's input events and painting it.
+   *
+   * @param ui The new "UI" property
+   */
+  public void setUI(ButtonUI ui)
         {
-          break;
+    super.setUI(ui);
         }
+  
+  /**
+   * Set the "UI" property of the button, which is a look and feel class
+   * responsible for handling the button's input events and painting it.
+   *
+   * @return The current "UI" property
+   */
+  public ButtonUI getUI()
+  {
+    return (ButtonUI) ui;
       }
+  
+  /**
+   * Set the "UI" property to a class constructed, via the {@link
+   * UIManager}, from the current look and feel. This should be overridden
+   * for each subclass of AbstractButton, to retrieve a suitable {@link
+   * ButtonUI} look and feel class.
+   */
+  public void updateUI()
+  {
   }
 }
Index: javax/swing/DefaultButtonModel.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/javax/swing/DefaultButtonModel.java,v
retrieving revision 1.3
diff -u -b -w -r1.3 DefaultButtonModel.java
--- javax/swing/DefaultButtonModel.java	11 Jun 2003 13:20:39 -0000	1.3
+++ javax/swing/DefaultButtonModel.java	22 Jan 2004 09:53:46 -0000
@@ -1,5 +1,5 @@
 /* DefaultButtonModel.java -- 
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -35,9 +35,10 @@
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
-
 package javax.swing;
 
+import java.awt.AWTEvent;
+import java.awt.AWTEventMulticaster;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
@@ -49,130 +50,412 @@
 import javax.swing.event.ChangeListener;
 import javax.swing.event.EventListenerList;
 
-public class DefaultButtonModel
-  implements ButtonModel, Serializable
+/**
+ * The purpose of this class is to model the dynamic state of an abstract
+ * button. The concrete button type holding this state may be a a "toggle"
+ * button (checkbox, radio button) or a "push" button (menu button, button).
+ * 
+ * Any change to the model's properties will trigger the firing of a
+ * ChangeEvent.
+ *
+ * Any change to the "pressed" property will trigger the firing of an
+ * ItemEvent in addition to ChangeEvent.
+ *
+ * Any change which causes the enabled, armed and pressed properties to
+ * simultaneously become <code>true</code> will trigger the firing of an
+ * ActionEvent in addition to the ChangeEvent.
+ *
+ * @author Graydon Hoare (graydon&064;redhat.com)
+ */
+public class DefaultButtonModel implements ButtonModel, Serializable
 {
   static final long serialVersionUID = -5342609566534980231L;
 
-    Vector actions          = new Vector();
+  /** Indicates that the button is <em>partially</em> committed to being
+   pressed, but not entirely. This usually happens when a user has pressed
+   but not yet released the mouse button. */
+  static int ARMED = 1;
+
+  /** State constant indicating that the button is enabled. Buttons cannot
+   be pressed or selected unless they are enabled. */
+  static int ENABLED = 2;
+
+  /** State constant indicating that the button has been fully
+   pressed. This usually happens when a user has released the mouse over a
+   previously "armed" button. */
+  static int PRESSED = 4;
+
+  /** State constant indicating that the mouse is currently positioned over
+      the button. */
+  static int ROLLOVER = 8;
+
+  /** State constant indicating that the button is selected. This constant
+      is only meaningful for toggle-type buttons (radio buttons,
+      checkboxes). */
+  static int SELECTED = 16;
+
+  /** Represents the "state properties" (armed, enabled, pressed, rollover
+      and selected) by a bitwise combination of integer constants. */
+  int stateMask;
+
+  /** List of ItemListeners, ChangeListeners, and ActionListeners
+      registered on this model. */
+  EventListenerList listenerList;
+
+  /** The single ChangeEvent this model (re)uses to call its
+      ChangeListeners. */
+  ChangeEvent changeEvent;
 
-    Vector items    = new Vector();
-    Vector changes  = new Vector();
+  /** The group this model belongs to. Only one button in a group may be
+      selected at any given time. */
     ButtonGroup group;
-    JComponent comp;
-
-    
-    DefaultButtonModel(JComponent a)
-    {
-	comp = a;
-    }
-
 
+  /** The key code (one of {@link java.awt.event.KeyEvent} VK_*) used to
+      press this button via a keyboard interface. */
+  int mnemonic;
+
+  /** The string used as the "command" property of any ActionEvent this
+      model sends. */
+  String actionCommand;
+
+  public DefaultButtonModel()
+  {
+    stateMask = 0;
+    listenerList = new EventListenerList();    
+    changeEvent = new ChangeEvent(this);
+  }
+
+  /**
+   * Return <code>null</code>. Use {@link AbstractButton} if you wish to
+   * interface with a button via an {@link ItemSelectable} interface.
+   *
+   * @return <code>null</code>
+   */
     public Object[] getSelectedObjects()
     {
 	return null;
     }
 
-
-    public void fireItemStateChanged(ItemEvent event)
-    {
-	for (int i=0;i<items.size();i++)
+  /**
+   * Add an ActionListener to the model. Usually only called to subscribe
+   * an AbstractButton's listener to the model.
+   *
+   * @param l The listener to add
+   */
+  public void addActionListener(ActionListener l)
 	    {
-		ItemListener a = (ItemListener) items.get(i);
-		a.itemStateChanged(event);
-	    }
+    listenerList.add(ActionListener.class, l);
     }
-    public void fireStateChanged(ChangeEvent event)
+
+  /**
+   * Remove an ActionListener to the model. Usually only called to
+   * unsubscribe an AbstractButton's listener to the model.
+   *
+   * @param l The listener to remove
+   */
+  public void removeActionListener(ActionListener l)
+  {
+    listenerList.remove(ActionListener.class, l);
+  }
+
+  /**
+   * Add an ItemListener to the model. Usually only called to subscribe
+   * an AbstractButton's listener to the model.
+   *
+   * @param l The listener to add
+   */
+  public void addItemListener(ItemListener l)
+  {
+    listenerList.add(ItemListener.class, l);
+  }
+
+  /**
+   * Remove an ItemListener to the model. Usually only called to
+   * unsubscribe an AbstractButton's listener to the model.
+   *
+   * @param l The listener to remove
+   */
+  public void removeItemListener(ItemListener l)
+  {
+    listenerList.remove(ItemListener.class, l);
+  }
+
+  /**
+   * Add a ChangeListener to the model. Usually only called to subscribe
+   * an AbstractButton's listener to the model.
+   *
+   * @param l The listener to add
+   */
+  public void addChangeListener(ChangeListener l)
+  {
+    listenerList.add(ChangeListener.class, l);
+  }
+
+  /**
+   * Remove a ChangeListener to the model. Usually only called to
+   * unsubscribe an AbstractButton's listener to the model.
+   *
+   * @param l The listener to remove
+   */
+  public void removeChangeListener(ChangeListener l)
+  {
+    listenerList.remove(ChangeListener.class, l);
+  }
+
+  /**
+   * Inform each ItemListener in the {@link listenerList} that an ItemEvent
+   * has occurred. This happens in response to any change to the {@link
+   * stateMask} field.
+   *
+   * @param e The ItemEvent to fire
+   */
+  public void fireItemStateChanged(ItemEvent e)
+  {
+    EventListener[] ll = listenerList.getListeners(ItemListener.class);
+    for (int i = 0; i < ll.length; i++)
+      ((ItemListener)ll[i]).itemStateChanged(e);
+  }
+
+  /**
+   * Inform each ActionListener in the {@link listenerList} that an
+   * ActionEvent has occurred. This happens in response to the any change
+   * to the {@link stateMask} field which makes the enabled, armed and
+   * pressed properties all simultaneously <code>true</code>.
+   *
+   * @param e The ActionEvent to fire
+   */
+  public void fireActionPerformed(ActionEvent e)
+  {
+    EventListener[] ll = listenerList.getListeners(ActionListener.class);
+    for (int i = 0; i < ll.length; i++)
+      ((ActionListener)ll[i]).actionPerformed(e);
+  }
+
+  /**
+   * Inform each ChangeListener in the {@link listenerList} that a
+   * ChangeEvent has occurred. This happens in response to the any change
+   * to a property of the model.
+   *
+   * @param event The ChangeEvent to fire
+   */
+  public void fireStateChanged(ChangeEvent e)
+  {
+    EventListener[] ll = listenerList.getListeners(ChangeListener.class);
+    for (int i = 0; i < ll.length; i++)
+      ((ChangeListener)ll[i]).stateChanged(e);
+  }
+
+  /**
+   * Helper method to fire a ChangeEvent with the model as the event's
+   * source.
+   */
+  protected void changeState(int stateflag, boolean b)
     {
-	for (int i=0;i<changes.size();i++)
+    int oldstate = stateMask;
+    int newstate;
+
+    if (b)
+      newstate = oldstate | stateflag;
+    else
+      newstate = oldstate & ~stateflag;
+
+    if (oldstate == newstate)
+      return;
+
+    stateMask = newstate;
+
+    fireStateChanged(changeEvent);
+
+    if ((newstate & ENABLED) == 0)
+      return;
+
+    if ((oldstate & SELECTED) == 0
+        && (newstate & SELECTED) == SELECTED)
+      fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, 
+                                         null, ItemEvent.SELECTED));
+
+    else if ((oldstate & SELECTED) == SELECTED
+             && (newstate & SELECTED) == 0)
+      fireItemStateChanged(new ItemEvent(this, ItemEvent.ITEM_STATE_CHANGED, 
+                                         null, ItemEvent.DESELECTED));
+
+    else if ((newstate & ARMED) == ARMED
+             && (newstate & PRESSED) == PRESSED)
 	    {
-		ChangeListener a = (ChangeListener) changes.get(i);
-		a.stateChanged(event);
+        fireActionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
+                                            actionCommand));
+        stateMask = stateMask & ~(PRESSED | ARMED);
 	    }
+    
     }
-    public void fireActionPerformed(ActionEvent event)
-    {
-	for (int i=0;i<actions.size();i++)
+
+  /**
+   * Get the value of the model's "armed" property.
+   * 
+   * @return The current "armed" property 
+   */
+  public boolean isArmed()
 	    {
-		ActionListener a = (ActionListener) actions.get(i);
-		a.actionPerformed(event);
-	    }
+    return (stateMask & ARMED) == ARMED;
     }
 
-    boolean arm;
-    public boolean isArmed()          { return arm; }
-    public void setArmed(boolean b)   { arm = b; }
-
-    boolean enabled = true;
-    public boolean isEnabled()         { return enabled; }
-    public void setEnabled(boolean b)  { enabled = b; }
+  /**
+   * Set the value of the model's "armed" property.
+   *
+   * @param a The new "armed" property
+   */
+  public void setArmed(boolean a)
+  {
+    changeState(ARMED, a);
+  }
 
-    boolean pressed;
-    public void setPressed(boolean b)  
+  /**
+   * Get the value of the model's "enabled" property.
+   *
+   * @return The current "enabled" property.
+   */
+  public boolean isEnabled()
     {
-	pressed = b; 
+    return (stateMask & ENABLED) == ENABLED;
     }
-    public boolean isPressed()         { return pressed; }
 
+  /**
+   * Set the value of the model's "enabled" property.
+   *
+   * @param e The new "enabled" property
+   */
+  public void setEnabled(boolean e)
+  {
+    changeState(ENABLED, e);
+  }
 
-    public void removeActionListener(ActionListener l) { actions.removeElement(l); }
-    public void addActionListener(ActionListener l)    
+  /**
+   * Set the value of the model's "pressed" property.
+   *
+   * @param p The new "pressed" property
+   */
+  public void setPressed(boolean p)
     {	
-	//	comp.enableEvents( AWTEvent.ACTION_EVENT_MASK );
-	actions.addElement(l);    
+    changeState(PRESSED, p);
     }
 
-    public void addItemListener(ItemListener l)        { items.addElement(l); }
-    public void removeItemListener(ItemListener l)     { items.removeElement(l); }
+  /**
+   * Get the value of the model's "pressed" property.
+   *
+   * @return The current "pressed" property
+   */
+  public boolean isPressed()
+  {
+    return (stateMask & PRESSED) == PRESSED;
+  }
 
-    public void addChangeListener(ChangeListener l)    { changes.addElement(l); }
-    public void removeChangeListener(ChangeListener l) { changes.removeElement(l); }
+  /**
+   * Set the value of the model's "rollover" property.
+   *
+   * @param r The new "rollover" property
+   */
+  public void setRollover(boolean r)
+  {
+    changeState(ROLLOVER, r);
+  }
 
-    boolean roll;
-    public void setRollover(boolean b) { roll = b; }
-    public boolean isRollover()        { return roll; }
 
-    int mne;  
-    public int  getMnemonic()        { return mne; }
-    public void setMnemonic(int key) { mne = key; }
+  /**
+   * Set the value of the model's "selected" property.
+   *
+   * @param s The new "selected" property
+   */
+  public void setSelected(boolean s)
+  {
+    changeState(SELECTED, s);
+  }
 
-    String com;
-    public void setActionCommand(String s) { com = s; }
-    public String getActionCommand()       { return com; }
+  /**
+   * Get the value of the model's "selected" property.
+   *
+   * @return The current "selected" property
+   */
+  public boolean isSelected()
+  {
+    return (stateMask & SELECTED) == SELECTED;
+  }
 
-    public void setGroup(ButtonGroup group)
+  /**
+   * Get the value of the model's "rollover" property.
+   *
+   * @return The current "rollover" property
+   */
+  public boolean isRollover()
     {
-	this.group = group;
+    return (stateMask & ROLLOVER) == ROLLOVER;
     }
 
-    boolean sel;
-    public void setSelected(boolean b) 
+  /**
+   * Get the value of the model's "mnemonic" property.
+   *
+   * @return The current "mnemonic" property
+   */
+  public int getMnemonic()
     { 
-	if (group != null)
+    return mnemonic;
+  }
+
+  /**
+   * Set the value of the model's "mnemonic" property.
+   *
+   * @param key The new "mnemonic" property
+   */
+  public void setMnemonic(int key)
 	    {
-		if (b == true)
+    if (mnemonic != key)
 		    {
-			System.out.println("selected button in group:"+this);
-			group.setSelected(this, b);
-			sel = true;
+        mnemonic = key;
+        fireStateChanged(changeEvent);
 		    }
-		else
+  }
+
+  /**
+   * Set the value of the model's "actionCommand" property. This property
+   * is used as the "command" property of the {@link ActionEvent} fired
+   * from the model.
+   *
+   * @param s The new "actionCommand" property.
+   */
+  public void setActionCommand(String s)
 		    {
-			System.out.println("deselected button in group: " + this);
-			sel = false;
+    if (actionCommand != s)
+      {
+        actionCommand = s;
+        fireStateChanged(changeEvent);
 		    }
 	    } 
-	else
+
+  /**
+   * Set the value of the model's "actionCommand" property. This property
+   * is used as the "command" property of the {@link ActionEvent} fired
+   * from the model.
+   *
+   * @return The current "actionCommand" property
+   */
+  public String getActionCommand()
 	    {
-		sel = b;
+    return actionCommand;
+  }
+
+  /**
+   * Set the value of the model's "group" property. The model is said to be
+   * a member of the {@link ButtonGroup} held in its "group" property, and
+   * only one models in a given group can have their "selected" property be
+   * <code>true</code> at a time.
+   *
+   * @param g The new "group" property
+   */
+  public void setGroup(ButtonGroup g)
+  {
+    if (group != g)
+      {
+        group = g;
+        fireStateChanged(changeEvent);
 	    }
     }
-    public boolean isSelected()        { return sel; }
 }
-
-
-
-
-
-
-
Index: javax/swing/JComponent.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/javax/swing/JComponent.java,v
retrieving revision 1.4
diff -u -b -w -r1.4 JComponent.java
--- javax/swing/JComponent.java	19 Jun 2003 16:30:09 -0000	1.4
+++ javax/swing/JComponent.java	22 Jan 2004 09:53:46 -0000
@@ -46,6 +46,7 @@
 import java.awt.FlowLayout;
 import java.awt.Font;
 import java.awt.Graphics;
+import java.awt.Image;
 import java.awt.Insets;
 import java.awt.Point;
 import java.awt.Rectangle;
@@ -56,6 +57,7 @@
 import java.awt.event.FocusListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
+import java.awt.image.ImageObserver;
 import java.awt.peer.LightweightPeer;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyVetoException;
@@ -271,13 +273,16 @@
 		super();
 		super.setLayout(new FlowLayout());
 		
+		listenerList = new EventListenerList();
+    
 		//eventMask |= AWTEvent.COMP_KEY_EVENT_MASK;
-		enableEvents( AWTEvent.KEY_EVENT_MASK );
+		// enableEvents( AWTEvent.KEY_EVENT_MASK );
 
 		//updateUI(); // get a proper ui
 	}
 
-	// protected EventListenerList listenerList
+	protected EventListenerList listenerList;
+
 	public boolean contains(int x, int y)
 	{
 		//return dims.contains(x,y);
@@ -701,11 +706,29 @@
 
 	public void paint(Graphics g)
 	{
-		//	System.out.println("SWING_PAINT:" + this);
+		Graphics g2 = g;
+		Image im = null;
+		Rectangle r = getBounds ();
+		// System.err.println(this + ".paint(...), bounds = " + r);
+		
+		if (use_double_buffer)
+		{
+			im = createImage (r.width, r.height);
+			g2 = im.getGraphics ();
+			g2.clearRect (0, 0, r.width, r.height);
+		}
+		
+		paintBorder(g2);
+		paintComponent(g2);
+		paintChildren(g2);
 
-		paintBorder(g);
-		paintComponent(g);
-		paintChildren(g);
+		if (use_double_buffer)
+		{
+			// always draw at 0,0, because regardless of your current bounds,
+			// the graphics object you were passed was positioned so the origin
+			// was at the upper left corner of your bounds.
+			g.drawImage (im, 0, 0, (ImageObserver)null);
+		}
 	}
 
 	protected  void paintBorder(Graphics g)
@@ -729,7 +752,7 @@
 	protected  void paintChildren(Graphics g)
 	{
 	    //      Paint this component's children.
-	    //super.paintChildren(g);
+		super.paint(g);
 	}
 
 	protected  void paintComponent(Graphics g)
Index: javax/swing/JToggleButton.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/javax/swing/JToggleButton.java,v
retrieving revision 1.2
diff -u -b -w -r1.2 JToggleButton.java
--- javax/swing/JToggleButton.java	11 Jun 2003 13:20:39 -0000	1.2
+++ javax/swing/JToggleButton.java	22 Jan 2004 09:53:46 -0000
@@ -74,7 +74,7 @@
 	super(text, icon);
 
         // Create the model
-        setModel(new ToggleButtonModel(this));
+        setModel(new ToggleButtonModel());
 	
         model.setSelected(selected);
     }
Index: javax/swing/SwingUtilities.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/javax/swing/SwingUtilities.java,v
retrieving revision 1.3
diff -u -b -w -r1.3 SwingUtilities.java
--- javax/swing/SwingUtilities.java	14 Jul 2003 05:33:30 -0000	1.3
+++ javax/swing/SwingUtilities.java	22 Jan 2004 09:53:47 -0000
@@ -97,8 +97,8 @@
     // view rect 'vr' already ok, 
     // we need to compute ir (icon rect) and tr (text-rect)
 	
-    int next_x = 0;//vr.x;
-    int next_y = 0;//vr.y;
+    int next_x = vr.x;
+    int next_y = vr.y;
 	
     ir.height = ir.width = ir.y = ir.x = 0;
 
@@ -115,10 +115,10 @@
       }
 	
     tr.x = next_x;
-    tr.y = vr.y + (vr.height/2);
+    tr.y = vr.y; // + (vr.height/2);
 
     tr.width  = fm.stringWidth(text);
-    tr.height = fm.getHeight() +  fm.getAscent()/2;
+    tr.height = fm.getHeight(); // +  fm.getAscent()/2;
 
     return text;
   }
Index: javax/swing/ToggleButtonModel.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/javax/swing/ToggleButtonModel.java,v
retrieving revision 1.2
diff -u -b -w -r1.2 ToggleButtonModel.java
--- javax/swing/ToggleButtonModel.java	19 Jun 2003 16:30:09 -0000	1.2
+++ javax/swing/ToggleButtonModel.java	22 Jan 2004 09:53:47 -0000
@@ -40,11 +40,6 @@
 
 public class ToggleButtonModel extends DefaultButtonModel
 {
-    ToggleButtonModel(JComponent c)
-    {
-	super(c);
-    }
-
     public void setPressed(boolean b)  
     {
 	if (! isEnabled())
Index: javax/swing/plaf/basic/BasicButtonUI.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/javax/swing/plaf/basic/BasicButtonUI.java,v
retrieving revision 1.4
diff -u -b -w -r1.4 BasicButtonUI.java
--- javax/swing/plaf/basic/BasicButtonUI.java	10 Jan 2004 21:59:30 -0000	1.4
+++ javax/swing/plaf/basic/BasicButtonUI.java	22 Jan 2004 09:53:47 -0000
@@ -35,16 +35,23 @@
 obligated to do so.  If you do not wish to do so, delete this
 exception statement from your version. */
 
-
 package javax.swing.plaf.basic;
 
+import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.FontMetrics;
 import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Stroke;
 import java.awt.Insets;
 import java.awt.Rectangle;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
 import javax.swing.AbstractButton;
 import javax.swing.JComponent;
 import javax.swing.SwingUtilities;
@@ -53,20 +60,161 @@
 
 public class BasicButtonUI extends ButtonUI
 {
+  /** A constant used to pad out elements in the button's layout and
+      preferred size calculations. */
     int gap = 3;
-    //    int y_text_space = 2, x_text_space + 5;
 
-    Color textColor, disabledTextColor;
+  /** The color that text will be painted when the button is enabled */
+  Color textColor;
+
+  /** The color that text will be painted when the button is disabled */
+  Color disabledTextColor;
+
+  /** The color that the button's background will be painted when the
+      button is pressed. */
     Color pressedBackgroundColor;
-    Color normalBackgroundColor;
 
+  /** The color that the button's background will be painted when the
+      button is not pressed. */
+  Color normalBackgroundColor;
 
+  /**
+   * Factory method to create an instance of BasicButtonUI for a given
+   * {@link JComponent}, which should be an {@link AbstractButton}.
+   *
+   * @param c The component to create a UI got
+   *
+   * @return A new UI capable of drawing the component
+   */
     public static ComponentUI createUI(final JComponent c) 
     {
 	return new BasicButtonUI();
     }
 
+  /**
+   * Helper class which listens to a button's focus events and disarms the
+   * button's model when focus is lost.
+   */
+  private static class FocusUIListener extends FocusAdapter
+  {
+    /** Button to listen to focus events from */
+    AbstractButton button;
+
+    /**
+     * Creates a new FocusUIListener object.
+     *
+     * @param b The button to listen to
+     */
+    FocusUIListener(AbstractButton b)
+    {
+      button = b;
+    }
     
+    /**
+     * Called when the button loses focus.
+     *
+     * @param event The loss of focus event.
+     */
+    public void focusLost(FocusEvent event)
+    {
+      // System.err.println("ButtonUI :: lost focus -- disarming");
+      button.getModel().setArmed(false);
+    }
+  }
+
+  /**
+   * A helper class which interprets mouse events as 
+   * state changes to the button's underlying model.
+   */
+  private static class ButtonUIListener extends MouseAdapter
+  {
+    /** The button to change the model of */
+    AbstractButton button;
+
+    /**
+     * Creates a new ButtonUIListener object.
+     *
+     * @param b The button to change the model of
+     */
+    public ButtonUIListener(AbstractButton b)
+    {
+      button = b;
+    }
+
+    /**
+     * Accept a mouse press event and arm the button's model.
+     *
+     * @param e The mouse press event to accept
+     */
+    public void mousePressed(MouseEvent e)
+    {
+      // System.err.println("ButtonUI :: mouse pressed");
+      if ((e.getModifiers() & InputEvent.BUTTON1_MASK) != 0)
+        {
+          // System.err.println("ButtonUI :: arming");
+          button.getModel().setArmed(true);
+        }
+    }
+
+    /**
+     * Accept a mouse enter event and set the button's model's
+     * "rollover" property to <code>true</code>. If the button's
+     * model is currently armed and the mouse button is not held
+     * down, this enter event will also disarm the model.
+     *
+     * @param e The mouse enter event to accept
+     */
+    public void mouseEntered(MouseEvent e)
+    {
+      // System.err.println("ButtonUI :: mouse entered");
+      // System.err.println("ButtonUI :: rolling over");
+      button.getModel().setRollover(true);
+      if (button.getModel().isArmed() 
+          && (e.getModifiers() & InputEvent.BUTTON1_MASK) == 0)
+        {
+          // System.err.println("ButtonUI :: no button pressed -- disarming");
+          button.getModel().setArmed(false);
+        }
+    }
+
+    /**
+     * Accept a mouse exit event and set the button's model's
+     * "rollover" property to <code>false</code>.
+     *
+     * @param e The mouse exit event to accept
+     */
+    public void mouseExited(MouseEvent e)
+    {
+      // System.err.println("ButtonUI :: mouse exited");
+      button.getModel().setRollover(false);
+    }
+
+    /**
+     * Accept a mouse release event and set the button's model's
+     * "pressed" property to <code>true</code>, if the model
+     * is armed. If the model is not armed, ignore the event.
+     *
+     * @param e The mouse release event to accept
+     */
+    public void mouseReleased(MouseEvent e)
+    {
+      // System.err.println("ButtonUI :: mouse released");
+      if (button.getModel().isArmed()
+          && (e.getModifiers() & InputEvent.BUTTON1_MASK) != 0)
+        {
+          button.getModel().setPressed(true);
+        }
+    }
+  }
+
+  /**
+   * Install the BasicButtonUI as the UI for a particular component.
+   * This means registering all the UI's listeners with the component,
+   * and setting any properties of the button which are particular to 
+   * this look and feel.
+   *
+   * @param c The component to install the UI into
+   */
     public void installUI(final JComponent c) 
     {
 	super.installUI(c);
@@ -76,18 +224,37 @@
 	pressedBackgroundColor   = new Color(150,150,150);
 	pressedBackgroundColor   = new Color(150,150,150);
 	normalBackgroundColor    = new Color(192,192,192);
-    }
-    
 
+    // this tells the border (if we have one) how to paint.
+    c.setBackground(normalBackgroundColor);
+    ((AbstractButton)c).setMargin (new Insets(10,10,10,10));
+
+    c.addMouseListener(new ButtonUIListener((AbstractButton) c));
+    c.addFocusListener(new FocusUIListener((AbstractButton) c));
+  }
+
+  /**
+   * Calculate the preferred size of this component, by delegating to
+   * {@link BasicGraphicsUtils.getPreferredButtonSize}.
+   *
+   * @param c The component to measure
+   *
+   * @return The preferred dimensions of the component
+   */
     public Dimension getPreferredSize(JComponent c) 
     {
 	AbstractButton b = (AbstractButton)c;
 	Dimension d = BasicGraphicsUtils.getPreferredButtonSize(b, gap);
-	//	System.out.println("^^^^^^^^^^^^^^^^^^^^^^   BASIC-PREF="+d + ",T="+b.text);
 	return d;
     }
     
-
+  /**
+   * Paint the component, which is an {@link AbstractButton}, according to 
+   * its current state.
+   *
+   * @param g The graphics context to paint with
+   * @param c The component to paint the state of
+   */
     public void paint(Graphics g, JComponent c)
     {      
 	AbstractButton b = (AbstractButton) c;
@@ -95,6 +262,7 @@
 	Rectangle tr = new Rectangle();
 	Rectangle ir = new Rectangle();
 	Rectangle vr = new Rectangle();
+    Rectangle br = new Rectangle();
 
         Font f = c.getFont();
 
@@ -102,115 +270,150 @@
 
         FontMetrics fm = g.getFontMetrics(f);
 
-        Insets i = c.getInsets();
+    Insets border = b.getInsets();
+    Insets margin = b.getMargin();
+
+    br.x = border.left;
+    br.y = border.top;
+    br.width = b.getWidth() - (border.right + border.left);
+    br.height = b.getHeight() - (border.top + border.bottom);
+
+    vr.x = br.x + margin.left;
+    vr.y = br.y + margin.top;
+    vr.width = br.width - (margin.right + margin.left);
+    vr.height = br.height - (margin.top + margin.bottom);
 
-        vr.x      = i.left;
-        vr.y      = i.top;
-        vr.width  = b.getWidth()  - (i.right  + vr.x);
-        vr.height = b.getHeight() - (i.bottom + vr.y);
-	
-	//System.out.println("             VIEW-RECT-BUTTON="+vr+", insets="+i+", FONTM="+fm);
-	
-	String text = SwingUtilities.layoutCompoundLabel(c,
-							 fm, 
-							 b.getText(),
+    String text = SwingUtilities.layoutCompoundLabel(c, fm, b.getText(),
 							 b.getIcon(),
 							 b.getVerticalAlignment(), 
 							 b.getHorizontalAlignment(),
 							 b.getVerticalTextPosition(), 
 							 b.getHorizontalTextPosition(),
-							 vr,
-							 ir,
-							 tr,
-							 gap);
+                                                     vr, ir, tr, gap);
 
-        if (b.getModel().isPressed() ||
-	    b.getModel().isSelected())
-	    {
-	      //System.out.println("paint pressed");
-		paintButtonPressed(g, c);
-	    }
+    if ((b.getModel().isRollover() && b.getModel().isArmed()) 
+        || b.getModel().isSelected())
+      paintButtonPressed(g, br, c);
 	else
-	    {
-	      //System.out.println("paint normal");
-		paintButtonNormal(g, c);
-	    }
+      paintButtonNormal(g, br, c);
 	
 	paintIcon(g, c, ir);
 	paintText(g, c, tr, b.getText());
 	paintFocus(g, c, vr, tr, ir);
     }
 
-
-    protected void paintFocus(Graphics g, 
-			      JComponent c,
-			      Rectangle vr,
-			      Rectangle tr,
-			      Rectangle ir)
+  /**
+   * Paint any focus decoration this {@link JComponent} might have.  The
+   * component, which in this case will be an {@link AbstractButton},
+   * should only have focus decoration painted if it has the focus, and its
+   * "focusPainted" property is <code>true</code>.
+   *
+   * @param g Graphics context to paint with
+   * @param c Component to paint the focus of
+   * @param vr Visible rectangle, the area in which to paint
+   * @param tr Text rectangle, contained in visible rectangle
+   * @param ir Icon rectangle, contained in visible rectangle
+   *
+   * @see AbstractButton.isFocusPainted()
+   * @see JComponent.hasFocus()
+   */
+  protected void paintFocus(Graphics g, JComponent c, Rectangle vr,
+                            Rectangle tr, Rectangle ir)
+  {
+    AbstractButton b = (AbstractButton) c;
+    if (b.hasFocus() && b.isFocusPainted())
     {
+        Graphics2D g2 = (Graphics2D) g;
+        Stroke saved_stroke = g2.getStroke();
+        Color saved_color = g2.getColor();
+        float dashes[] = new float[] {1.0f, 1.0f};        
+        BasicStroke s = new BasicStroke(1.0f, 
+                                        BasicStroke.CAP_SQUARE, 
+                                        BasicStroke.JOIN_MITER,
+                                        10, dashes, 0.0f);
+        g2.setStroke(s);
+        g2.setColor(Color.BLACK);
+        g2.drawRect(vr.x + 2, 
+                    vr.y + 2, 
+                    vr.width - 4,
+                    vr.height - 4);
+        g2.setStroke(saved_stroke);
+        g2.setColor(saved_color);
+      }
     }
 
-    protected void paintIcon(Graphics g, 
-			     JComponent c, 
-			     Rectangle iconRect)
+  /**
+   * Paint the icon for this component. Depending on the state of the
+   * component and the availability of the button's various icon
+   * properties, this might mean painting one of several different icons.
+   *
+   * @param g Graphics context to paint with
+   * @param c Component to paint the icon of
+   * @param iconRect Rectangle in which the icon should be painted
+   */
+  protected void paintIcon(Graphics g, JComponent c, Rectangle iconRect)
     {
 	AbstractButton b = (AbstractButton) c;
 	if (b.getIcon() != null)
 	    {
 		int x = iconRect.x;
 		int y = iconRect.y;
-
-		System.out.println("WE HAVE AN ICON: " + b.getIcon());
- 
 		b.getIcon().paintIcon(c, g, x, y);
 	    }
-	else
-	    {
-		//System.out.println("NO ICON FOR BUTTON:" + b.text);
-	    }
     }
 
-    protected void paintButtonPressed(Graphics g,
-				      JComponent b)
+  /**
+   * Paints the background area of an {@link AbstractButton} in the pressed
+   * state.  This means filling the supplied area with the {@link
+   * pressedBackgroundColor}.
+   *
+   * @param g The graphics context to paint with
+   * @param area The area in which to paint
+   * @param b The component to paint the state of
+   */
+  protected void paintButtonPressed(Graphics g, Rectangle area, JComponent b)
     {
 	Dimension size = b.getSize();
 	
 	g.setColor(pressedBackgroundColor);
-	g.fillRect(1,1,size.width-2, size.height-2);                
-
+    g.fillRect(area.x, area.y, area.width, area.height);
     }
     
-    protected void paintButtonNormal(Graphics g,
-				     JComponent b)
+  /**
+   * Paints the background area of an {@link AbstractButton} in the normal,
+   * non-pressed state.  This means filling the supplied area with the
+   * {@link normalBackgroundColor}.
+   *
+   * @param g The graphics context to paint with
+   * @param area The area in which to paint
+   * @param b The component to paint the state of
+   */
+  protected void paintButtonNormal(Graphics g, Rectangle area, JComponent b)
     {
 	Dimension size = b.getSize();
-	
 	g.setColor(normalBackgroundColor);
-	g.fillRect(1,1,size.width-2, size.height-2);                
-
+    g.fillRect(area.x, area.y, area.width, area.height);
     }
     
-    protected void paintText(Graphics g,
-			     JComponent c,
-			     Rectangle textRect,
+  /**
+   * Paints the "text" property of an {@link AbstractButton}, using the
+   * {@link textColor} color.
+   *
+   * @param g The graphics context to paint with
+   * @param c The component to paint the state of
+   * @param textRect The area in which to paint the text
+   * @param text The text to paint
+   */
+  protected void paintText(Graphics g, JComponent c, Rectangle textRect,
 			     String text) 
     {	
 	Font f = c.getFont();
-
         g.setFont(f);
-
         FontMetrics fm = g.getFontMetrics(f);
-
 	g.setColor(c.isEnabled() ? textColor : disabledTextColor);
-
-	BasicGraphicsUtils.drawString(g,
-				      text, 
+    BasicGraphicsUtils.drawString(g, text, 
 				      0,
 				      textRect.x, 
-				      textRect.y + fm.getAscent()/2);
+                                  textRect.y + fm.getAscent());
     } 
 }
-
-
-
-
Index: javax/swing/plaf/basic/BasicGraphicsUtils.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/javax/swing/plaf/basic/BasicGraphicsUtils.java,v
retrieving revision 1.4
diff -u -b -w -r1.4 BasicGraphicsUtils.java
--- javax/swing/plaf/basic/BasicGraphicsUtils.java	1 Aug 2003 20:10:22 -0000	1.4
+++ javax/swing/plaf/basic/BasicGraphicsUtils.java	22 Jan 2004 09:53:47 -0000
@@ -595,6 +595,7 @@
     Rectangle iconRect = new Rectangle();
     Rectangle textRect = new Rectangle();
     Insets insets = b.getInsets();
+    Insets margin = b.getMargin();
     
     /* For determining the ideal size, do not assume a size restriction. */
     viewRect = new Rectangle(0, 0,
@@ -620,7 +621,6 @@
       viewRect, iconRect, textRect,
       textIconGap);
 
-
     /*  +------------------------+       +------------------------+
      *  |                        |       |                        |
      *  | ICON                   |       | CONTENTCONTENTCONTENT  |
@@ -630,7 +630,11 @@
      */
     contentRect = textRect.union(iconRect);
 
-    return new Dimension(insets.left + contentRect.width + insets.right,
-                         insets.top + contentRect.height + insets.bottom);
+    return new Dimension(insets.left + margin.left
+			 + contentRect.width 
+			 + insets.right + margin.right,
+                         insets.top + margin.top
+			 + contentRect.height 
+			 + insets.bottom + margin.bottom);
   }
 }
Index: jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c,v
retrieving revision 1.18
diff -u -b -w -r1.18 gnu_java_awt_peer_gtk_GtkWindowPeer.c
--- jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c	21 Jan 2004 20:11:08 -0000	1.18
+++ jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c	22 Jan 2004 09:53:47 -0000
@@ -228,11 +228,24 @@
 {
   void *ptr = NSA_GET_PTR (env, obj);
   jobject *gref = NSA_GET_GLOBAL_REF (env, obj);
+  GtkWidget* vbox, *layout;
+  GList* children;
   g_assert (gref);
 
   gdk_threads_enter ();
 
   gtk_widget_realize (ptr);
+
+  /* Receive events from the GtkLayout too */
+  children = gtk_container_get_children(GTK_CONTAINER(ptr));
+  vbox = children->data;  
+  g_assert(GTK_IS_VBOX(vbox));
+  children = gtk_container_get_children(GTK_CONTAINER(vbox));
+  layout = children->data;  
+  g_assert(GTK_IS_LAYOUT(layout));
+
+  g_signal_connect (GTK_OBJECT (layout), "event", 
+		    G_CALLBACK (pre_event_handler), *gref);
 
   /* Connect signals for window event support. */
   g_signal_connect (G_OBJECT (ptr), "delete-event",

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]