This fixes one weird NPE (see associated bug report) and I also cleaned
up some inconsistencies that I came over and some warnings that Eclipse
came over :-)

2007-01-06  Roman Kennke  <[EMAIL PROTECTED]>

        PR 30337
        * javax/swing/plaf/basic/BasicComboBoxUI.java
        (installUI): Install popup and list here.
        Don't configure the arrow button and editor here.
        (installComponents): Don't install popup and list here. (Moved
        to installUI). Configure arrow button here and check for null.
        (addEditor): Configure editor here.
        (configureArrowButton): Directly fetch listeners from popup.
        (paintCurrentValue): Removed unused local variables.
        (layoutContainer): Removed unused local variables.
        (PropertyChangeHandler.propertyChange): Don't invalidate minimumSize
        on each property change. Avoid calling getPropertyName() repeatedly.
        Clean up. Call addEditor() when editor changes. Configure and
        unconfigure editor when editable changes. Use 'model' instead
        of non-existing 'dataModel' property.
        * javax/swing/plaf/basic/BasicComboPopup.java
        (uninstallingUI): Remove property change listener and item listener
        here. Uninstall list listeners. Set model to null to prevent leakage.
        (configureList): Don't sync list selection there.
        (uninstallComboBoxListeners): Moved to uninstallingUI.
        (uninstallListeners): Moved to uninstallingUI.
        * javax/swing/plaf/metal/MetalComboBoxUI.java
        (createPopup): Call super.
        (getMinimumSize): Removed unused statement.

/Roman

Index: javax/swing/plaf/basic/BasicComboBoxUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicComboBoxUI.java,v
retrieving revision 1.40
diff -u -1 -5 -r1.40 BasicComboBoxUI.java
--- javax/swing/plaf/basic/BasicComboBoxUI.java	24 Jul 2006 15:04:05 -0000	1.40
+++ javax/swing/plaf/basic/BasicComboBoxUI.java	6 Jan 2007 15:38:45 -0000
@@ -203,52 +203,49 @@
    * Installs the UI for the given [EMAIL PROTECTED] JComponent}.
    *
    * @param c  the JComponent to install a UI for.
    * 
    * @see #uninstallUI(JComponent)
    */
   public void installUI(JComponent c)
   {
     super.installUI(c);
 
     if (c instanceof JComboBox)
       {
         isMinimumSizeDirty = true;
         comboBox = (JComboBox) c;
         installDefaults();
+        popup = createPopup();
+        listBox = popup.getList();
 
         // Set editor and renderer for the combo box. Editor is used
         // only if combo box becomes editable, otherwise renderer is used
         // to paint the selected item; combobox is not editable by default.
         ListCellRenderer renderer = comboBox.getRenderer();
         if (renderer == null || renderer instanceof UIResource)
           comboBox.setRenderer(createRenderer());
 
         ComboBoxEditor currentEditor = comboBox.getEditor();
         if (currentEditor == null || currentEditor instanceof UIResource)
           {
             currentEditor = createEditor();
             comboBox.setEditor(currentEditor);
           } 
-        editor = currentEditor.getEditorComponent();
 
         installComponents();
         installListeners();
-        if (arrowButton != null)
-          configureArrowButton();
-        if (editor != null)
-          configureEditor();
         comboBox.setLayout(createLayoutManager());
         comboBox.setFocusable(true);
         installKeyboardActions();
         comboBox.putClientProperty(BasicLookAndFeel.DONT_CANCEL_POPUP,
                                    Boolean.TRUE);
       }
   }
 
   /**
    * Uninstalls the UI for the given [EMAIL PROTECTED] JComponent}.
    *
    * @param c The JComponent that is having this UI removed.
    * 
    * @see #installUI(JComponent)
    */
@@ -461,37 +458,35 @@
    * @return A new component that will be responsible for displaying/editing
    *         the selected item in the combo box.
    */
   protected ComboBoxEditor createEditor()
   {
     return new BasicComboBoxEditor.UIResource();
   }
 
   /**
    * Installs the components for this JComboBox. ArrowButton, main
    * part of combo box (upper part) and popup list of items are created and
    * configured here.
    */
   protected void installComponents()
   {
-    // create drop down list of items
-    popup = createPopup();
-    listBox = popup.getList();
-
     // create and install arrow button
     arrowButton = createArrowButton();
     comboBox.add(arrowButton);
+    if (arrowButton != null)
+      configureArrowButton();
 
     if (comboBox.isEditable())
       addEditor();
 
     comboBox.add(currentValuePane);
   }
 
   /**
    * Uninstalls components from this [EMAIL PROTECTED] JComboBox}.
    * 
    * @see #installComponents()
    */
   protected void uninstallComponents()
   {
     // uninstall arrow button
@@ -509,31 +504,35 @@
     ComboBoxEditor currentEditor = comboBox.getEditor();
     if (currentEditor instanceof UIResource)
       {
         comboBox.setEditor(null);
         editor = null;
       }
   }
 
   /**
    * Adds the current editor to the combo box.
    */
   public void addEditor()
   {
     removeEditor();
     editor = comboBox.getEditor().getEditorComponent();
-    comboBox.add(editor);
+    if (editor != null)
+      {
+        configureEditor();
+        comboBox.add(editor);
+      }
   }
 
   /**
    * Removes the current editor from the combo box.
    */
   public void removeEditor()
   {
     if (editor != null)
       {
         unconfigureEditor();
         comboBox.remove(editor);
       }
   }
 
   /**
@@ -560,34 +559,32 @@
     if (keyListener != null)
       editor.removeKeyListener(keyListener);
   }
 
   /**
    * Configures the arrow button.
    * 
    * @see #configureArrowButton()
    */
   public void configureArrowButton()
   {
     if (arrowButton != null)
       {
         arrowButton.setEnabled(comboBox.isEnabled());
         arrowButton.setFocusable(false);
-        if (popupMouseListener != null)
-          arrowButton.addMouseListener(popupMouseListener);
-        if (popupMouseMotionListener != null)
-          arrowButton.addMouseMotionListener(popupMouseMotionListener);
+        arrowButton.addMouseListener(popup.getMouseListener());
+        arrowButton.addMouseMotionListener(popup.getMouseMotionListener());
         
         // Mark the button as not closing the popup, we handle this ourselves.
         arrowButton.putClientProperty(BasicLookAndFeel.DONT_CANCEL_POPUP,
                                       Boolean.TRUE);
       }
   }
 
   /**
    * Unconfigures the arrow button.
    * 
    * @see #configureArrowButton()
    *
    * @specnote The specification says this method is implementation specific
    *           and should not be used or overridden.
    */
@@ -843,33 +840,30 @@
   {
     return comboBox.getInsets();
   }
 
   /**
    * Paints currently selected value in the main part of the combo
    * box (part without popup).
    *
    * @param g graphics context
    * @param bounds Rectangle representing the size of the area in which
    *        selected item should be drawn
    * @param hasFocus true if combo box has focus and false otherwise
    */
   public void paintCurrentValue(Graphics g, Rectangle bounds, boolean hasFocus)
   {
-    Object currentValue = comboBox.getSelectedItem();
-    boolean isPressed = arrowButton.getModel().isPressed();
-
     /* Gets the component to be drawn for the current value.
      * If there is currently no selected item we will take an empty
      * String as replacement.
      */
     ListCellRenderer renderer = comboBox.getRenderer();
     if (comboBox.getSelectedIndex() != -1)
       {
         Component comp;
         if (hasFocus && ! isPopupVisible(comboBox))
           {
             comp = renderer.getListCellRendererComponent(listBox,
                 comboBox.getSelectedItem(), -1, true, false);
           }
         else
           {
@@ -1097,31 +1091,30 @@
 
     /**
      * Arranges the components in the container.  It puts arrow
      * button right end part of the comboBox. If the comboBox is editable
      * then editor is placed to the left of arrow  button, starting from the
      * beginning.
      *
      * @param parent Container that should be layed out.
      */
     public void layoutContainer(Container parent)
     {
       // Position editor component to the left of arrow button if combo box is 
       // editable
       Insets i = getInsets();
       int arrowSize = comboBox.getHeight() - (i.top + i.bottom);
-      int editorWidth = comboBox.getBounds().width - arrowSize;
 
       if (arrowButton != null)
         arrowButton.setBounds(comboBox.getWidth() - (i.right + arrowSize),
                               i.top, arrowSize, arrowSize);
       if (editor != null)
         editor.setBounds(rectangleForCurrentValue());
     }
   }
 
   /**
    * Handles focus changes occuring in the combo box. This class is
    * responsible for repainting combo box whenever focus is gained or lost
    * and also for hiding popup list of items whenever combo box loses its
    * focus.
    */
@@ -1333,65 +1326,80 @@
      * Creates a new instance.
      */
     public PropertyChangeHandler()
     {
       // Nothing to do here.
     }
 
     /**
      * Invoked whenever bound property of JComboBox changes.
      * 
      * @param e  the event.
      */
     public void propertyChange(PropertyChangeEvent e)
     {
       // Lets assume every change invalidates the minimumsize.
-      isMinimumSizeDirty = true;
-
-      if (e.getPropertyName().equals("enabled"))
+      String propName = e.getPropertyName();
+      if (propName.equals("enabled"))
         {
-          arrowButton.setEnabled(comboBox.isEnabled());
+          boolean enabled = comboBox.isEnabled();
+          if (editor != null)
+            editor.setEnabled(enabled);
+          if (arrowButton != null)
+            arrowButton.setEnabled(enabled);
 
-          if (comboBox.isEditable())
-            comboBox.getEditor().getEditorComponent().setEnabled(
-                comboBox.isEnabled());
+          comboBox.repaint();
+        }
+      else if (propName.equals("editor"))
+        {
+          addEditor();
+          comboBox.revalidate();
         }
       else if (e.getPropertyName().equals("editable"))
         {
           if (comboBox.isEditable())
             {
-              configureEditor();
               addEditor();
             }
           else
             {
-              unconfigureEditor();
               removeEditor();
             }
 
           comboBox.revalidate();
-          comboBox.repaint();
         }
-      else if (e.getPropertyName().equals("dataModel"))
+      else if (e.getPropertyName().equals("model"))
         {
           // remove ListDataListener from old model and add it to new model
           ComboBoxModel oldModel = (ComboBoxModel) e.getOldValue();
-          if (oldModel != null)
+          if (oldModel != null && listDataListener != null)
             oldModel.removeListDataListener(listDataListener);
 
-          if ((ComboBoxModel) e.getNewValue() != null)
+          ComboBoxModel newModel = (ComboBoxModel) e.getNewValue();
+          if (newModel != null && listDataListener != null)
             comboBox.getModel().addListDataListener(listDataListener);
+
+          if (editor != null)
+            {
+              comboBox.configureEditor(comboBox.getEditor(),
+                                       comboBox.getSelectedItem());
+            }
+          isMinimumSizeDirty = true;
+          comboBox.revalidate();
+          comboBox.repaint();
         }
       else if (e.getPropertyName().equals("font"))
         {
           Font font = (Font) e.getNewValue();
-          editor.setFont(font);
+          if (editor != null)
+            {
+              editor.setFont(font);
+            }
           listBox.setFont(font);
-          arrowButton.setFont(font);
+          isMinimumSizeDirty = true;
           comboBox.revalidate();
-          comboBox.repaint();
         }
 
       // FIXME: Need to handle changes in other bound properties.       
     }
   }
 }
Index: javax/swing/plaf/basic/BasicComboPopup.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicComboPopup.java,v
retrieving revision 1.19
diff -u -1 -5 -r1.19 BasicComboPopup.java
--- javax/swing/plaf/basic/BasicComboPopup.java	13 Jun 2006 09:28:57 -0000	1.19
+++ javax/swing/plaf/basic/BasicComboPopup.java	6 Jan 2007 15:38:45 -0000
@@ -259,33 +259,42 @@
    * Returns KeyListener listening to key events occuring in the combo box.
    * This method returns null because KeyHandler is not longer used.
    *
    * @return KeyListener
    */
   public KeyListener getKeyListener()
   {
     return keyListener;
   }
 
   /**
    * This method uninstalls the UI for the  given JComponent.
    */
   public void uninstallingUI()
   {
+    if (propertyChangeListener != null)
+      {
+        comboBox.removePropertyChangeListener(propertyChangeListener);
+      }
+    if (itemListener != null)
+      {
+        comboBox.removeItemListener(itemListener);
+      }
     uninstallComboBoxModelListeners(comboBox.getModel());
-    uninstallListeners();
     uninstallKeyboardActions();
+    uninstallListListeners();
+    list.setModel(null);
   }
 
   /**
    * This method uninstalls listeners that were listening to changes occuring
    * in the comb box's data model
    *
    * @param model data model for the combo box from which to uninstall
    *        listeners
    */
   protected void uninstallComboBoxModelListeners(ComboBoxModel model)
   {
     model.removeListDataListener(listDataListener);
   }
 
   /**
@@ -454,31 +463,30 @@
    * This method configures the list of comboBox's items by setting  default
    * properties and installing listeners.
    */
   protected void configureList()
   {
     list.setFont(comboBox.getFont());
     list.setForeground(comboBox.getForeground());
     list.setBackground(comboBox.getBackground());
     Color sfg = UIManager.getColor("ComboBox.selectionForeground");
     list.setSelectionForeground(sfg);
     Color sbg = UIManager.getColor("ComboBox.selectionBackground");
     list.setSelectionBackground(sbg);
     list.setBorder(null);
     list.setCellRenderer(comboBox.getRenderer());
     list.setFocusable(false);
-    syncListSelection();
     list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
     installListListeners();
   }
 
   /**
    * This method installs list listeners.
    */
   protected void installListListeners()
   {
     // mouse listener listening to mouse events occuring in the 
     // combo box's list of items.
     listMouseListener = createListMouseListener();
     list.addMouseListener(listMouseListener);
 
     // mouse listener listening to mouse motion events occuring in the
@@ -998,64 +1006,42 @@
           uninstallComboBoxModelListeners(oldModel);
           ComboBoxModel newModel = (ComboBoxModel) e.getNewValue();
           list.setModel(newModel);
           installComboBoxModelListeners(newModel);
           if (comboBox.getItemCount() > 0)
             comboBox.setSelectedIndex(0);
           if (isVisible())
             hide();
         }
     }
   }
 
   // ------ private helper methods --------------------
 
   /**
-   * This method uninstalls listeners installed by the UI
-   */
-  private void uninstallListeners()
-  {
-    uninstallComboBoxListeners();
-    uninstallComboBoxModelListeners(comboBox.getModel());
-  }
-
-  /**
    * This method uninstalls Listeners registered with combo boxes list of
    * items
    */
   private void uninstallListListeners()
   {
     list.removeMouseListener(listMouseListener);
     listMouseListener = null;
 
     list.removeMouseMotionListener(listMouseMotionListener);
     listMouseMotionListener = null;
   }
 
-  /**
-   * This method uninstalls listeners listening to combo box  associated with
-   * this popup menu
-   */
-  private void uninstallComboBoxListeners()
-  {
-    comboBox.removeItemListener(itemListener);
-    itemListener = null;
-
-    comboBox.removePropertyChangeListener(propertyChangeListener);
-    propertyChangeListener = null;
-  }
-
   void syncListSelection()
   {
     int index = comboBox.getSelectedIndex();
     if (index == -1)
       list.clearSelection();
     else
       list.setSelectedIndex(index);
   }
 
   // --------------------------------------------------------------------
   //  The following classes are here only for backwards API compatibility
   //  They aren't used.
   // --------------------------------------------------------------------
 
   /**
Index: javax/swing/plaf/metal/MetalComboBoxUI.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/plaf/metal/MetalComboBoxUI.java,v
retrieving revision 1.12
diff -u -1 -5 -r1.12 MetalComboBoxUI.java
--- javax/swing/plaf/metal/MetalComboBoxUI.java	21 Mar 2006 14:58:20 -0000	1.12
+++ javax/swing/plaf/metal/MetalComboBoxUI.java	6 Jan 2007 15:38:45 -0000
@@ -205,31 +205,31 @@
    * 
    * @return An editor.
    */
   protected ComboBoxEditor createEditor()
   {
     return new MetalComboBoxEditor.UIResource();   
   }
   
   /**
    * Creates a popup for the combo box.
    * 
    * @return A popup.
    */
   protected ComboPopup createPopup()
   {
-    return new MetalComboPopup(comboBox);
+    return super.createPopup();
   }
   
   /**
    * Creates a new button for use in rendering the JComboBox.
    * 
    * @return A button.
    */
   protected JButton createArrowButton()
   {
     JButton button = new MetalComboBoxButton(comboBox, new MetalComboBoxIcon(), 
             new CellRendererPane(), listBox);  
     button.setMargin(new Insets(0, 1, 1, 3));
     return button;
   }
   
@@ -293,31 +293,30 @@
    * @param c  the component
    * 
    * @return The minimum size for the combo box.
    */
   public Dimension getMinimumSize(JComponent c)
   {
     if (!isMinimumSizeDirty)
       return new Dimension(cachedMinimumSize);
 
     Dimension d;
     if (!comboBox.isEditable() && arrowButton != null
         && arrowButton instanceof MetalComboBoxButton)
       {
         MetalComboBoxButton b = (MetalComboBoxButton) arrowButton;
         d = getDisplaySize();
-        Insets insets = b.getInsets();
         Insets arrowInsets = b.getInsets();
         Insets comboInsets = comboBox.getInsets();
         Icon icon = b.getComboIcon();
         d.width += comboInsets.left + comboInsets.right;
         d.width += arrowInsets.left + arrowInsets.right;
         d.width += arrowInsets.right + icon.getIconWidth();
         d.height += comboInsets.top + comboInsets.bottom;
         d.height += arrowInsets.top + arrowInsets.bottom;
       }
     else if (comboBox.isEditable() && arrowButton != null && editor != null)
       {
         d = super.getMinimumSize(c);
         Insets arrowMargin = arrowButton.getMargin();
         d.height += arrowMargin.top + arrowMargin.bottom;
         d.width += arrowMargin.left + arrowMargin.right;

Reply via email to