diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java index 1ce48b33..6a3a2c6f 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -280,6 +280,15 @@ public interface FlatClientProperties */ String TABBED_PANE_TAB_CLOSABLE = "JTabbedPane.tabClosable"; + /** + * Specifies the tooltip text used for tab close buttons. + *

+ * Component {@link javax.swing.JTabbedPane} + * or tab content components (see {@link javax.swing.JTabbedPane#setComponentAt(int, java.awt.Component)})
+ * Value type {@link java.lang.String} + */ + String TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT = "JTabbedPane.tabCloseToolTipText"; + /** * Specifies the callback that is invoked when a tab close button is clicked. * The callback is responsible for closing the tab. 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 e2d79a14..cb61394b 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 @@ -1533,6 +1533,8 @@ public class FlatTabbedPaneUI private final PropertyChangeListener contentListener = this::contentPropertyChange; private int pressedTabIndex = -1; + private int lastTipTabIndex = -1; + private String lastTip; void installListeners() { tabPane.addMouseMotionListener( this ); @@ -1565,7 +1567,7 @@ public class FlatTabbedPaneUI @Override public void mousePressed( MouseEvent e ) { - updateRollover( e, true ); + updateRollover( e ); if( !isPressedTabClose() ) mouseDelegate.mousePressed( e ); @@ -1574,20 +1576,20 @@ public class FlatTabbedPaneUI @Override public void mouseReleased( MouseEvent e ) { if( isPressedTabClose() ) { - updateRollover( e, false ); + updateRollover( e ); if( pressedTabIndex >= 0 && pressedTabIndex == getRolloverTab() ) closeTab( pressedTabIndex ); } else mouseDelegate.mouseReleased( e ); pressedTabIndex = -1; - updateRollover( e, false ); + updateRollover( e ); } @Override public void mouseEntered( MouseEvent e ) { // this is necessary for "more tabs" button - updateRollover( e, false ); + updateRollover( e ); } @Override @@ -1595,22 +1597,22 @@ public class FlatTabbedPaneUI // this event occurs also if mouse is moved to a custom tab component // that handles mouse events (e.g. a close button) // --> make sure that the tab stays highlighted - updateRollover( e, false ); + updateRollover( e ); } //---- interface MouseMotionListener ---- @Override public void mouseDragged( MouseEvent e ) { - updateRollover( e, false ); + updateRollover( e ); } @Override public void mouseMoved( MouseEvent e ) { - updateRollover( e, false ); + updateRollover( e ); } - private void updateRollover( MouseEvent e, boolean pressed ) { + private void updateRollover( MouseEvent e ) { int x = e.getX(); int y = e.getY(); @@ -1622,10 +1624,41 @@ public class FlatTabbedPaneUI boolean hitClose = isTabClosable( tabIndex ) ? getTabCloseHitArea( tabIndex ).contains( x, y ) : false; - if( pressed ) + if( e.getID() == MouseEvent.MOUSE_PRESSED ) pressedTabIndex = hitClose ? tabIndex : -1; setRolloverTabClose( hitClose ); setPressedTabClose( hitClose && tabIndex == pressedTabIndex ); + + // update tooltip + if( tabIndex >= 0 && hitClose ) { + Object closeTip = getTabClientProperty( tabIndex, TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT ); + if( closeTip instanceof String ) + setCloseToolTip( tabIndex, (String) closeTip ); + else + restoreTabToolTip(); + } else + restoreTabToolTip(); + } + + private void setCloseToolTip( int tabIndex, String closeTip ) { + if( tabIndex == lastTipTabIndex ) + return; // closeTip already set + + if( tabIndex != lastTipTabIndex ) + restoreTabToolTip(); + + lastTipTabIndex = tabIndex; + lastTip = tabPane.getToolTipTextAt( lastTipTabIndex ); + tabPane.setToolTipTextAt( lastTipTabIndex, closeTip ); + } + + private void restoreTabToolTip() { + if( lastTipTabIndex < 0 ) + return; + + tabPane.setToolTipTextAt( lastTipTabIndex, lastTip ); + lastTip = null; + lastTipTabIndex = -1; } //---- interface PropertyChangeListener ---- diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java index dee6b937..4a295902 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java @@ -54,6 +54,7 @@ public class FlatContainerTest tabsClosableCheckBox.setSelected( true ); tabsClosableChanged(); + putTabbedPanesClientProperty( TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT, "Close" ); tabScrollCheckBox.setSelected( true ); tabScrollChanged(); @@ -129,14 +130,15 @@ public class FlatContainerTest private void addInitialTabs( JTabbedPane... tabbedPanes ) { for( JTabbedPane tabbedPane : tabbedPanes ) { - tabbedPane.addTab( "Tab 1", new Panel1() ); + tabbedPane.addTab( "Tab 1", null, new Panel1(), "First tab." ); JComponent tab2 = new Panel2(); tab2.setBorder( new LineBorder( Color.magenta ) ); - tabbedPane.addTab( "Second Tab", tab2 ); + tabbedPane.addTab( "Second Tab", null, tab2, "This is the second tab." ); addTab( tabbedPane, "Disabled", "tab content 3" ); tabbedPane.setEnabledAt( 2, false ); + tabbedPane.setToolTipTextAt( 2, "Disabled tab." ); tabbedPane.addTab( "Tab 4", new JLabel( "non-opaque content", SwingConstants.CENTER ) ); }