From 69061cd41c908d0b0784c8c78e542c67f9614ca9 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Thu, 24 Jun 2021 17:57:12 +0200 Subject: [PATCH] Styling: support TableHeader --- .../flatlaf/icons/FlatAscendingSortIcon.java | 29 +++++- .../flatlaf/icons/FlatDescendingSortIcon.java | 12 +-- .../flatlaf/ui/FlatTableHeaderBorder.java | 29 ++++++ .../formdev/flatlaf/ui/FlatTableHeaderUI.java | 91 ++++++++++++++++--- .../formdev/flatlaf/ui/FlatStylingTests.java | 17 ++++ 5 files changed, 156 insertions(+), 22 deletions(-) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatAscendingSortIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatAscendingSortIcon.java index 77ee805a..8456dc0c 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatAscendingSortIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatAscendingSortIcon.java @@ -21,7 +21,11 @@ import java.awt.Color; import java.awt.Component; import java.awt.Graphics2D; import java.awt.geom.Path2D; +import javax.swing.SwingUtilities; import javax.swing.UIManager; +import javax.swing.plaf.TableHeaderUI; +import javax.swing.table.JTableHeader; +import com.formdev.flatlaf.ui.FlatTableHeaderUI; import com.formdev.flatlaf.ui.FlatUIUtils; /** @@ -35,8 +39,8 @@ import com.formdev.flatlaf.ui.FlatUIUtils; public class FlatAscendingSortIcon extends FlatAbstractIcon { - protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) ); - protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" ); + protected boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) ); + protected Color sortIconColor = UIManager.getColor( "Table.sortIconColor" ); public FlatAscendingSortIcon() { super( 10, 5, null ); @@ -44,7 +48,28 @@ public class FlatAscendingSortIcon @Override protected void paintIcon( Component c, Graphics2D g ) { + boolean chevron = this.chevron; + Color sortIconColor = this.sortIconColor; + + // Because this icons are always shared for all table headers, + // get icon specific style from FlatTableHeaderUI. + JTableHeader tableHeader = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c ); + if( tableHeader != null ) { + TableHeaderUI ui = tableHeader.getUI(); + if( ui instanceof FlatTableHeaderUI ) { + FlatTableHeaderUI fui = (FlatTableHeaderUI) ui; + if( fui.arrowType != null ) + chevron = FlatUIUtils.isChevron( fui.arrowType ); + if( fui.sortIconColor != null ) + sortIconColor = fui.sortIconColor; + } + } + g.setColor( sortIconColor ); + paintArrow( c, g, chevron ); + } + + protected void paintArrow( Component c, Graphics2D g, boolean chevron ) { if( chevron ) { // chevron arrow Path2D path = FlatUIUtils.createPath( false, 1,4, 5,0, 9,4 ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatDescendingSortIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatDescendingSortIcon.java index c43f751d..0ae9ac4c 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatDescendingSortIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatDescendingSortIcon.java @@ -17,11 +17,9 @@ package com.formdev.flatlaf.icons; import java.awt.BasicStroke; -import java.awt.Color; import java.awt.Component; import java.awt.Graphics2D; import java.awt.geom.Path2D; -import javax.swing.UIManager; import com.formdev.flatlaf.ui.FlatUIUtils; /** @@ -33,18 +31,14 @@ import com.formdev.flatlaf.ui.FlatUIUtils; * @author Karl Tauber */ public class FlatDescendingSortIcon - extends FlatAbstractIcon + extends FlatAscendingSortIcon { - protected final boolean chevron = FlatUIUtils.isChevron( UIManager.getString( "Component.arrowType" ) ); - protected final Color sortIconColor = UIManager.getColor( "Table.sortIconColor" ); - public FlatDescendingSortIcon() { - super( 10, 5, null ); + super(); } @Override - protected void paintIcon( Component c, Graphics2D g ) { - g.setColor( sortIconColor ); + protected void paintArrow( Component c, Graphics2D g, boolean chevron ) { if( chevron ) { // chevron arrow Path2D path = FlatUIUtils.createPath( false, 1,0, 5,4, 9,0 ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderBorder.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderBorder.java index d8e6e87c..2237d6fb 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderBorder.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderBorder.java @@ -21,6 +21,7 @@ import java.awt.Component; import java.awt.Container; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Insets; import java.awt.geom.Rectangle2D; import javax.swing.JScrollBar; import javax.swing.JScrollPane; @@ -49,12 +50,30 @@ public class FlatTableHeaderBorder super( UIManager.getInsets( "TableHeader.cellMargins" ) ); } + @Override + public Insets getBorderInsets( Component c, Insets insets ) { + JTableHeader header = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c ); + if( header != null ) { + if( header.getUI() instanceof FlatTableHeaderUI ) { + FlatTableHeaderUI ui = (FlatTableHeaderUI) header.getUI(); + if( ui.cellMargins != null ) { + Insets m = ui.cellMargins; + return scaleInsets( c, insets, m.top, m.left, m.bottom, m.right ); + } + } + } + + return super.getBorderInsets( c, insets ); + } + @Override public void paintBorder( Component c, Graphics g, int x, int y, int width, int height ) { JTableHeader header = (JTableHeader) SwingUtilities.getAncestorOfClass( JTableHeader.class, c ); boolean leftToRight = (header != null ? header : c).getComponentOrientation().isLeftToRight(); boolean paintLeft = !leftToRight; boolean paintRight = leftToRight; + Color separatorColor = this.separatorColor; + Color bottomSeparatorColor = this.bottomSeparatorColor; if( header != null ) { int hx = SwingUtilities.convertPoint( c, x, y, header ).x; @@ -66,6 +85,16 @@ public class FlatTableHeaderBorder if( hx + width >= header.getWidth() && leftToRight && hideTrailingVerticalLine( header ) ) paintRight = false; } + + // Because this border is always shared for all table headers, + // get border specific style from FlatTableHeaderUI. + if( header.getUI() instanceof FlatTableHeaderUI ) { + FlatTableHeaderUI ui = (FlatTableHeaderUI) header.getUI(); + if( ui.separatorColor != null ) + separatorColor = ui.separatorColor; + if( ui.bottomSeparatorColor != null ) + bottomSeparatorColor = ui.bottomSeparatorColor; + } } float lineWidth = UIScale.scale( 1f ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderUI.java index f19b5202..0d5f45ea 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableHeaderUI.java @@ -23,7 +23,8 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.geom.Rectangle2D; -import java.util.Objects; +import java.beans.PropertyChangeListener; +import java.util.Map; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JLabel; @@ -36,6 +37,8 @@ import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicTableHeaderUI; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumnModel; +import com.formdev.flatlaf.FlatClientProperties; +import com.formdev.flatlaf.ui.FlatStyleSupport.Styleable; import com.formdev.flatlaf.util.UIScale; /** @@ -59,32 +62,50 @@ import com.formdev.flatlaf.util.UIScale; * @uiDefault TableHeader.separatorColor Color * @uiDefault TableHeader.bottomSeparatorColor Color * + * + * + * @uiDefault Component.arrowType String chevron (default) or triangle + * @uiDefault Table.sortIconColor Color + * * @author Karl Tauber */ public class FlatTableHeaderUI extends BasicTableHeaderUI { - protected Color bottomSeparatorColor; - protected int height; - protected int sortIconPosition; + @Styleable protected Color bottomSeparatorColor; + @Styleable protected int height; + @Styleable protected int sortIconPosition; + + // for FlatTableHeaderBorder + @Styleable protected Insets cellMargins; + @Styleable protected Color separatorColor; + + // for FlatAscendingSortIcon and FlatDescendingSortIcon + // (needs to be public because icon classes are in another package) + @Styleable public String arrowType; + @Styleable public Color sortIconColor; + + private PropertyChangeListener propertyChangeListener; + private Map oldStyleValues; public static ComponentUI createUI( JComponent c ) { return new FlatTableHeaderUI(); } + @Override + public void installUI( JComponent c ) { + super.installUI( c ); + + applyStyle( FlatStyleSupport.getStyle( c ) ); + } + @Override protected void installDefaults() { super.installDefaults(); bottomSeparatorColor = UIManager.getColor( "TableHeader.bottomSeparatorColor" ); height = UIManager.getInt( "TableHeader.height" ); - switch( Objects.toString( UIManager.getString( "TableHeader.sortIconPosition" ), "right" ) ) { - default: - case "right": sortIconPosition = SwingConstants.RIGHT; break; - case "left": sortIconPosition = SwingConstants.LEFT; break; - case "top": sortIconPosition = SwingConstants.TOP; break; - case "bottom": sortIconPosition = SwingConstants.BOTTOM; break; - } + sortIconPosition = parseSortIconPosition( UIManager.getString( "TableHeader.sortIconPosition" ) ); } @Override @@ -92,6 +113,54 @@ public class FlatTableHeaderUI super.uninstallDefaults(); bottomSeparatorColor = null; + + oldStyleValues = null; + } + + @Override + protected void installListeners() { + super.installListeners(); + + propertyChangeListener = FlatStyleSupport.createPropertyChangeListener( header, this::applyStyle, null ); + header.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + } + + @Override + protected void uninstallListeners() { + super.uninstallListeners(); + + header.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener ); + propertyChangeListener = null; + } + + /** + * @since TODO + */ + protected void applyStyle( Object style ) { + oldStyleValues = FlatStyleSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty ); + } + + /** + * @since TODO + */ + protected Object applyStyleProperty( String key, Object value ) { + if( key.equals( "sortIconPosition" ) && value instanceof String ) + value = parseSortIconPosition( (String) value ); + + return FlatStyleSupport.applyToAnnotatedObject( this, key, value ); + } + + private static int parseSortIconPosition( String str ) { + if( str == null ) + str = ""; + + switch( str ) { + default: + case "right": return SwingConstants.RIGHT; + case "left": return SwingConstants.LEFT; + case "top": return SwingConstants.TOP; + case "bottom": return SwingConstants.BOTTOM; + } } @Override diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/FlatStylingTests.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/FlatStylingTests.java index 1cd771c6..92f219e0 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/FlatStylingTests.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/FlatStylingTests.java @@ -500,6 +500,23 @@ public class FlatStylingTests ui.applyStyle( "showCellFocusIndicator: true" ); } + @Test + void tableHeader() { + FlatTableHeaderUI ui = new FlatTableHeaderUI(); + + ui.applyStyle( "bottomSeparatorColor: #fff" ); + ui.applyStyle( "height: 20" ); + ui.applyStyle( "sortIconPosition: top" ); + + // FlatTableHeaderBorder + ui.applyStyle( "cellMargins: 1,2,3,4" ); + ui.applyStyle( "separatorColor: #fff" ); + + // FlatAscendingSortIcon and FlatDescendingSortIcon + ui.applyStyle( "arrowType: chevron" ); + ui.applyStyle( "sortIconColor: #fff" ); + } + @Test void textArea() { FlatTextAreaUI ui = new FlatTextAreaUI();