From 1f5e08fdc6f7cc853af97f7436af569d64847fa7 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Thu, 15 Oct 2020 13:16:21 +0200 Subject: [PATCH] TabbedPane: fixed clipping title if "more tabs" button is used (issue #40) --- .../formdev/flatlaf/ui/FlatTabbedPaneUI.java | 15 ++++++++ .../flatlaf/util/JavaCompatibility.java | 38 ++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java index f8df3d51..8b376ce3 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTabbedPaneUI.java @@ -71,6 +71,7 @@ import javax.swing.text.View; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.util.Animator; import com.formdev.flatlaf.util.CubicBezierEasing; +import com.formdev.flatlaf.util.JavaCompatibility; import com.formdev.flatlaf.util.UIScale; /** @@ -497,6 +498,20 @@ public class FlatTabbedPaneUI return; } + // clip title if "more tabs" button is used + // (normally this is done by invoker, but fails in this case) + if( hiddenTabsNavigation == MORE_TABS_BUTTON && + tabViewport != null && + (tabPlacement == TOP || tabPlacement == BOTTOM) ) + { + Rectangle viewRect = tabViewport.getViewRect(); + viewRect.width -= 4; // subtract width of cropped edge + if( !viewRect.contains( textRect ) ) { + Rectangle r = viewRect.intersection( textRect ); + title = JavaCompatibility.getClippedString( null, metrics, title, r.width ); + } + } + // plain text Color color; if( tabPane.isEnabled() && tabPane.isEnabledAt( tabIndex ) ) { diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/JavaCompatibility.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/JavaCompatibility.java index dc696af6..f4e740fc 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/JavaCompatibility.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/JavaCompatibility.java @@ -16,6 +16,7 @@ package com.formdev.flatlaf.util; +import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.lang.reflect.InvocationTargetException; @@ -27,7 +28,7 @@ import com.formdev.flatlaf.FlatLaf; /** * Provides Java version compatibility methods. - * + *

* WARNING: This is private API and may change. * * @author Karl Tauber @@ -35,10 +36,12 @@ import com.formdev.flatlaf.FlatLaf; public class JavaCompatibility { private static Method drawStringUnderlineCharAtMethod; + private static Method getClippedStringMethod; /** * Java 8: sun.swing.SwingUtilities2.drawStringUnderlineCharAt( JComponent c, * Graphics g, String text, int underlinedIndex, int x, int y ) + *
* Java 9: javax.swing.plaf.basic.BasicGraphicsUtils.drawStringUnderlineCharAt( JComponent c, * Graphics2D g, String string, int underlinedIndex, float x, float y ) */ @@ -71,4 +74,37 @@ public class JavaCompatibility throw new RuntimeException( ex ); } } + + /** + * Java 8: sun.swing.SwingUtilities2.clipStringIfNecessary( JComponent c, + * FontMetrics fm, String string, int availTextWidth ) + *
+ * Java 9: javax.swing.plaf.basic.BasicGraphicsUtils.getClippedString( JComponent c, + * FontMetrics fm, String string, int availTextWidth ) + */ + public static String getClippedString( JComponent c, FontMetrics fm, String string, int availTextWidth ) { + synchronized( JavaCompatibility.class ) { + if( getClippedStringMethod == null ) { + try { + Class cls = Class.forName( SystemInfo.isJava_9_orLater + ? "javax.swing.plaf.basic.BasicGraphicsUtils" + : "sun.swing.SwingUtilities2" ); + getClippedStringMethod = cls.getMethod( SystemInfo.isJava_9_orLater + ? "getClippedString" + : "clipStringIfNecessary", + new Class[] { JComponent.class, FontMetrics.class, String.class, int.class } ); + } catch( Exception ex ) { + Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, null, ex ); + throw new RuntimeException( ex ); + } + } + } + + try { + return (String) getClippedStringMethod.invoke( null, c, fm, string, availTextWidth ); + } catch( IllegalAccessException | IllegalArgumentException | InvocationTargetException ex ) { + Logger.getLogger( FlatLaf.class.getName() ).log( Level.SEVERE, null, ex ); + throw new RuntimeException( ex ); + } + } }