diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c234a2d..34acbce9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ FlatLaf Change Log - Updated "Hiberbee Dark" and "Material Theme UI Lite" themes. - Styling: Fixed resolving of UI variables in styles that use other variables. - 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 `DefaultTreeCellRenderer`. (issue #653; regression since implementing PR #609 in FlatLaf 3.0) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableCellBorder.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableCellBorder.java index 254cd352..81e4f37b 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableCellBorder.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableCellBorder.java @@ -113,11 +113,24 @@ public class FlatTableCellBorder /** * 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. + *
+ * To avoid possible performance issues, checking for editable cell is limited + * to {@link #maxCheckCellsEditable}. */ public static class Selected extends FlatTableCellBorder { + /** @since 3.1 */ + public int maxCheckCellsEditable = 50; + @Override public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { Boolean b = getStyleFromTableUI( c, ui -> ui.showCellFocusIndicator ); @@ -125,7 +138,7 @@ public class FlatTableCellBorder if( !showCellFocusIndicator ) { JTable table = (JTable) SwingUtilities.getAncestorOfClass( JTable.class, c ); - if( table != null && !isSelectionEditable( table ) ) + if( table != null && !shouldShowCellFocusIndicator( table ) ) 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 ) { - if( table.getRowSelectionAllowed() ) { - int columnCount = table.getColumnCount(); - int[] selectedRows = table.getSelectedRows(); - for( int selectedRow : selectedRows ) { - for( int column = 0; column < columnCount; column++ ) { - if( table.isCellEditable( selectedRow, column ) ) - return true; - } - } - } + protected boolean shouldShowCellFocusIndicator( JTable table ) { + // show always for column only selection + // (do not check for editable cells because there may be thousands or millions of rows) + if( !table.getRowSelectionAllowed() ) + return true; + + // do not show if more than one row is selected + // (unlikely that user wants edit cell in this case) + if( table.getSelectedRowCount() != 1 ) + return false; + + int selectedRow = table.getSelectedRow(); if( table.getColumnSelectionAllowed() ) { - int rowCount = table.getRowCount(); - int[] selectedColumns = table.getSelectedColumns(); - for( int selectedColumn : selectedColumns ) { - for( int row = 0; row < rowCount; row++ ) { - if( table.isCellEditable( row, selectedColumn ) ) - return true; - } + // column and row selection are allowed --> cell selection enabled + int selectedColumnCount = table.getSelectedColumnCount(); + + // do not show if exactly one cell is selected + if( selectedColumnCount == 1 ) + 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; } }