JDK-4913373 : Memory Leak in JColorChooser due to extra calls to buildChooser()
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_nt
  • CPU: x86
  • Submitted: 2003-08-27
  • Updated: 2004-10-25
  • Resolved: 2004-10-25
Related Reports
Duplicate :  
Description
Name: keR10081			Date: 08/27/2003


In current implementation of the PropertyChangeListener that handles
change of CHOOSER_PANELS_PROPERTY we do things wrong. Namely, we delete
all old panels, then add all new panels and call installChooserPanel on
each of the new panels. This leads us to calling this method several
times on the panels which are present both in old and new panels. This
call in turn calls buildChooser which adds contents of the panel to it
once again. This is not noticeable in metal/motif/windows LaFs, since it
adds the contents to the BorderLayout.CEnTER, so there is no visual
appearance of the bug, only memory leak, but is well noticeable with GTK
LaF, where we have FlowLayout and thus see ugly chooser panel. This
could be seen running test case, which simply adds a custom panel to a
GTK color chooser, causing it to look ugly.

Test case:
import javax.swing.*;
import java.awt.event.*;

import javax.swing.colorchooser.AbstractColorChooserPanel;
public class ColorChooserBug {
	public static void main(String[] args) {

try{UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");} 

catch(Exception ex){ex.printStackTrace();}
		final JFrame frame = new JFrame("Test");
		JColorChooser cc = new JColorChooser();
		cc.addChooserPanel(new AbstractColorChooserPanel() {
			public void updateChooser() {}
			protected void buildChooser() {
                         removeAll();
				add(new JLabel("This is an added panel"));
			}
			public String getDisplayName() {
				return "Added Tab";
			}
			public Icon getSmallDisplayIcon() { return null;}
			public Icon getLargeDisplayIcon() { return null;}
		});
		frame.getContentPane().add(cc);
		frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		frame.pack();
		frame.show();
	}
}

======================================================================
###@###.### 10/25/04 12:39 GMT

Comments
SUGGESTED FIX Name: keR10081 Date: 08/29/2003 *** /net/diablo/export2/swing/kve/tiger/webrev/src/share/classes/javax/swing/plaf/basic/BasicColorChooserUI.java- ?? ??? 29 16:03:52 2003 --- BasicColorChooserUI.java ?? ??? 29 15:47:11 2003 *************** *** 66,72 **** protected void uninstallDefaultChoosers() { AbstractColorChooserPanel[] choosers = chooser.getChooserPanels(); for( int i = 0 ; i < choosers.length; i++) { ! chooser.removeChooserPanel( choosers[i] ); } } --- 66,76 ---- protected void uninstallDefaultChoosers() { AbstractColorChooserPanel[] choosers = chooser.getChooserPanels(); for( int i = 0 ; i < choosers.length; i++) { ! for( int j = 0 ; j < defaultChoosers.length; j++) { ! if (choosers[i] == defaultChoosers[j]) { ! chooser.removeChooserPanel( choosers[i] ); ! } ! } } } *************** *** 85,94 **** chooser.setLayout( new BorderLayout() ); defaultChoosers = createDefaultChoosers(); ! chooser.setChooserPanels(defaultChoosers); ! previewPanelHolder = new JPanel(new CenterLayout()); previewPanelHolder.setName("ColorChooser.previewPanelHolder"); if (DefaultLookup.getBoolean(chooser, this, --- 89,102 ---- chooser.setLayout( new BorderLayout() ); + AbstractColorChooserPanel[] choosers = chooser.getChooserPanels(); defaultChoosers = createDefaultChoosers(); ! chooser.setChooserPanels(defaultChoosers); ! for( int i = 0 ; i < choosers.length; i++) { ! chooser.addChooserPanel(choosers[i]); ! } ! previewPanelHolder = new JPanel(new CenterLayout()); previewPanelHolder.setName("ColorChooser.previewPanelHolder"); if (DefaultLookup.getBoolean(chooser, this, *************** *** 97,103 **** "ColorChooser.previewText", chooser.getLocale()); previewPanelHolder.setBorder(new TitledBorder(previewString)); } ! chooser.add(previewPanelHolder, BorderLayout.SOUTH); installPreviewPanel(); chooser.applyComponentOrientation(c.getComponentOrientation()); --- 105,111 ---- "ColorChooser.previewText", chooser.getLocale()); previewPanelHolder.setBorder(new TitledBorder(previewString)); } ! chooser.add(previewPanelHolder, BorderLayout.SOUTH); installPreviewPanel(); chooser.applyComponentOrientation(c.getComponentOrientation()); *************** *** 232,245 **** (AbstractColorChooserPanel[])evt.getOldValue(); AbstractColorChooserPanel[] newPanels = (AbstractColorChooserPanel[])evt.getNewValue(); ! for (int i = 0; i < oldPanels.length; i++) { // remove old panels ! Container wrapper = oldPanels[i].getParent(); ! if (wrapper != null) { ! Container parent = wrapper.getParent(); ! if (parent != null) ! parent.remove(wrapper); // remove from hierarchy ! oldPanels[i].uninstallChooserPanel(chooser); // uninstall } } --- 240,261 ---- (AbstractColorChooserPanel[])evt.getOldValue(); AbstractColorChooserPanel[] newPanels = (AbstractColorChooserPanel[])evt.getNewValue(); ! ArrayList toKeep = new ArrayList(oldPanels.length); ! for (int i = 0; i < newPanels.length; i++) { ! for (int j = 0; j < oldPanels.length; j++) { ! if (newPanels[i] == oldPanels[j]) ! toKeep.add(oldPanels[j]); ! } ! } for (int i = 0; i < oldPanels.length; i++) { // remove old panels ! if (!toKeep.contains(oldPanels[i])) { ! Container wrapper = oldPanels[i].getParent(); ! if (wrapper != null) { ! Container parent = wrapper.getParent(); ! if (parent != null) ! parent.remove(wrapper); // remove from hierarchy ! oldPanels[i].uninstallChooserPanel(chooser); // uninstall ! } } } *************** *** 248,254 **** chooser.remove(tabbedPane); return; } ! else if (numNewPanels == 1) { // one panel case chooser.remove(tabbedPane); JPanel centerWrapper = new JPanel( new CenterLayout() ); centerWrapper.add(newPanels[0]); --- 264,270 ---- chooser.remove(tabbedPane); return; } ! else if ((numNewPanels == 1) && (toKeep.size() == 0)) { // one panel case chooser.remove(tabbedPane); JPanel centerWrapper = new JPanel( new CenterLayout() ); centerWrapper.add(newPanels[0]); *************** *** 256,282 **** chooser.add(singlePanel); } else { // multi-panel case ! if ( oldPanels.length < 2 ) {// moving from single to multiple chooser.remove(singlePanel); - chooser.add(tabbedPane, BorderLayout.CENTER); - } - - for (int i = 0; i < newPanels.length; i++) { JPanel centerWrapper = new JPanel( new CenterLayout() ); ! String name = newPanels[i].getDisplayName(); ! int mnemonic = newPanels[i].getMnemonic(); ! centerWrapper.add(newPanels[i]); tabbedPane.addTab(name, centerWrapper); ! if (mnemonic > 0) { ! tabbedPane.setMnemonicAt(i, mnemonic); ! tabbedPane.setDisplayedMnemonicIndexAt( ! i, newPanels[i].getDisplayedMnemonicIndex()); } } } chooser.applyComponentOrientation(chooser.getComponentOrientation()); for (int i = 0; i < newPanels.length; i++) { ! newPanels[i].installChooserPanel(chooser); } } --- 272,307 ---- chooser.add(singlePanel); } else { // multi-panel case ! if ((oldPanels.length == 1) && (toKeep.size() == 1)) {// moving from single to multiple chooser.remove(singlePanel); JPanel centerWrapper = new JPanel( new CenterLayout() ); ! String name = oldPanels[0].getDisplayName(); ! int mnemonic = oldPanels[0].getMnemonic(); ! centerWrapper.add(oldPanels[0]); tabbedPane.addTab(name, centerWrapper); ! ! } ! chooser.add(tabbedPane, BorderLayout.CENTER); ! ! for (int i = 0; i < newPanels.length; i++) { ! if (!toKeep.contains(newPanels[i])) { ! JPanel centerWrapper = new JPanel( new CenterLayout() ); ! String name = newPanels[i].getDisplayName(); ! int mnemonic = newPanels[i].getMnemonic(); ! centerWrapper.add(newPanels[i]); ! tabbedPane.addTab(name, centerWrapper); ! if (mnemonic > 0) { ! tabbedPane.setMnemonicAt(i, mnemonic); ! tabbedPane.setDisplayedMnemonicIndexAt( ! i, newPanels[i].getDisplayedMnemonicIndex()); ! } } } } chooser.applyComponentOrientation(chooser.getComponentOrientation()); for (int i = 0; i < newPanels.length; i++) { ! if (!toKeep.contains(newPanels[i])) ! newPanels[i].installChooserPanel(chooser); } } *************** *** 314,320 **** super("color"); } } ! } --- 339,345 ---- super("color"); } } ! } ======================================================================
25-09-2004

EVALUATION Name: keR10081 Date: 08/27/2003 We need to call installChooserPanel only once for each of the panels. ###@###.### ====================================================================== Name: keR10081 Date: 08/29/2003 We need to apply the suggested fix to correct problem. ###@###.### ====================================================================== This problem has been partly (visual appearance of GTK ColorChooser) solved by changing layout for GTKColorChooser. All the remaining issues would be resolved as part of fix for bug 4898630, since it makes sense to fix these bugs together. Closing this bug as a duplicate of 4898630. ###@###.### 10/25/04 12:39 GMT
25-10-0004