Table: fixed potential performance issue with paint cell focus indicator border (issue #654)

This commit is contained in:
Karl Tauber
2023-03-27 16:37:02 +02:00
parent 778def118a
commit d27a246dfe
2 changed files with 60 additions and 21 deletions

View File

@@ -38,6 +38,8 @@ FlatLaf Change Log
- Updated "Hiberbee Dark" and "Material Theme UI Lite" themes. - Updated "Hiberbee Dark" and "Material Theme UI Lite" themes.
- Styling: Fixed resolving of UI variables in styles that use other variables. - Styling: Fixed resolving of UI variables in styles that use other variables.
- MenuItem: Fixed horizontal alignment of icons. (issue #631) - MenuItem: Fixed horizontal alignment of icons. (issue #631)
- Table: Fixed potential performance issue with paint cell focus indicator
border. (issue #654)
- Tree: Fixed missing custom closed/opened/leaf icons of a custom - Tree: Fixed missing custom closed/opened/leaf icons of a custom
`DefaultTreeCellRenderer`. (issue #653; regression since implementing PR #609 `DefaultTreeCellRenderer`. (issue #653; regression since implementing PR #609
in FlatLaf 3.0) in FlatLaf 3.0)

View File

@@ -113,11 +113,24 @@ public class FlatTableCellBorder
/** /**
* Border for selected cell that uses margins and paints focus indicator border * Border for selected cell that uses margins and paints focus indicator border
* if enabled (Table.showCellFocusIndicator=true) or at least one selected cell is editable. * <ul>
* <li>if enabled (Table.showCellFocusIndicator=true) or
* <li>if column selection is enabled and row selection disabled or
* <li>if cells in only one row are selected and at least one cell is editable
* </ul>
* The reason for this logic is to hide the focus indicator when it is not needed,
* and only show it when there are editable cells and the user needs to know
* which cell is focused to start editing.
* <p>
* To avoid possible performance issues, checking for editable cell is limited
* to {@link #maxCheckCellsEditable}.
*/ */
public static class Selected public static class Selected
extends FlatTableCellBorder extends FlatTableCellBorder
{ {
/** @since 3.1 */
public int maxCheckCellsEditable = 50;
@Override @Override
public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) {
Boolean b = getStyleFromTableUI( c, ui -> ui.showCellFocusIndicator ); Boolean b = getStyleFromTableUI( c, ui -> ui.showCellFocusIndicator );
@@ -125,7 +138,7 @@ public class FlatTableCellBorder
if( !showCellFocusIndicator ) { if( !showCellFocusIndicator ) {
JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c ); JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c );
if( table != null && !isSelectionEditable( table ) ) if( table != null && !shouldShowCellFocusIndicator( table ) )
return; return;
} }
@@ -133,28 +146,52 @@ public class FlatTableCellBorder
} }
/** /**
* Checks whether at least one selected cell is editable. * Returns whether focus indicator border should be shown.
*
* @since 3.1
*/ */
protected boolean isSelectionEditable( JTable table ) { protected boolean shouldShowCellFocusIndicator( JTable table ) {
if( table.getRowSelectionAllowed() ) { // show always for column only selection
int columnCount = table.getColumnCount(); // (do not check for editable cells because there may be thousands or millions of rows)
int[] selectedRows = table.getSelectedRows(); if( !table.getRowSelectionAllowed() )
for( int selectedRow : selectedRows ) { return true;
for( int column = 0; column < columnCount; column++ ) {
if( table.isCellEditable( selectedRow, column ) ) // do not show if more than one row is selected
return true; // (unlikely that user wants edit cell in this case)
} if( table.getSelectedRowCount() != 1 )
} return false;
}
int selectedRow = table.getSelectedRow();
if( table.getColumnSelectionAllowed() ) { if( table.getColumnSelectionAllowed() ) {
int rowCount = table.getRowCount(); // column and row selection are allowed --> cell selection enabled
int[] selectedColumns = table.getSelectedColumns(); int selectedColumnCount = table.getSelectedColumnCount();
for( int selectedColumn : selectedColumns ) {
for( int row = 0; row < rowCount; row++ ) { // do not show if exactly one cell is selected
if( table.isCellEditable( row, selectedColumn ) ) if( selectedColumnCount == 1 )
return true; return false;
}
// show always if there are too many columns to check for editable
if( selectedColumnCount > maxCheckCellsEditable )
return true;
// check whether at least one selected cell is editable
for( int selectedColumn : table.getSelectedColumns() ) {
if( table.isCellEditable( selectedRow, selectedColumn ) )
return true;
}
} else {
// row selection enabled
int columnCount = table.getColumnCount();
// show always if there are too many columns to check for editable
if( columnCount > maxCheckCellsEditable )
return true;
// check whether at least one selected cell is editable
for( int column = 0; column < columnCount; column++ ) {
if( table.isCellEditable( selectedRow, column ) )
return true;
} }
} }