ComboBox: reworked uninstall of CellPaddingBorder, which is temporary used for cell renderers, to make it easier to understand and reliable

(tested using FlatCustomBordersTest, FlatNetBeansTest, etc)
This commit is contained in:
Karl Tauber
2021-07-03 10:43:55 +02:00
parent 3e14f28dc2
commit 4507ce359d

View File

@@ -39,7 +39,6 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D; import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.lang.ref.WeakReference;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.CellRendererPane; import javax.swing.CellRendererPane;
@@ -139,7 +138,7 @@ public class FlatComboBoxUI
protected boolean hover; protected boolean hover;
protected boolean pressed; protected boolean pressed;
private WeakReference<Component> lastRendererComponent; private CellPaddingBorder paddingBorder;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
return new FlatComboBoxUI(); return new FlatComboBoxUI();
@@ -228,6 +227,8 @@ public class FlatComboBoxUI
paddingUnscaled = padding; paddingUnscaled = padding;
padding = UIScale.scale( paddingUnscaled ); padding = UIScale.scale( paddingUnscaled );
paddingBorder = new CellPaddingBorder( padding );
MigLayoutVisualPadding.install( comboBox ); MigLayoutVisualPadding.install( comboBox );
} }
@@ -253,6 +254,8 @@ public class FlatComboBoxUI
popupBackground = null; popupBackground = null;
paddingBorder.uninstall();
MigLayoutVisualPadding.uninstall( comboBox ); MigLayoutVisualPadding.uninstall( comboBox );
} }
@@ -476,14 +479,14 @@ public class FlatComboBoxUI
@Override @Override
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
public void paintCurrentValue( Graphics g, Rectangle bounds, boolean hasFocus ) { public void paintCurrentValue( Graphics g, Rectangle bounds, boolean hasFocus ) {
paddingBorder.uninstall();
ListCellRenderer<Object> renderer = comboBox.getRenderer(); ListCellRenderer<Object> renderer = comboBox.getRenderer();
uninstallCellPaddingBorder( renderer );
if( renderer == null ) if( renderer == null )
renderer = new DefaultListCellRenderer(); renderer = new DefaultListCellRenderer();
Component c = renderer.getListCellRendererComponent( listBox, comboBox.getSelectedItem(), -1, false, false ); Component c = renderer.getListCellRendererComponent( listBox, comboBox.getSelectedItem(), -1, false, false );
c.setFont( comboBox.getFont() ); c.setFont( comboBox.getFont() );
c.applyComponentOrientation( comboBox.getComponentOrientation() ); c.applyComponentOrientation( comboBox.getComponentOrientation() );
uninstallCellPaddingBorder( c );
boolean enabled = comboBox.isEnabled(); boolean enabled = comboBox.isEnabled();
c.setBackground( getBackground( enabled ) ); c.setBackground( getBackground( enabled ) );
@@ -537,26 +540,20 @@ public class FlatComboBoxUI
@Override @Override
protected Dimension getDefaultSize() { protected Dimension getDefaultSize() {
@SuppressWarnings( "unchecked" ) paddingBorder.uninstall();
ListCellRenderer<Object> renderer = comboBox.getRenderer();
uninstallCellPaddingBorder( renderer );
Dimension size = super.getDefaultSize(); Dimension size = super.getDefaultSize();
paddingBorder.uninstall();
uninstallCellPaddingBorder( renderer );
return size; return size;
} }
@Override @Override
protected Dimension getDisplaySize() { protected Dimension getDisplaySize() {
@SuppressWarnings( "unchecked" )
ListCellRenderer<Object> renderer = comboBox.getRenderer();
uninstallCellPaddingBorder( renderer );
// update padding // update padding
padding = UIScale.scale( paddingUnscaled ); padding = UIScale.scale( paddingUnscaled );
paddingBorder.uninstall();
Dimension displaySize = super.getDisplaySize(); Dimension displaySize = super.getDisplaySize();
paddingBorder.uninstall();
// recalculate width without hardcoded 100 under special conditions // recalculate width without hardcoded 100 under special conditions
if( displaySize.width == 100 + padding.left + padding.right && if( displaySize.width == 100 + padding.left + padding.right &&
@@ -570,7 +567,6 @@ public class FlatComboBoxUI
displaySize = new Dimension( width, displaySize.height ); displaySize = new Dimension( width, displaySize.height );
} }
uninstallCellPaddingBorder( renderer );
return displaySize; return displaySize;
} }
@@ -597,14 +593,6 @@ public class FlatComboBoxUI
return null; return null;
} }
private void uninstallCellPaddingBorder( Object o ) {
CellPaddingBorder.uninstall( o );
if( lastRendererComponent != null ) {
CellPaddingBorder.uninstall( lastRendererComponent );
lastRendererComponent = null;
}
}
private boolean isCellRenderer() { private boolean isCellRenderer() {
return comboBox.getParent() instanceof CellRendererPane; return comboBox.getParent() instanceof CellRendererPane;
} }
@@ -668,8 +656,6 @@ public class FlatComboBoxUI
protected class FlatComboPopup protected class FlatComboPopup
extends BasicComboPopup extends BasicComboPopup
{ {
private CellPaddingBorder paddingBorder;
protected FlatComboPopup( JComboBox combo ) { protected FlatComboPopup( JComboBox combo ) {
super( combo ); super( combo );
@@ -753,6 +739,19 @@ public class FlatComboBoxUI
}; };
} }
@Override
protected int getPopupHeightForRowCount( int maxRowCount ) {
int height = super.getPopupHeightForRowCount( maxRowCount );
paddingBorder.uninstall();
return height;
}
@Override
protected void paintChildren( Graphics g ) {
super.paintChildren( g );
paddingBorder.uninstall();
}
//---- class PopupListCellRenderer ----- //---- class PopupListCellRenderer -----
private class PopupListCellRenderer private class PopupListCellRenderer
@@ -762,22 +761,15 @@ public class FlatComboBoxUI
public Component getListCellRendererComponent( JList list, Object value, public Component getListCellRendererComponent( JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus ) int index, boolean isSelected, boolean cellHasFocus )
{ {
ListCellRenderer renderer = comboBox.getRenderer(); paddingBorder.uninstall();
CellPaddingBorder.uninstall( renderer );
CellPaddingBorder.uninstall( lastRendererComponent );
ListCellRenderer renderer = comboBox.getRenderer();
if( renderer == null ) if( renderer == null )
renderer = new DefaultListCellRenderer(); renderer = new DefaultListCellRenderer();
Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus ); Component c = renderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
c.applyComponentOrientation( comboBox.getComponentOrientation() ); c.applyComponentOrientation( comboBox.getComponentOrientation() );
if( c instanceof JComponent ) { paddingBorder.install( c );
if( paddingBorder == null )
paddingBorder = new CellPaddingBorder( padding );
paddingBorder.install( (JComponent) c );
}
lastRendererComponent = (c != renderer) ? new WeakReference<>( c ) : null;
return c; return c;
} }
@@ -788,44 +780,57 @@ public class FlatComboBoxUI
/** /**
* Cell padding border used only in popup list. * Cell padding border used only in popup list.
* * <p>
* The insets are the union of the cell padding and the renderer border insets, * The insets are the union of the cell padding and the renderer border insets,
* which vertically aligns text in popup list with text in combobox. * which vertically aligns text in popup list with text in combobox.
* * <p>
* The renderer border is painted on the outside of this border. * The renderer border is painted on the outer side of this border.
*/ */
private static class CellPaddingBorder private static class CellPaddingBorder
extends AbstractBorder extends AbstractBorder
{ {
private final Insets padding; private final Insets padding;
private JComponent rendererComponent;
private Border rendererBorder; private Border rendererBorder;
CellPaddingBorder( Insets padding ) { CellPaddingBorder( Insets padding ) {
this.padding = padding; this.padding = padding;
} }
void install( JComponent rendererComponent ) { void install( Component c ) {
Border oldBorder = rendererComponent.getBorder(); if( !(c instanceof JComponent) )
if( !(oldBorder instanceof CellPaddingBorder) ) {
rendererBorder = oldBorder;
rendererComponent.setBorder( this );
}
}
static void uninstall( Object o ) {
if( o instanceof WeakReference )
o = ((WeakReference<?>)o).get();
if( !(o instanceof JComponent) )
return; return;
JComponent rendererComponent = (JComponent) o; JComponent jc = (JComponent) c;
Border border = rendererComponent.getBorder(); Border oldBorder = jc.getBorder();
if( border instanceof CellPaddingBorder ) { if( oldBorder == this )
CellPaddingBorder paddingBorder = (CellPaddingBorder) border; return; // already installed
rendererComponent.setBorder( paddingBorder.rendererBorder );
paddingBorder.rendererBorder = null; // this border can be installed only at one component
} uninstall();
// remember component where this border was installed for uninstall
rendererComponent = jc;
// remember old border and replace it
rendererBorder = oldBorder;
rendererComponent.setBorder( this );
}
/**
* Uninstall border from previously installed component.
* Because this border is installed in PopupListCellRenderer.getListCellRendererComponent(),
* there is no single place to uninstall it.
* This is the reason why this method is called from various places.
*/
void uninstall() {
if( rendererComponent == null )
return;
if( rendererComponent.getBorder() == this )
rendererComponent.setBorder( rendererBorder );
rendererComponent = null;
rendererBorder = null;
} }
@Override @Override