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;