Skip to content

Commit

Permalink
ComboBox: fixed occasional StackOverflowError when modifying combo …
Browse files Browse the repository at this point in the history
…box not on AWT thread (issue #432)
  • Loading branch information
DevCharly committed Dec 6, 2021
1 parent 269eb0b commit 7f4efaf
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 5 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ FlatLaf Change Log

## 1.6.5-SNAPSHOT

#### Fixed bugs

- Linux: Fixed font problems when running on Oracle Java 8 (OpenJDK 8 is not
affected):
- oversized text if system font is "Inter" (issue #427)
- missing text if system font is "Cantarell" (on Fedora)
- MenuItem: Changed accelerator delimiter from `-` to `+`. (Windows and Linux).

- ComboBox: Fixed occasional `StackOverflowError` when modifying combo box not
on AWT thread. (issue #432)

## 1.6.4

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,9 @@ private static class CellPaddingBorder
this.padding = padding;
}

void install( Component c ) {
// using synchronized to avoid problems with code that modifies combo box
// (model, selection, etc) not on AWT thread (which should be not done)
synchronized void install( Component c ) {
if( !(c instanceof JComponent) )
return;

Expand Down Expand Up @@ -837,7 +839,7 @@ void install( Component c ) {
* there is no single place to uninstall it.
* This is the reason why this method is called from various places.
*/
void uninstall() {
synchronized void uninstall() {
if( rendererComponent == null )
return;

Expand All @@ -848,9 +850,9 @@ void uninstall() {
}

@Override
public Insets getBorderInsets( Component c, Insets insets ) {
synchronized public Insets getBorderInsets( Component c, Insets insets ) {
Insets padding = scale( this.padding );
if( rendererBorder != null ) {
if( rendererBorder != null && !(rendererBorder instanceof CellPaddingBorder) ) {
Insets insideInsets = rendererBorder.getBorderInsets( c );
insets.top = Math.max( padding.top, insideInsets.top );
insets.left = Math.max( padding.left, insideInsets.left );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright 2021 FormDev Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.formdev.flatlaf.testing;

import java.awt.Container;
import java.awt.FlowLayout;
import java.util.Random;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLightLaf;

/**
* @author Karl Tauber
*/
public class FlatStressTest
{
public static void main( String[] args ) {
SwingUtilities.invokeLater( () -> {
FlatLightLaf.setup();
new FlatStressTest();
} );
}

protected FlatStressTest() {
JFrame frame = new JFrame( "FlatStressTest" );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

Container contentPane = frame.getContentPane();
contentPane.setLayout( new FlowLayout() );

contentPane.add( createStressTest() );

frame.setSize( 800, 600 );
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}

private JComponent createStressTest() {
return createComboBoxStressTest();
}

// for https://github.com/JFormDesigner/FlatLaf/issues/432
// simulates StackOverflowError in FlatComboBoxUI when doing stuff in various threads
//
// requires adding `Thread.sleep( 1 );` to `FlatComboBoxUI.CellPaddingBorder.install()`
// after invocation of `uninstall()`
private JComponent createComboBoxStressTest() {
Random random = new Random();

JComboBox<String> comboBox = new JComboBox<>();
comboBox.putClientProperty( FlatClientProperties.MINIMUM_WIDTH, 0 );
for( int i = 0; i < 100; i++ )
comboBox.addItem( Integer.toString( random.nextInt() ) );

Thread thread = new Thread( () -> {
for(;;) {
comboBox.setSelectedIndex( random.nextInt( comboBox.getItemCount() ) );
comboBox.putClientProperty( FlatClientProperties.MINIMUM_WIDTH, random.nextInt( 500 ) );
}
});
thread.setDaemon( true );
thread.start();

return comboBox;
}
}

0 comments on commit 7f4efaf

Please sign in to comment.