)
supr javax.swing.plaf.basic.BasicLookAndFeel
-hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,globalExtraDefaults,mnemonicHandler,oldPopupFactory,postInitialization,preferredFontFamily,preferredLightFontFamily,preferredMonospacedFontFamily,preferredSemiboldFontFamily,subMenuUsabilityHelperInstalled,systemColorGetter,uiDefaultsGetters,updateUIPending
+hfds DESKTOPFONTHINTS,aquaLoaded,customDefaultsSources,desktopPropertyListener,desktopPropertyName,desktopPropertyName2,extraDefaults,globalExtraDefaults,linuxPopupMenuCanceler,mnemonicHandler,oldPopupFactory,postInitialization,preferredFontFamily,preferredLightFontFamily,preferredMonospacedFontFamily,preferredSemiboldFontFamily,subMenuUsabilityHelperInstalled,systemColorGetter,uiDefaultsGetters,uiKeyPlatformPrefixes,uiKeySpecialPrefixes,updateUIPending
hcls ActiveFont,FlatUIDefaults,ImageIconUIResource
CLSS public abstract interface static com.formdev.flatlaf.FlatLaf$DisabledIconProvider
@@ -318,7 +324,7 @@ meth public static boolean setup(java.io.InputStream)
meth public static com.formdev.flatlaf.FlatLaf createLaf(com.formdev.flatlaf.IntelliJTheme)
meth public static com.formdev.flatlaf.FlatLaf createLaf(java.io.InputStream) throws java.io.IOException
supr java.lang.Object
-hfds checkboxDuplicateColors,checkboxKeyMapping,colors,icons,isMaterialUILite,namedColors,ui,uiKeyCopying,uiKeyDoNotOverride,uiKeyExcludes,uiKeyInverseMapping,uiKeyMapping
+hfds checkboxDuplicateColors,checkboxKeyMapping,jsonColors,jsonIcons,jsonUI,namedColors,uiKeyCopying,uiKeyDoNotOverride,uiKeyExcludes,uiKeyInverseMapping,uiKeyMapping
CLSS public static com.formdev.flatlaf.IntelliJTheme$ThemeLaf
outer com.formdev.flatlaf.IntelliJTheme
@@ -413,6 +419,7 @@ innr public static Fade
innr public static HSLChange
innr public static HSLIncreaseDecrease
innr public static Mix
+innr public static Mix2
meth public !varargs static java.awt.Color applyFunctions(java.awt.Color,com.formdev.flatlaf.util.ColorFunctions$ColorFunction[])
meth public static float clamp(float)
meth public static float luma(java.awt.Color)
@@ -474,6 +481,16 @@ meth public java.lang.String toString()
meth public void apply(float[])
supr java.lang.Object
+CLSS public static com.formdev.flatlaf.util.ColorFunctions$Mix2
+ outer com.formdev.flatlaf.util.ColorFunctions
+cons public init(java.awt.Color,float)
+fld public final float weight
+fld public final java.awt.Color color1
+intf com.formdev.flatlaf.util.ColorFunctions$ColorFunction
+meth public java.lang.String toString()
+meth public void apply(float[])
+supr java.lang.Object
+
CLSS public com.formdev.flatlaf.util.CubicBezierEasing
cons public init(float,float,float,float)
fld public final static com.formdev.flatlaf.util.CubicBezierEasing EASE
@@ -755,6 +772,7 @@ supr java.lang.Object
CLSS public com.formdev.flatlaf.util.SystemInfo
cons public init()
fld public final static boolean isAARCH64
+fld public final static boolean isGNOME
fld public final static boolean isJava_11_orLater
fld public final static boolean isJava_12_orLater
fld public final static boolean isJava_15_orLater
@@ -771,6 +789,7 @@ fld public final static boolean isMacOS_10_11_ElCapitan_orLater
fld public final static boolean isMacOS_10_14_Mojave_orLater
fld public final static boolean isMacOS_10_15_Catalina_orLater
fld public final static boolean isProjector
+fld public final static boolean isUnknownOS
fld public final static boolean isWebswing
fld public final static boolean isWinPE
fld public final static boolean isWindows
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 2625294f..e26b7ec3 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java
@@ -21,6 +21,8 @@ import java.awt.IllegalComponentStateException;
import java.awt.Window;
import java.util.Objects;
import javax.swing.JComponent;
+import javax.swing.JFormattedTextField;
+import javax.swing.JSpinner;
import javax.swing.SwingConstants;
/**
@@ -1209,12 +1211,15 @@ public interface FlatClientProperties
/**
* Specifies whether all text is selected when the text component gains focus.
*
- * Component {@link javax.swing.JTextField} (and subclasses)
+ * Components {@link javax.swing.text.JTextComponent} (and subclasses),
+ * {@link javax.swing.JComboBox} (since 3.6) and {@link javax.swing.JSpinner} (since 3.6)
* Value type {@link java.lang.String}
* Allowed Values
* {@link #SELECT_ALL_ON_FOCUS_POLICY_NEVER},
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ONCE} (default) or
* {@link #SELECT_ALL_ON_FOCUS_POLICY_ALWAYS}
+ *
+ * @see #SELECT_ALL_ON_MOUSE_CLICK
*/
String SELECT_ALL_ON_FOCUS_POLICY = "JTextField.selectAllOnFocusPolicy";
@@ -1229,6 +1234,12 @@ public interface FlatClientProperties
* Select all text when the text component gains focus for the first time
* and selection was not modified (is at end of text).
* This is the default.
+ *
+ * Limitations:
+ * For {@link JFormattedTextField} and {@link JSpinner} this behaves
+ * as {@link #SELECT_ALL_ON_FOCUS_POLICY_ALWAYS}.
+ * This is because of special behavior of {@link JFormattedTextField}
+ * that did not allow implementation of {@code "once"}.
*
* @see #SELECT_ALL_ON_FOCUS_POLICY
*/
@@ -1241,6 +1252,19 @@ public interface FlatClientProperties
*/
String SELECT_ALL_ON_FOCUS_POLICY_ALWAYS = "always";
+ /**
+ * Specifies whether all text is selected when when clicking with the mouse
+ * into the text field (and if "select all on focus" policy is enabled).
+ *
+ * Components {@link javax.swing.text.JTextComponent} (and subclasses),
+ * {@link javax.swing.JComboBox} and {@link javax.swing.JSpinner}
+ * Value type {@link java.lang.Boolean}
+ *
+ * @see #SELECT_ALL_ON_FOCUS_POLICY
+ * @since 3.6
+ */
+ String SELECT_ALL_ON_MOUSE_CLICK = "JTextField.selectAllOnMouseClick";
+
/**
* Placeholder text that is only painted if the text field is empty.
*
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/IntelliJTheme.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/IntelliJTheme.java
index 8992328d..21874425 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/IntelliJTheme.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/IntelliJTheme.java
@@ -413,22 +413,37 @@ public class IntelliJTheme
key.equals( "Tree.rightChildIndent" ) )
return; // ignore
+ // ignore icons
+ if( key.endsWith( "Icon" ) )
+ return; // ignore
+
// map keys
key = uiKeyMapping.getOrDefault( key, key );
if( key.isEmpty() )
return; // ignore key
- // exclude properties
+ // exclude properties (1st level)
int dot = key.indexOf( '.' );
- if( dot > 0 && uiKeyExcludes.contains( key.substring( 0, dot + 1 ) ) )
+ if( dot > 0 && uiKeyExcludesStartsWith.contains( key.substring( 0, dot + 1 ) ) )
return;
+ // exclude properties (2st level)
+ int dot2 = (dot > 0) ? key.indexOf( '.', dot + 1 ) : -1;
+ if( dot2 > 0 && uiKeyExcludesStartsWith.contains( key.substring( 0, dot2 + 1 ) ) )
+ return;
+
+ // exclude properties (contains)
+ for( String s : uiKeyExcludesContains ) {
+ if( key.contains( s ) )
+ return;
+ }
+
if( uiKeyDoNotOverride.contains( key ) && jsonUIKeys.contains( key ) )
return;
jsonUIKeys.add( key );
- String valueStr = value.toString();
+ String valueStr = value.toString().trim();
// map named colors
String uiValue = namedColors.get( valueStr );
@@ -657,7 +672,8 @@ public class IntelliJTheme
}
}
- private static final Set uiKeyExcludes;
+ private static final Set uiKeyExcludesStartsWith;
+ private static final String[] uiKeyExcludesContains;
private static final Set uiKeyDoNotOverride;
/** Rename UI default keys (key --> value). */
private static final Map uiKeyMapping = new HashMap<>();
@@ -669,7 +685,7 @@ public class IntelliJTheme
static {
// IntelliJ UI properties that are not used in FlatLaf
- uiKeyExcludes = new HashSet<>( Arrays.asList(
+ uiKeyExcludesStartsWith = new HashSet<>( Arrays.asList(
"ActionButton.", "ActionToolbar.", "ActionsList.", "AppInspector.", "AssignedMnemonic.", "Autocomplete.",
"AvailableMnemonic.",
"Badge.", "Banner.", "BigSpinner.", "Bookmark.", "BookmarkIcon.", "BookmarkMnemonicAssigned.", "BookmarkMnemonicAvailable.",
@@ -703,14 +719,24 @@ public class IntelliJTheme
// possible typos in .theme.json files
"Checkbox.", "Toolbar.", "Tooltip.", "UiDesigner.", "link."
) );
+ uiKeyExcludesContains = new String[] {
+ ".darcula."
+ };
uiKeyDoNotOverride = new HashSet<>( Arrays.asList(
"TabbedPane.selectedForeground"
) );
+ // "*."
+ uiKeyMapping.put( "*.fontFace", "" ); // ignore (used in OnePauintxi themes)
+ uiKeyMapping.put( "*.fontSize", "" ); // ignore (used in OnePauintxi themes)
+
// Button
uiKeyMapping.put( "Button.minimumSize", "" ); // ignore (used in Material Theme UI Lite)
+ // CheckBox.iconSize
+ uiKeyMapping.put( "CheckBox.iconSize", "" ); // ignore (used in Rider themes)
+
// ComboBox
uiKeyMapping.put( "ComboBox.background", "" ); // ignore
uiKeyMapping.put( "ComboBox.buttonBackground", "" ); // ignore
@@ -751,6 +777,9 @@ public class IntelliJTheme
uiKeyMapping.put( "ProgressBar.trackColor", "ProgressBar.background" );
uiKeyMapping.put( "ProgressBar.progressColor", "ProgressBar.foreground" );
+ // RadioButton
+ uiKeyMapping.put( "RadioButton.iconSize", "" ); // ignore (used in Rider themes)
+
// ScrollBar
uiKeyMapping.put( "ScrollBar.trackColor", "ScrollBar.track" );
uiKeyMapping.put( "ScrollBar.thumbColor", "ScrollBar.thumb" );
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java
index 81a58196..a2e614ec 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java
@@ -649,22 +649,26 @@ class UIDefaultsLoader
if( value.indexOf( ',' ) >= 0 ) {
// Syntax: top,left,bottom,right[,lineColor[,lineThickness[,arc]]]
List parts = splitFunctionParams( value, ',' );
- Insets insets = parseInsets( value );
- ColorUIResource lineColor = (parts.size() >= 5 && !parts.get( 4 ).isEmpty())
- ? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver )
- : null;
- float lineThickness = (parts.size() >= 6 && !parts.get( 5 ).isEmpty())
- ? parseFloat( parts.get( 5 ) )
- : 1f;
- int arc = (parts.size() >= 7) && !parts.get( 6 ).isEmpty()
- ? parseInteger( parts.get( 6 ) )
- : -1;
+ try {
+ Insets insets = parseInsets( value );
+ ColorUIResource lineColor = (parts.size() >= 5 && !parts.get( 4 ).isEmpty())
+ ? (ColorUIResource) parseColorOrFunction( resolver.apply( parts.get( 4 ) ), resolver )
+ : null;
+ float lineThickness = (parts.size() >= 6 && !parts.get( 5 ).isEmpty())
+ ? parseFloat( parts.get( 5 ) )
+ : 1f;
+ int arc = (parts.size() >= 7) && !parts.get( 6 ).isEmpty()
+ ? parseInteger( parts.get( 6 ) )
+ : -1;
- return (LazyValue) t -> {
- return (lineColor != null || arc > 0)
- ? new FlatLineBorder( insets, lineColor, lineThickness, arc )
- : new FlatEmptyBorder( insets );
- };
+ return (LazyValue) t -> {
+ return (lineColor != null || arc > 0)
+ ? new FlatLineBorder( insets, lineColor, lineThickness, arc )
+ : new FlatEmptyBorder( insets );
+ };
+ } catch( RuntimeException ex ) {
+ throw new IllegalArgumentException( "invalid border '" + value + "' (" + ex.getMessage() + ")" );
+ }
} else
return parseInstance( value, resolver, addonClassLoaders );
}
@@ -735,7 +739,7 @@ class UIDefaultsLoader
Integer.parseInt( numbers.get( 1 ) ),
Integer.parseInt( numbers.get( 2 ) ),
Integer.parseInt( numbers.get( 3 ) ) );
- } catch( NumberFormatException ex ) {
+ } catch( NumberFormatException | IndexOutOfBoundsException ex ) {
throw new IllegalArgumentException( "invalid insets '" + value + "'" );
}
}
@@ -748,7 +752,7 @@ class UIDefaultsLoader
return new DimensionUIResource(
Integer.parseInt( numbers.get( 0 ) ),
Integer.parseInt( numbers.get( 1 ) ) );
- } catch( NumberFormatException ex ) {
+ } catch( NumberFormatException | IndexOutOfBoundsException ex ) {
throw new IllegalArgumentException( "invalid size '" + value + "'" );
}
}
@@ -1379,17 +1383,17 @@ class UIDefaultsLoader
break;
}
}
- } catch( IOException ex ) {
- throw new IllegalArgumentException( ex );
+ } catch( RuntimeException | IOException ex ) {
+ throw new IllegalArgumentException( "invalid font '" + value + "' (" + ex.getMessage() + ")" );
}
if( style != -1 && styleChange != 0 )
- throw new IllegalArgumentException( "can not mix absolute style (e.g. 'bold') with derived style (e.g. '+italic') in '" + value + "'" );
+ throw new IllegalArgumentException( "invalid font '" + value + "': can not mix absolute style (e.g. 'bold') with derived style (e.g. '+italic')" );
if( styleChange != 0 ) {
if( (styleChange & Font.BOLD) != 0 && (styleChange & (Font.BOLD << 16)) != 0 )
- throw new IllegalArgumentException( "can not use '+bold' and '-bold' in '" + value + "'" );
+ throw new IllegalArgumentException( "invalid font '" + value + "': can not use '+bold' and '-bold'" );
if( (styleChange & Font.ITALIC) != 0 && (styleChange & (Font.ITALIC << 16)) != 0 )
- throw new IllegalArgumentException( "can not use '+italic' and '-italic' in '" + value + "'" );
+ throw new IllegalArgumentException( "invalid font '" + value + "': can not use '+italic' and '-italic'" );
}
font = new FlatLaf.ActiveFont( baseFontKey, families, style, styleChange, absoluteSize, relativeSize, scaleSize );
@@ -1529,7 +1533,7 @@ class UIDefaultsLoader
return (LazyValue) t -> {
return new GrayFilter( brightness, contrast, alpha );
};
- } catch( NumberFormatException ex ) {
+ } catch( NumberFormatException | IndexOutOfBoundsException ex ) {
throw new IllegalArgumentException( "invalid gray filter '" + value + "'" );
}
}
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java
index e301961e..0edf010b 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatCaret.java
@@ -17,6 +17,7 @@
package com.formdev.flatlaf.ui;
import static com.formdev.flatlaf.FlatClientProperties.*;
+import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
@@ -24,7 +25,9 @@ import java.awt.event.FocusEvent;
import java.awt.event.MouseEvent;
import javax.swing.Action;
import javax.swing.ActionMap;
+import javax.swing.JComboBox;
import javax.swing.JFormattedTextField;
+import javax.swing.JSpinner;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.UIResource;
@@ -33,6 +36,7 @@ import javax.swing.text.DefaultCaret;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
+import javax.swing.text.Position;
import javax.swing.text.Utilities;
/**
@@ -48,12 +52,15 @@ public class FlatCaret
{
private static final String KEY_CARET_INFO = "FlatLaf.internal.caretInfo";
+ // selectAllOnFocusPolicy
+ private static final int NEVER = 0, ONCE = 1, ALWAYS = 2;
+
private final String selectAllOnFocusPolicy;
private final boolean selectAllOnMouseClick;
private boolean inInstall;
private boolean wasFocused;
- private boolean wasTemporaryLost;
+ private boolean wasFocusTemporaryLost;
private boolean isMousePressed;
private boolean isWordSelection;
private boolean isLineSelection;
@@ -94,6 +101,9 @@ public class FlatCaret
// restore selection
select( (int) ci[1], (int) ci[0] );
+ if( ci[4] != 0 )
+ wasFocused = true;
+
// if text component is focused, then caret and selection are visible,
// but when switching theme, the component does not yet have
// a highlighter and the selection is not painted
@@ -121,6 +131,7 @@ public class FlatCaret
getMark(),
getBlinkRate(),
System.currentTimeMillis(),
+ wasFocused ? 1 : 0,
} );
super.deinstall( c );
@@ -140,11 +151,36 @@ public class FlatCaret
super.adjustVisibility( nloc );
}
+ @Override
+ public void setDot( int dot ) {
+ super.setDot( dot );
+
+ // mark as focused if invoked from JTextComponent.setCaretPosition()
+ // to disable SELECT_ALL_ON_FOCUS_POLICY_ONCE if application explicitly changes selection
+ if( !wasFocused &&
+ getSelectAllOnFocusPolicy() == ONCE &&
+ StackUtils.wasInvokedFrom( JTextComponent.class.getName(), "setCaretPosition", 6 ) )
+ wasFocused = true;
+ }
+
+ @Override
+ public void moveDot( int dot ) {
+ super.moveDot( dot );
+
+ // mark as focused if invoked from JTextComponent.moveCaretPosition()
+ // to disable SELECT_ALL_ON_FOCUS_POLICY_ONCE if application explicitly changes selection
+ if( !wasFocused &&
+ getSelectAllOnFocusPolicy() == ONCE &&
+ StackUtils.wasInvokedFrom( JTextComponent.class.getName(), "moveCaretPosition", 6 ) )
+ wasFocused = true;
+ }
+
@Override
public void focusGained( FocusEvent e ) {
- if( !inInstall && !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
+ if( !inInstall && !wasFocusTemporaryLost && (!isMousePressed || isSelectAllOnMouseClick()) )
selectAllOnFocusGained();
- wasTemporaryLost = false;
+
+ wasFocusTemporaryLost = false;
wasFocused = true;
super.focusGained( e );
@@ -152,7 +188,7 @@ public class FlatCaret
@Override
public void focusLost( FocusEvent e ) {
- wasTemporaryLost = e.isTemporary();
+ wasFocusTemporaryLost = e.isTemporary();
super.focusLost( e );
}
@@ -232,24 +268,13 @@ public class FlatCaret
if( doc == null || !c.isEnabled() || !c.isEditable() || FlatUIUtils.isCellEditor( c ) )
return;
- Object selectAllOnFocusPolicy = c.getClientProperty( SELECT_ALL_ON_FOCUS_POLICY );
- if( selectAllOnFocusPolicy == null )
- selectAllOnFocusPolicy = this.selectAllOnFocusPolicy;
-
- if( selectAllOnFocusPolicy == null || SELECT_ALL_ON_FOCUS_POLICY_NEVER.equals( selectAllOnFocusPolicy ) )
+ int selectAllOnFocusPolicy = getSelectAllOnFocusPolicy();
+ if( selectAllOnFocusPolicy == NEVER )
return;
- if( !SELECT_ALL_ON_FOCUS_POLICY_ALWAYS.equals( selectAllOnFocusPolicy ) ) {
- // policy is "once" (or null or unknown)
-
+ if( selectAllOnFocusPolicy == ONCE && !isMousePressed ) {
// was already focused?
- if( wasFocused )
- return;
-
- // check whether selection was modified before gaining focus
- int dot = getDot();
- int mark = getMark();
- if( dot != mark || dot != doc.getLength() )
+ if( wasFocused && !(c instanceof JFormattedTextField) )
return;
}
@@ -265,16 +290,51 @@ public class FlatCaret
select( 0, c2.getDocument().getLength() );
} );
- } else {
+ } else
select( 0, doc.getLength() );
- }
}
private void select( int mark, int dot ) {
if( mark != getMark() )
- setDot( mark );
+ setDot( mark, Position.Bias.Forward );
if( dot != getDot() )
- moveDot( dot );
+ moveDot( dot, Position.Bias.Forward );
+ }
+
+ private int getSelectAllOnFocusPolicy() {
+ Object value = getClientProperty( SELECT_ALL_ON_FOCUS_POLICY );
+ // Note: using String.valueOf() because selectAllOnFocusPolicy may be null
+ switch( String.valueOf( value instanceof String ? value : selectAllOnFocusPolicy ) ) {
+ default:
+ case SELECT_ALL_ON_FOCUS_POLICY_NEVER: return NEVER;
+ case SELECT_ALL_ON_FOCUS_POLICY_ONCE: return ONCE;
+ case SELECT_ALL_ON_FOCUS_POLICY_ALWAYS: return ALWAYS;
+ }
+ }
+
+ private boolean isSelectAllOnMouseClick() {
+ Object value = getClientProperty( SELECT_ALL_ON_MOUSE_CLICK );
+ return (value instanceof Boolean) ? (boolean) value : selectAllOnMouseClick;
+ }
+
+ private Object getClientProperty( String key ) {
+ JTextComponent c = getComponent();
+ if( c == null )
+ return null;
+
+ Object value = c.getClientProperty( key );
+ if( value != null )
+ return value;
+
+ Container parent = c.getParent();
+ if( parent instanceof JComboBox )
+ return ((JComboBox>)parent).getClientProperty( key );
+ if( parent instanceof JSpinner.DefaultEditor ) {
+ parent = parent.getParent();
+ if( parent instanceof JSpinner )
+ return ((JSpinner)parent).getClientProperty( key );
+ }
+ return null;
}
/** @since 1.4 */
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java
index 05a4973a..2f135bca 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatComboBoxUI.java
@@ -882,7 +882,7 @@ public class FlatComboBoxUI
GraphicsConfiguration gc = comboBox.getGraphicsConfiguration();
if( gc != null ) {
Rectangle screenBounds = gc.getBounds();
- Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
+ Insets screenInsets = FlatUIUtils.getScreenInsets( gc );
displayWidth = Math.min( displayWidth, screenBounds.width - screenInsets.left - screenInsets.right );
} else {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java
index 553695d8..a1fdaa6f 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java
@@ -32,7 +32,6 @@ import java.awt.Panel;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Rectangle;
-import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
@@ -312,7 +311,7 @@ public class FlatPopupFactory
return null;
Rectangle screenBounds = gc.getBounds();
- Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
+ Insets screenInsets = FlatUIUtils.getScreenInsets( gc );
int screenTop = screenBounds.y + screenInsets.top;
// place tooltip above mouse location if there is enough space
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupMenuUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupMenuUI.java
index 69fc6ec4..42e0670a 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupMenuUI.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupMenuUI.java
@@ -246,7 +246,7 @@ public class FlatPopupMenuUI
// (always subtract screen insets because there is no API to detect whether
// the popup can overlap the taskbar; see JPopupMenu.canPopupOverlapTaskBar())
Rectangle screenBounds = gc.getBounds();
- Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
+ Insets screenInsets = FlatUIUtils.getScreenInsets( gc );
return FlatUIUtils.subtractInsets( screenBounds, screenInsets );
}
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java
index 369332e7..9d689991 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java
@@ -914,7 +914,7 @@ public class FlatTitlePane
// screen insets are in physical size, except for Java 15+
// (see https://bugs.openjdk.java.net/browse/JDK-8243925)
// and except for Java 8 on secondary screens where primary screen is scaled
- Insets screenInsets = window.getToolkit().getScreenInsets( gc );
+ Insets screenInsets = FlatUIUtils.getScreenInsets( gc );
// maximized bounds are required in physical size, except for Java 15+
// (see https://bugs.openjdk.java.net/browse/JDK-8231564 and
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java
index 706e4546..08c74d19 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java
@@ -26,6 +26,7 @@ import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.Paint;
@@ -34,6 +35,7 @@ import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.SystemColor;
+import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
@@ -414,6 +416,17 @@ public class FlatUIUtils
return (fullScreenWindow != null && fullScreenWindow == SwingUtilities.windowForComponent( c ));
}
+ /** @since 3.7 */
+ public static Insets getScreenInsets( GraphicsConfiguration gc ) {
+ // on Linux, getScreenInsets() may report wrong values in multi-screen setups
+ // see https://github.com/apache/netbeans/issues/8532#issuecomment-2909687016
+ if( SystemInfo.isLinux &&
+ GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices().length > 1 )
+ return new Insets( 0, 0, 0, 0 );
+
+ return Toolkit.getDefaultToolkit().getScreenInsets( gc );
+ }
+
public static Boolean isRoundRect( Component c ) {
return (c instanceof JComponent)
? FlatClientProperties.clientPropertyBooleanStrict(
diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowResizer.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowResizer.java
index c63ac409..42e9d96e 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowResizer.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatWindowResizer.java
@@ -331,7 +331,7 @@ public abstract class FlatWindowResizer
protected Rectangle getParentBounds() {
GraphicsConfiguration gc = window.getGraphicsConfiguration();
Rectangle bounds = gc.getBounds();
- Insets insets = window.getToolkit().getScreenInsets( gc );
+ Insets insets = FlatUIUtils.getScreenInsets( gc );
return new Rectangle( bounds.x + insets.left, bounds.y + insets.top,
bounds.width - insets.left - insets.right,
bounds.height - insets.top - insets.bottom );
diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties
index 1eda0de3..04f5db56 100644
--- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties
+++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties
@@ -276,7 +276,7 @@ RootPane.inactiveBorderColor = lighten(@background,5%,derived)
#---- ScrollBar ----
ScrollBar.track = lighten(@background,1%,derived noAutoInverse)
-ScrollBar.thumb = lighten($ScrollBar.track,10%,derived noAutoInverse)
+ScrollBar.thumb = lighten($ScrollBar.track,15%,derived noAutoInverse)
ScrollBar.hoverTrackColor = lighten($ScrollBar.track,4%,derived noAutoInverse)
ScrollBar.hoverThumbColor = lighten($ScrollBar.thumb,10%,derived noAutoInverse)
ScrollBar.pressedThumbColor = lighten($ScrollBar.thumb,15%,derived noAutoInverse)
diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties
index ec2dbdaa..368562b1 100644
--- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties
+++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties
@@ -574,12 +574,12 @@ RootPane.honorDialogMinimumSizeOnResize = true
ScrollBar.width = 10
ScrollBar.minimumButtonSize = 12,12
-ScrollBar.minimumThumbSize = 10,10
+ScrollBar.minimumThumbSize = 18,18
ScrollBar.maximumThumbSize = 100000,100000
ScrollBar.trackInsets = 0,0,0,0
-ScrollBar.thumbInsets = 0,0,0,0
+ScrollBar.thumbInsets = 2,2,2,2
ScrollBar.trackArc = 0
-ScrollBar.thumbArc = 0
+ScrollBar.thumbArc = 999
ScrollBar.hoverThumbWithTrack = false
ScrollBar.pressedThumbWithTrack = false
ScrollBar.showButtons = false
@@ -588,15 +588,8 @@ ScrollBar.buttonArrowColor = @buttonArrowColor
ScrollBar.buttonDisabledArrowColor = @buttonDisabledArrowColor
ScrollBar.allowsAbsolutePositioning = true
-[mac]ScrollBar.minimumThumbSize = 18,18
-[mac]ScrollBar.thumbInsets = 2,2,2,2
-[mac]ScrollBar.thumbArc = 999
[mac]ScrollBar.hoverThumbWithTrack = true
-[linux]ScrollBar.minimumThumbSize = 18,18
-[linux]ScrollBar.thumbInsets = 2,2,2,2
-[linux]ScrollBar.thumbArc = 999
-
#---- ScrollPane ----
diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties
index a9165856..f6223208 100644
--- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties
+++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties
@@ -282,7 +282,7 @@ RootPane.inactiveBorderColor = darken(@background,30%,derived)
#---- ScrollBar ----
ScrollBar.track = lighten(@background,1%,derived noAutoInverse)
-ScrollBar.thumb = darken($ScrollBar.track,10%,derived noAutoInverse)
+ScrollBar.thumb = darken($ScrollBar.track,15%,derived noAutoInverse)
ScrollBar.hoverTrackColor = darken($ScrollBar.track,3%,derived noAutoInverse)
ScrollBar.hoverThumbColor = darken($ScrollBar.thumb,10%,derived noAutoInverse)
ScrollBar.pressedThumbColor = darken($ScrollBar.thumb,20%,derived noAutoInverse)
diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/themes/FlatMacDarkLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/themes/FlatMacDarkLaf.properties
index 02ed6b34..226fecd1 100644
--- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/themes/FlatMacDarkLaf.properties
+++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/themes/FlatMacDarkLaf.properties
@@ -184,6 +184,7 @@ MenuBar.selectionEmbeddedInsets = 3,0,3,0
MenuBar.selectionArc = 8
MenuBar.selectionBackground = lighten(@menuBackground,15%,derived)
MenuBar.selectionForeground = @foreground
+MenuBar.borderColor = over($Separator.foreground,$MenuBar.background)
#---- MenuItem ----
diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/themes/FlatMacLightLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/themes/FlatMacLightLaf.properties
index d18eb106..b37d2131 100644
--- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/themes/FlatMacLightLaf.properties
+++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/themes/FlatMacLightLaf.properties
@@ -184,6 +184,7 @@ MenuBar.selectionEmbeddedInsets = 3,0,3,0
MenuBar.selectionArc = 8
MenuBar.selectionBackground = darken(@menuBackground,15%,derived)
MenuBar.selectionForeground = @foreground
+MenuBar.borderColor = over($Separator.foreground,$MenuBar.background)
#---- MenuItem ----
diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java
index 28c36c89..da9f52e9 100644
--- a/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java
+++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java
@@ -18,6 +18,7 @@ package com.formdev.flatlaf;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.awt.Color;
import java.awt.Dimension;
@@ -29,6 +30,7 @@ import javax.swing.border.Border;
import javax.swing.UIDefaults.ActiveValue;
import javax.swing.UIDefaults.LazyValue;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.function.Executable;
import com.formdev.flatlaf.ui.FlatEmptyBorder;
import com.formdev.flatlaf.ui.FlatLineBorder;
import com.formdev.flatlaf.util.DerivedColor;
@@ -452,6 +454,73 @@ public class TestUIDefaultsLoader
return ((LazyValue)v).createValue( null );
}
+ //---- invalid values -----------------------------------------------------
+
+ @Test
+ void parseInvalidValue() {
+ assertThrows( new IllegalArgumentException( "invalid character 'abc'" ), () -> UIDefaultsLoader.parseValue( "dummyChar", "abc", null ) );
+ assertThrows( new NumberFormatException( "invalid integer or float '123abc'" ), () -> UIDefaultsLoader.parseValue( "dummyWidth", "123abc", null ) );
+ assertThrows( new NumberFormatException( "invalid integer or float '1.23abc'" ), () -> UIDefaultsLoader.parseValue( "dummyWidth", "1.23abc", null ) );
+
+ assertThrows( new IllegalArgumentException( "invalid insets '1,abc,3,4'" ), () -> UIDefaultsLoader.parseValue( "dummyInsets", "1,abc,3,4", null ) );
+ assertThrows( new IllegalArgumentException( "invalid insets '1,2,3'" ), () -> UIDefaultsLoader.parseValue( "dummyInsets", "1,2,3", null ) );
+ assertThrows( new IllegalArgumentException( "invalid size '1abc'" ), () -> UIDefaultsLoader.parseValue( "dummySize", "1abc", null ) );
+ assertThrows( new IllegalArgumentException( "invalid size '1'" ), () -> UIDefaultsLoader.parseValue( "dummySize", "1", null ) );
+ assertThrows( new IllegalArgumentException( "invalid color '#f0'" ), () -> UIDefaultsLoader.parseValue( "dummy", "#f0", null ) );
+ assertThrows( new IllegalArgumentException( "invalid color '#f0'" ), () -> UIDefaultsLoader.parseValue( "dummyColor", "#f0", null ) );
+ }
+
+ @Test
+ void parseInvalidValueWithJavaType() {
+ assertThrows( new IllegalArgumentException( "invalid boolean 'falseyy'" ), () -> UIDefaultsLoader.parseValue( "dummy", "falseyy", boolean.class ) );
+ assertThrows( new IllegalArgumentException( "invalid boolean 'falseyy'" ), () -> UIDefaultsLoader.parseValue( "dummy", "falseyy", Boolean.class ) );
+
+ assertThrows( new IllegalArgumentException( "invalid character 'abc'" ), () -> UIDefaultsLoader.parseValue( "dummyChar", "abc", char.class ) );
+ assertThrows( new IllegalArgumentException( "invalid character 'abc'" ), () -> UIDefaultsLoader.parseValue( "dummyChar", "abc", Character.class ) );
+ assertThrows( new NumberFormatException( "invalid integer '123abc'" ), () -> UIDefaultsLoader.parseValue( "dummyWidth", "123abc", int.class ) );
+ assertThrows( new NumberFormatException( "invalid integer '123abc'" ), () -> UIDefaultsLoader.parseValue( "dummyWidth", "123abc", Integer.class ) );
+ assertThrows( new NumberFormatException( "invalid float '1.23abc'" ), () -> UIDefaultsLoader.parseValue( "dummyWidth", "1.23abc", float.class ) );
+ assertThrows( new NumberFormatException( "invalid float '1.23abc'" ), () -> UIDefaultsLoader.parseValue( "dummyWidth", "1.23abc", Float.class ) );
+
+ assertThrows( new IllegalArgumentException( "invalid insets '1,abc,3'" ), () -> UIDefaultsLoader.parseValue( "dummyInsets", "1,abc,3", Insets.class ) );
+ assertThrows( new IllegalArgumentException( "invalid insets '1,2,3'" ), () -> UIDefaultsLoader.parseValue( "dummyInsets", "1,2,3", Insets.class ) );
+ assertThrows( new IllegalArgumentException( "invalid size '1abc'" ), () -> UIDefaultsLoader.parseValue( "dummySize", "1abc", Dimension.class ) );
+ assertThrows( new IllegalArgumentException( "invalid size '1'" ), () -> UIDefaultsLoader.parseValue( "dummySize", "1", Dimension.class ) );
+ assertThrows( new IllegalArgumentException( "invalid color '#f0'" ), () -> UIDefaultsLoader.parseValue( "dummy", "#f0", Color.class ) );
+ assertThrows( new IllegalArgumentException( "invalid color '#f0'" ), () -> UIDefaultsLoader.parseValue( "dummyColor", "#f0", Color.class ) );
+ }
+
+ @Test
+ void parseInvalidBorders() {
+ assertThrows( new IllegalArgumentException( "invalid border '1,abc,3,4' (invalid insets '1,abc,3,4')" ), () -> UIDefaultsLoader.parseValue( "dummyBorder", "1,abc,3,4", null ) );
+ assertThrows( new IllegalArgumentException( "invalid border '1,2,3' (invalid insets '1,2,3')" ), () -> UIDefaultsLoader.parseValue( "dummyBorder", "1,2,3", null ) );
+ assertThrows( new IllegalArgumentException( "invalid border '1,2,3,,,' (invalid insets '1,2,3,,,')" ), () -> UIDefaultsLoader.parseValue( "dummyBorder", "1,2,3,,,", null ) );
+ assertThrows( new IllegalArgumentException( "invalid border '1,2,3,4,#f0' (invalid color '#f0')" ), () -> UIDefaultsLoader.parseValue( "dummyBorder", "1,2,3,4,#f0", null ) );
+ assertThrows( new IllegalArgumentException( "invalid border '1,2,3,4,#f00,2.5abc' (invalid float '2.5abc')" ), () -> UIDefaultsLoader.parseValue( "dummyBorder", "1,2,3,4,#f00,2.5abc", null ) );
+ assertThrows( new IllegalArgumentException( "invalid border '1,2,3,4,#f00,2.5,6abc' (invalid integer '6abc')" ), () -> UIDefaultsLoader.parseValue( "dummyBorder", "1,2,3,4,#f00,2.5,6abc", null ) );
+ }
+
+ @Test
+ void parseInvalidFonts() {
+ // size
+ assertThrows( new IllegalArgumentException( "invalid font '12abc' (invalid integer '12abc')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "12abc", null ) );
+ assertThrows( new IllegalArgumentException( "invalid font '+12abc' (invalid integer '+12abc')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "+12abc", null ) );
+ assertThrows( new IllegalArgumentException( "invalid font '+3abc' (invalid integer '+3abc')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "+3abc", null ) );
+ assertThrows( new IllegalArgumentException( "invalid font '-4abc' (invalid integer '-4abc')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "-4abc", null ) );
+ assertThrows( new IllegalArgumentException( "invalid font '150abc%' (invalid integer '150abc')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "150abc%", null ) );
+ assertThrows( new IllegalArgumentException( "invalid font 'bold 13abc Monospaced' (invalid integer '13abc')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "bold 13abc Monospaced", null ) );
+
+ // invalid combinations of styles
+ assertThrows( new IllegalArgumentException( "invalid font 'bold +italic': can not mix absolute style (e.g. 'bold') with derived style (e.g. '+italic')" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "bold +italic", null ) );
+ assertThrows( new IllegalArgumentException( "invalid font '+bold -bold': can not use '+bold' and '-bold'" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "+bold -bold", null ) );
+ assertThrows( new IllegalArgumentException( "invalid font '+italic -italic': can not use '+italic' and '-italic'" ), () -> UIDefaultsLoader.parseValue( "dummyFont", "+italic -italic", null ) );
+ }
+
+ private void assertThrows( Throwable expected, Executable executable ) {
+ Throwable actual = assertThrowsExactly( expected.getClass(), executable );
+ assertEquals( expected.getMessage(), actual.getMessage() );
+ }
+
//---- class TestInstance -------------------------------------------------
@SuppressWarnings( "EqualsHashCode" ) // Error Prone
diff --git a/flatlaf-demo/build.gradle.kts b/flatlaf-demo/build.gradle.kts
index 55d7e2ef..beb241db 100644
--- a/flatlaf-demo/build.gradle.kts
+++ b/flatlaf-demo/build.gradle.kts
@@ -48,6 +48,9 @@ tasks {
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 )
attributes( "Multi-Release" to "true" )
+
+ // allow loading FlatLaf native library in Java 24+ (see https://openjdk.org/jeps/472)
+ attributes( "Enable-Native-Access" to "ALL-UNNAMED" )
}
exclude( "module-info.class" )
diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java
index 08b0a202..e3711254 100644
--- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java
+++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java
@@ -272,8 +272,20 @@ class DemoFrame
private void windowDecorationsChanged() {
boolean windowDecorations = windowDecorationsCheckBoxMenuItem.isSelected();
- // change window decoration of all frames and dialogs
- FlatLaf.setUseNativeWindowDecorations( windowDecorations );
+ if( SystemInfo.isLinux ) {
+ // enable/disable custom window decorations
+ JFrame.setDefaultLookAndFeelDecorated( windowDecorations );
+ JDialog.setDefaultLookAndFeelDecorated( windowDecorations );
+
+ // dispose frame, update decoration and re-show frame
+ dispose();
+ setUndecorated( windowDecorations );
+ getRootPane().setWindowDecorationStyle( windowDecorations ? JRootPane.FRAME : JRootPane.NONE );
+ setVisible( true );
+ } else {
+ // change window decoration of all frames and dialogs
+ FlatLaf.setUseNativeWindowDecorations( windowDecorations );
+ }
menuBarEmbeddedCheckBoxMenuItem.setEnabled( windowDecorations );
unifiedTitleBarMenuItem.setEnabled( windowDecorations );
@@ -530,7 +542,7 @@ class DemoFrame
}
private boolean supportsFlatLafWindowDecorations() {
- return FlatLaf.supportsNativeWindowDecorations() || (SystemInfo.isLinux && JFrame.isDefaultLookAndFeelDecorated());
+ return FlatLaf.supportsNativeWindowDecorations() || SystemInfo.isLinux;
}
private void initComponents() {
@@ -1045,10 +1057,9 @@ class DemoFrame
scrollingPopupMenu.add( "Item " + i );
if( supportsFlatLafWindowDecorations() ) {
- if( SystemInfo.isLinux )
- unsupported( windowDecorationsCheckBoxMenuItem );
- else
- windowDecorationsCheckBoxMenuItem.setSelected( FlatLaf.isUseNativeWindowDecorations() );
+ windowDecorationsCheckBoxMenuItem.setSelected( SystemInfo.isLinux
+ ? JFrame.isDefaultLookAndFeelDecorated()
+ : FlatLaf.isUseNativeWindowDecorations() );
menuBarEmbeddedCheckBoxMenuItem.setSelected( UIManager.getBoolean( "TitlePane.menuBarEmbedded" ) );
unifiedTitleBarMenuItem.setSelected( UIManager.getBoolean( "TitlePane.unifiedBackground" ) );
showTitleBarIconMenuItem.setSelected( UIManager.getBoolean( "TitlePane.showIcon" ) );
@@ -1092,7 +1103,7 @@ class DemoFrame
private void unsupported( JCheckBoxMenuItem menuItem ) {
menuItem.setEnabled( false );
menuItem.setSelected( false );
- menuItem.setToolTipText( "Not supported on your system." );
+ menuItem.setToolTipText( "Not supported on this platform." );
}
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
diff --git a/flatlaf-extras/README.md b/flatlaf-extras/README.md
index ef66e83d..314f24ae 100644
--- a/flatlaf-extras/README.md
+++ b/flatlaf-extras/README.md
@@ -41,6 +41,11 @@ If SVG classes are used, `jsvg-.jar` is also required:
[](https://maven-badges.herokuapp.com/maven-central/com.github.weisj/jsvg)
+Supported JSVG versions:
+
+- FlatLaf 3.7+ supports JSVG 1.6.0 and later.
+- FlatLaf 3.6- supports only JSVG 1.x (but not 2.x).
+
Tools
-----
diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java
index 046c4ca8..f615a48f 100644
--- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java
+++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGIcon.java
@@ -25,6 +25,7 @@ import java.awt.Image;
import java.awt.Paint;
import java.awt.Rectangle;
import java.awt.RenderingHints;
+import java.awt.geom.Dimension2D;
import java.awt.LinearGradientPaint;
import java.awt.image.BufferedImage;
import java.awt.image.RGBImageFilter;
@@ -52,7 +53,7 @@ import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import com.formdev.flatlaf.util.SoftCache;
import com.formdev.flatlaf.util.UIScale;
import com.github.weisj.jsvg.SVGDocument;
-import com.github.weisj.jsvg.geometry.size.FloatSize;
+import com.github.weisj.jsvg.parser.LoaderContext;
import com.github.weisj.jsvg.parser.SVGLoader;
/**
@@ -271,7 +272,7 @@ public class FlatSVGIcon
this( null, -1, -1, 1, false, null, null );
try( InputStream in2 = in ) {
- document = svgLoader.load( in2 );
+ document = svgLoader.load( in2, null, LoaderContext.createDefault() );
if( document == null ) {
loadFailed = true;
@@ -620,9 +621,9 @@ public class FlatSVGIcon
UIScale.scaleGraphics( g );
if( width > 0 || height > 0 ) {
- FloatSize svgSize = document.size();
- double sx = (width > 0) ? width / svgSize.width : 1;
- double sy = (height > 0) ? height / svgSize.height : 1;
+ Dimension2D svgSize = document.size();
+ double sx = (width > 0) ? width / svgSize.getWidth() : 1;
+ double sy = (height > 0) ? height / svgSize.getHeight() : 1;
if( sx != 1 || sy != 1 )
g.scale( sx, sy );
}
diff --git a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java
index bf09fbc9..c76d5fda 100644
--- a/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java
+++ b/flatlaf-extras/src/main/java/com/formdev/flatlaf/extras/FlatSVGUtils.java
@@ -19,6 +19,7 @@ package com.formdev.flatlaf.extras;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
+import java.awt.geom.Dimension2D;
import java.awt.image.BufferedImage;
import java.net.URL;
import java.util.Arrays;
@@ -28,7 +29,6 @@ import javax.swing.JWindow;
import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import com.formdev.flatlaf.util.SystemInfo;
import com.github.weisj.jsvg.SVGDocument;
-import com.github.weisj.jsvg.geometry.size.FloatSize;
/**
* Utility methods for SVG.
@@ -180,9 +180,9 @@ public class FlatSVGUtils
*/
public static BufferedImage svg2image( URL svgUrl, float scaleFactor ) {
SVGDocument document = FlatSVGIcon.loadSVG( svgUrl );
- FloatSize size = document.size();
- int width = (int) (size.width * scaleFactor);
- int height = (int) (size.height * scaleFactor);
+ Dimension2D size = document.size();
+ int width = (int) (size.getWidth() * scaleFactor);
+ int height = (int) (size.getHeight() * scaleFactor);
return svg2image( document, width, height );
}
@@ -202,9 +202,9 @@ public class FlatSVGUtils
try {
FlatSVGIcon.setRenderingHints( g );
- FloatSize size = document.size();
- double sx = width / size.width;
- double sy = height / size.height;
+ Dimension2D size = document.size();
+ double sx = width / size.getWidth();
+ double sy = height / size.getHeight();
if( sx != 1 || sy != 1 )
g.scale( sx, sy );
diff --git a/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatJideSplitButtonUI.java b/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatJideSplitButtonUI.java
index 080cf1fb..25ca30f4 100644
--- a/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatJideSplitButtonUI.java
+++ b/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatJideSplitButtonUI.java
@@ -25,9 +25,11 @@ import java.awt.geom.Rectangle2D;
import javax.swing.ButtonModel;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
+import javax.swing.plaf.PopupMenuUI;
import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.UIScale;
import com.jidesoft.plaf.LookAndFeelFactory;
@@ -54,6 +56,14 @@ public class FlatJideSplitButtonUI
// but it does not because FlatLaf already has added the UI class to the UI defaults
LookAndFeelFactory.installJideExtension();
+ // workaround for bug in JideSplitButton, which overrides JMenu.updateUI(),
+ // but does not invoke super.updateUI() to update UI of JMenu.popupMenu field
+ if( c instanceof JideSplitButton ) {
+ JPopupMenu popupMenu = ((JideSplitButton)c).getPopupMenu();
+ if( popupMenu != null )
+ popupMenu.setUI( (PopupMenuUI) UIManager.getUI( popupMenu ) );
+ }
+
return new FlatJideSplitButtonUI();
}
diff --git a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0-linux.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0-linux.txt
index f70ad825..5259e6e9 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0-linux.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0-linux.txt
@@ -25,18 +25,6 @@
+ ProgressBar.font [active] Liberation Sans plain 13 javax.swing.plaf.FontUIResource [UI]
-#---- ScrollBar ----
-
-- ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
-+ ScrollBar.minimumThumbSize 18,18 javax.swing.plaf.DimensionUIResource [UI]
-
-- ScrollBar.thumbArc 0
-+ ScrollBar.thumbArc 999
-
-- ScrollBar.thumbInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
-+ ScrollBar.thumbInsets 2,2,2,2 javax.swing.plaf.InsetsUIResource [UI]
-
-
#---- TaskPane ----
- TaskPane.font [active] Segoe UI bold 12 javax.swing.plaf.FontUIResource [UI]
diff --git a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0-mac.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0-mac.txt
index 7f0d7d07..eb458058 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0-mac.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0-mac.txt
@@ -68,15 +68,6 @@
- ScrollBar.hoverThumbWithTrack false
+ ScrollBar.hoverThumbWithTrack true
-- ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
-+ ScrollBar.minimumThumbSize 18,18 javax.swing.plaf.DimensionUIResource [UI]
-
-- ScrollBar.thumbArc 0
-+ ScrollBar.thumbArc 999
-
-- ScrollBar.thumbInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
-+ ScrollBar.thumbInsets 2,2,2,2 javax.swing.plaf.InsetsUIResource [UI]
-
#---- TaskPane ----
diff --git a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt
index ce1fec24..a96d5114 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt
@@ -881,22 +881,22 @@ ScrollBar.buttonArrowColor #b7b7b7 HSL 0 0 72 javax.swing.plaf.Colo
ScrollBar.buttonDisabledArrowColor #777777 HSL 0 0 47 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.foreground #dddddd HSL 0 0 87 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.hoverButtonBackground #484c4e HSL 200 4 29 com.formdev.flatlaf.util.DerivedColor [UI] lighten(5%)
-ScrollBar.hoverThumbColor #6e767a HSL 200 5 45 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10%)
+ScrollBar.hoverThumbColor #7a8387 HSL 198 5 50 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10%)
ScrollBar.hoverThumbWithTrack false
ScrollBar.hoverTrackColor #484c4f HSL 206 5 30 com.formdev.flatlaf.util.DerivedColor [UI] lighten(4%)
ScrollBar.maximumThumbSize 100000,100000 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.minimumButtonSize 12,12 javax.swing.plaf.DimensionUIResource [UI]
-ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
+ScrollBar.minimumThumbSize 18,18 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.pressedButtonBackground #54595c HSL 203 5 35 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10%)
-ScrollBar.pressedThumbColor #7a8387 HSL 198 5 50 com.formdev.flatlaf.util.DerivedColor [UI] lighten(15%)
+ScrollBar.pressedThumbColor #888f93 HSL 202 5 55 com.formdev.flatlaf.util.DerivedColor [UI] lighten(15%)
ScrollBar.pressedThumbWithTrack false
ScrollBar.showButtons false
ScrollBar.squareButtons false
-ScrollBar.thumb #565c5f HSL 200 5 35 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10%)
-ScrollBar.thumbArc 0
+ScrollBar.thumb #62696c HSL 198 5 40 com.formdev.flatlaf.util.DerivedColor [UI] lighten(15%)
+ScrollBar.thumbArc 999
ScrollBar.thumbDarkShadow #7a7d7f HSL 204 2 49 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.thumbHighlight #232324 HSL 240 1 14 javax.swing.plaf.ColorUIResource [UI]
-ScrollBar.thumbInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
+ScrollBar.thumbInsets 2,2,2,2 javax.swing.plaf.InsetsUIResource [UI]
ScrollBar.thumbShadow #616365 HSL 210 2 39 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.track #3e4244 HSL 200 5 25 com.formdev.flatlaf.util.DerivedColor [UI] lighten(1%)
ScrollBar.trackArc 0
diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0-linux.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0-linux.txt
index d8837b5a..b3a9f77e 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0-linux.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0-linux.txt
@@ -25,18 +25,6 @@
+ ProgressBar.font [active] Liberation Sans plain 13 javax.swing.plaf.FontUIResource [UI]
-#---- ScrollBar ----
-
-- ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
-+ ScrollBar.minimumThumbSize 18,18 javax.swing.plaf.DimensionUIResource [UI]
-
-- ScrollBar.thumbArc 0
-+ ScrollBar.thumbArc 999
-
-- ScrollBar.thumbInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
-+ ScrollBar.thumbInsets 2,2,2,2 javax.swing.plaf.InsetsUIResource [UI]
-
-
#---- TaskPane ----
- TaskPane.font [active] Segoe UI bold 12 javax.swing.plaf.FontUIResource [UI]
diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0-mac.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0-mac.txt
index 46d779b2..f79062bb 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0-mac.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0-mac.txt
@@ -68,15 +68,6 @@
- ScrollBar.hoverThumbWithTrack false
+ ScrollBar.hoverThumbWithTrack true
-- ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
-+ ScrollBar.minimumThumbSize 18,18 javax.swing.plaf.DimensionUIResource [UI]
-
-- ScrollBar.thumbArc 0
-+ ScrollBar.thumbArc 999
-
-- ScrollBar.thumbInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
-+ ScrollBar.thumbInsets 2,2,2,2 javax.swing.plaf.InsetsUIResource [UI]
-
#---- TaskPane ----
diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt
index 47a09ec5..2d18f745 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt
@@ -886,22 +886,22 @@ ScrollBar.buttonArrowColor #666666 HSL 0 0 40 javax.swing.plaf.Colo
ScrollBar.buttonDisabledArrowColor #a6a6a6 HSL 0 0 65 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.hoverButtonBackground #e5e5e5 HSL 0 0 90 com.formdev.flatlaf.util.DerivedColor [UI] darken(5%)
-ScrollBar.hoverThumbColor #c3c3c3 HSL 0 0 76 com.formdev.flatlaf.util.DerivedColor [UI] darken(10%)
+ScrollBar.hoverThumbColor #b6b6b6 HSL 0 0 71 com.formdev.flatlaf.util.DerivedColor [UI] darken(10%)
ScrollBar.hoverThumbWithTrack false
ScrollBar.hoverTrackColor #ededed HSL 0 0 93 com.formdev.flatlaf.util.DerivedColor [UI] darken(3%)
ScrollBar.maximumThumbSize 100000,100000 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.minimumButtonSize 12,12 javax.swing.plaf.DimensionUIResource [UI]
-ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
+ScrollBar.minimumThumbSize 18,18 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.pressedButtonBackground #d9d9d9 HSL 0 0 85 com.formdev.flatlaf.util.DerivedColor [UI] darken(10%)
-ScrollBar.pressedThumbColor #a9a9a9 HSL 0 0 66 com.formdev.flatlaf.util.DerivedColor [UI] darken(20%)
+ScrollBar.pressedThumbColor #9c9c9c HSL 0 0 61 com.formdev.flatlaf.util.DerivedColor [UI] darken(20%)
ScrollBar.pressedThumbWithTrack false
ScrollBar.showButtons false
ScrollBar.squareButtons false
-ScrollBar.thumb #dcdcdc HSL 0 0 86 com.formdev.flatlaf.util.DerivedColor [UI] darken(10%)
-ScrollBar.thumbArc 0
+ScrollBar.thumb #cfcfcf HSL 0 0 81 com.formdev.flatlaf.util.DerivedColor [UI] darken(15%)
+ScrollBar.thumbArc 999
ScrollBar.thumbDarkShadow #9c9c9c HSL 0 0 61 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.thumbHighlight #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
-ScrollBar.thumbInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
+ScrollBar.thumbInsets 2,2,2,2 javax.swing.plaf.InsetsUIResource [UI]
ScrollBar.thumbShadow #c2c2c2 HSL 0 0 76 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.track #f5f5f5 HSL 0 0 96 com.formdev.flatlaf.util.DerivedColor [UI] lighten(1%)
ScrollBar.trackArc 0
diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt
index 572dc92e..a7392ccb 100644
--- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt
+++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt
@@ -919,15 +919,15 @@ ScrollBar.hoverThumbWithTrack false
ScrollBar.hoverTrackColor #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.maximumThumbSize 100000,100000 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.minimumButtonSize 12,12 javax.swing.plaf.DimensionUIResource [UI]
-ScrollBar.minimumThumbSize 10,10 javax.swing.plaf.DimensionUIResource [UI]
+ScrollBar.minimumThumbSize 18,18 javax.swing.plaf.DimensionUIResource [UI]
ScrollBar.pressedThumbWithTrack false
ScrollBar.showButtons false
ScrollBar.squareButtons false
ScrollBar.thumb #73737333 20% HSLA 0 0 45 20 javax.swing.plaf.ColorUIResource [UI]
-ScrollBar.thumbArc 0
+ScrollBar.thumbArc 999
ScrollBar.thumbDarkShadow #696969 HSL 0 0 41 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.thumbHighlight #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
-ScrollBar.thumbInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
+ScrollBar.thumbInsets 2,2,2,2 javax.swing.plaf.InsetsUIResource [UI]
ScrollBar.thumbShadow #a0a0a0 HSL 0 0 63 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.track #88ff88 HSL 120 100 77 javax.swing.plaf.ColorUIResource [UI]
ScrollBar.trackArc 0
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSingleComponentTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSingleComponentTest.java
index 6c40eb87..a2b51e5f 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSingleComponentTest.java
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatSingleComponentTest.java
@@ -24,13 +24,8 @@ import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
-import javax.swing.JButton;
-import javax.swing.JComponent;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JScrollPane;
-import javax.swing.KeyStroke;
-import javax.swing.UIManager;
+import java.util.function.Supplier;
+import javax.swing.*;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import com.formdev.flatlaf.FlatDarculaLaf;
@@ -59,11 +54,18 @@ public class FlatSingleComponentTest
private final JLabel infoLabel;
- private JComponent createSingleComponent() {
+ protected JComponent createSingleComponent() {
return new JButton( "hello" );
}
public static void main( String[] args ) {
+ EventQueue.invokeLater( () -> {
+ launch( FlatSingleComponentTest::new, args );
+ } );
+ }
+
+ @SuppressWarnings( "ReturnValueIgnored" ) // Error Prone
+ protected static void launch( Supplier factory, String[] args ) {
DemoPrefs.init( PREFS_ROOT_PATH );
DemoPrefs.initSystemScale();
@@ -88,10 +90,10 @@ public class FlatSingleComponentTest
DemoPrefs.setupLaf( args );
// create and show frame
- new FlatSingleComponentTest();
+ factory.get();
}
- private FlatSingleComponentTest() {
+ protected FlatSingleComponentTest() {
super( "FlatSingleComponentTest" );
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java
index 8b74098e..da05be2c 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.java
@@ -18,7 +18,9 @@ package com.formdev.flatlaf.testing;
import java.awt.Color;
import java.awt.Component;
+import java.awt.Container;
import java.awt.Dimension;
+import java.awt.FocusTraversalPolicy;
import java.awt.Graphics;
import java.awt.Insets;
import java.util.function.Supplier;
@@ -47,6 +49,12 @@ public class FlatTextComponentsTest
FlatTextComponentsTest() {
initComponents();
updatePreferredSizes();
+
+ // exclude from tab focus traversal
+ controlPanel.setFocusTraversalPolicyProvider( true );
+ controlPanel.setFocusTraversalPolicy( new NotFocusableTraversalPolicy() );
+ placeholderPanel.setFocusTraversalPolicyProvider( true );
+ placeholderPanel.setFocusTraversalPolicy( new NotFocusableTraversalPolicy() );
}
@Override
@@ -196,7 +204,7 @@ public class FlatTextComponentsTest
JLabel formattedTextFieldLabel = new JLabel();
JFormattedTextField formattedTextField1 = new JFormattedTextField();
JFormattedTextField formattedTextField3 = new JFormattedTextField();
- JPanel panel1 = new JPanel();
+ controlPanel = new JPanel();
editableCheckBox = new JCheckBox();
JButton button1 = new JButton();
JLabel leftPaddingLabel = new JLabel();
@@ -215,7 +223,7 @@ public class FlatTextComponentsTest
trailingComponentVisibleCheckBox = new JCheckBox();
showClearButtonCheckBox = new JCheckBox();
showRevealButtonCheckBox = new JCheckBox();
- JPanel panel2 = new JPanel();
+ placeholderPanel = new JPanel();
JLabel label7 = new JLabel();
FlatTextField flatTextField1 = new FlatTextField();
JLabel label8 = new JLabel();
@@ -351,11 +359,11 @@ public class FlatTextComponentsTest
formattedTextField3.putClientProperty(FlatClientProperties.PLACEHOLDER_TEXT, "place");
add(formattedTextField3, "cell 2 1,growx");
- //======== panel1 ========
+ //======== controlPanel ========
{
- panel1.setBorder(new TitledBorder("Control"));
- panel1.putClientProperty("FlatLaf.internal.testing.ignore", true);
- panel1.setLayout(new MigLayout(
+ controlPanel.setBorder(new TitledBorder("Control"));
+ controlPanel.putClientProperty("FlatLaf.internal.testing.ignore", true);
+ controlPanel.setLayout(new MigLayout(
"hidemode 3",
// columns
"[fill]" +
@@ -379,94 +387,104 @@ public class FlatTextComponentsTest
//---- editableCheckBox ----
editableCheckBox.setText("editable");
editableCheckBox.setSelected(true);
+ editableCheckBox.setFocusable(false);
editableCheckBox.addActionListener(e -> editableChanged());
- panel1.add(editableCheckBox, "cell 0 0 2 1,alignx left,growx 0");
+ controlPanel.add(editableCheckBox, "cell 0 0 2 1,alignx left,growx 0");
//---- button1 ----
button1.setText("change text");
+ button1.setFocusable(false);
button1.addActionListener(e -> changeText());
- panel1.add(button1, "cell 0 1 2 1,alignx left,growx 0");
+ controlPanel.add(button1, "cell 0 1 2 1,alignx left,growx 0");
//---- leftPaddingLabel ----
leftPaddingLabel.setText("Left padding:");
- panel1.add(leftPaddingLabel, "cell 0 2");
+ controlPanel.add(leftPaddingLabel, "cell 0 2");
//---- leftPaddingField ----
leftPaddingField.addChangeListener(e -> paddingChanged());
- panel1.add(leftPaddingField, "cell 1 2");
+ controlPanel.add(leftPaddingField, "cell 1 2");
//---- rightPaddingLabel ----
rightPaddingLabel.setText("Right padding:");
- panel1.add(rightPaddingLabel, "cell 0 3");
+ controlPanel.add(rightPaddingLabel, "cell 0 3");
//---- rightPaddingField ----
rightPaddingField.addChangeListener(e -> paddingChanged());
- panel1.add(rightPaddingField, "cell 1 3");
+ controlPanel.add(rightPaddingField, "cell 1 3");
//---- topPaddingLabel ----
topPaddingLabel.setText("Top padding:");
- panel1.add(topPaddingLabel, "cell 0 4");
+ controlPanel.add(topPaddingLabel, "cell 0 4");
//---- topPaddingField ----
topPaddingField.addChangeListener(e -> paddingChanged());
- panel1.add(topPaddingField, "cell 1 4");
+ controlPanel.add(topPaddingField, "cell 1 4");
//---- bottomPaddingLabel ----
bottomPaddingLabel.setText("Bottom padding:");
- panel1.add(bottomPaddingLabel, "cell 0 5");
+ controlPanel.add(bottomPaddingLabel, "cell 0 5");
//---- bottomPaddingField ----
bottomPaddingField.addChangeListener(e -> paddingChanged());
- panel1.add(bottomPaddingField, "cell 1 5");
+ controlPanel.add(bottomPaddingField, "cell 1 5");
//---- leadingIconCheckBox ----
leadingIconCheckBox.setText("leading icon");
+ leadingIconCheckBox.setFocusable(false);
leadingIconCheckBox.addActionListener(e -> leadingIcon());
- panel1.add(leadingIconCheckBox, "cell 0 6 2 1,alignx left,growx 0");
+ controlPanel.add(leadingIconCheckBox, "cell 0 6 2 1,alignx left,growx 0");
//---- trailingIconCheckBox ----
trailingIconCheckBox.setText("trailing icon");
+ trailingIconCheckBox.setFocusable(false);
trailingIconCheckBox.addActionListener(e -> trailingIcon());
- panel1.add(trailingIconCheckBox, "cell 0 7 2 1,alignx left,growx 0");
+ controlPanel.add(trailingIconCheckBox, "cell 0 7 2 1,alignx left,growx 0");
//---- leadingComponentCheckBox ----
leadingComponentCheckBox.setText("leading component");
+ leadingComponentCheckBox.setFocusable(false);
leadingComponentCheckBox.addActionListener(e -> leadingComponent());
- panel1.add(leadingComponentCheckBox, "cell 0 8 2 1,alignx left,growx 0");
+ controlPanel.add(leadingComponentCheckBox, "cell 0 8 2 1,alignx left,growx 0");
//---- trailingComponentCheckBox ----
trailingComponentCheckBox.setText("trailing component");
+ trailingComponentCheckBox.setFocusable(false);
trailingComponentCheckBox.addActionListener(e -> trailingComponent());
- panel1.add(trailingComponentCheckBox, "cell 0 9 2 1,alignx left,growx 0");
+ controlPanel.add(trailingComponentCheckBox, "cell 0 9 2 1,alignx left,growx 0");
//---- leadingComponentVisibleCheckBox ----
leadingComponentVisibleCheckBox.setText("leading component visible");
leadingComponentVisibleCheckBox.setSelected(true);
+ leadingComponentVisibleCheckBox.setFocusable(false);
leadingComponentVisibleCheckBox.addActionListener(e -> leadingComponentVisible());
- panel1.add(leadingComponentVisibleCheckBox, "cell 0 10 2 1,alignx left,growx 0");
+ controlPanel.add(leadingComponentVisibleCheckBox, "cell 0 10 2 1,alignx left,growx 0");
//---- trailingComponentVisibleCheckBox ----
trailingComponentVisibleCheckBox.setText("trailing component visible");
trailingComponentVisibleCheckBox.setSelected(true);
+ trailingComponentVisibleCheckBox.setFocusable(false);
trailingComponentVisibleCheckBox.addActionListener(e -> trailingComponentVisible());
- panel1.add(trailingComponentVisibleCheckBox, "cell 0 11 2 1,alignx left,growx 0");
+ controlPanel.add(trailingComponentVisibleCheckBox, "cell 0 11 2 1,alignx left,growx 0");
//---- showClearButtonCheckBox ----
showClearButtonCheckBox.setText("clear button");
+ showClearButtonCheckBox.setFocusable(false);
showClearButtonCheckBox.addActionListener(e -> showClearButton());
- panel1.add(showClearButtonCheckBox, "cell 0 12 2 1,alignx left,growx 0");
+ controlPanel.add(showClearButtonCheckBox, "cell 0 12 2 1,alignx left,growx 0");
//---- showRevealButtonCheckBox ----
showRevealButtonCheckBox.setText("password reveal button");
+ showRevealButtonCheckBox.setFocusable(false);
showRevealButtonCheckBox.addActionListener(e -> showRevealButton());
- panel1.add(showRevealButtonCheckBox, "cell 0 13 2 1,alignx left,growx 0");
+ controlPanel.add(showRevealButtonCheckBox, "cell 0 13 2 1,alignx left,growx 0");
}
- add(panel1, "cell 4 0 1 10,aligny top,growy 0");
+ add(controlPanel, "cell 4 0 1 10,aligny top,growy 0");
- //======== panel2 ========
+ //======== placeholderPanel ========
{
- panel2.setBorder(new TitledBorder("Placeholder"));
- panel2.setLayout(new MigLayout(
+ placeholderPanel.setBorder(new TitledBorder("Placeholder"));
+ placeholderPanel.setLayout(new MigLayout(
"hidemode 3",
// columns
"[fill]" +
@@ -480,55 +498,55 @@ public class FlatTextComponentsTest
//---- label7 ----
label7.setText("leading");
- panel2.add(label7, "cell 0 0");
+ placeholderPanel.add(label7, "cell 0 0");
//---- flatTextField1 ----
flatTextField1.setHorizontalAlignment(SwingConstants.LEADING);
flatTextField1.setPlaceholderText("text");
flatTextField1.setColumns(10);
- panel2.add(flatTextField1, "cell 1 0");
+ placeholderPanel.add(flatTextField1, "cell 1 0");
//---- label8 ----
label8.setText("left");
- panel2.add(label8, "cell 0 1");
+ placeholderPanel.add(label8, "cell 0 1");
//---- flatTextField2 ----
flatTextField2.setHorizontalAlignment(SwingConstants.LEFT);
flatTextField2.setPlaceholderText("text");
flatTextField2.setColumns(10);
- panel2.add(flatTextField2, "cell 1 1");
+ placeholderPanel.add(flatTextField2, "cell 1 1");
//---- label9 ----
label9.setText("center");
- panel2.add(label9, "cell 0 2");
+ placeholderPanel.add(label9, "cell 0 2");
//---- flatTextField3 ----
flatTextField3.setHorizontalAlignment(SwingConstants.CENTER);
flatTextField3.setPlaceholderText("text");
flatTextField3.setColumns(10);
- panel2.add(flatTextField3, "cell 1 2");
+ placeholderPanel.add(flatTextField3, "cell 1 2");
//---- label10 ----
label10.setText("right");
- panel2.add(label10, "cell 0 3");
+ placeholderPanel.add(label10, "cell 0 3");
//---- flatTextField4 ----
flatTextField4.setHorizontalAlignment(SwingConstants.RIGHT);
flatTextField4.setPlaceholderText("text");
flatTextField4.setColumns(10);
- panel2.add(flatTextField4, "cell 1 3");
+ placeholderPanel.add(flatTextField4, "cell 1 3");
//---- label11 ----
label11.setText("trailing");
- panel2.add(label11, "cell 0 4");
+ placeholderPanel.add(label11, "cell 0 4");
//---- flatTextField5 ----
flatTextField5.setHorizontalAlignment(SwingConstants.TRAILING);
flatTextField5.setPlaceholderText("text");
flatTextField5.setColumns(10);
- panel2.add(flatTextField5, "cell 1 4");
+ placeholderPanel.add(flatTextField5, "cell 1 4");
}
- add(panel2, "cell 5 0 1 9,aligny top,growy 0");
+ add(placeholderPanel, "cell 5 0 1 10,aligny top,growy 0");
//---- passwordFieldLabel ----
passwordFieldLabel.setText("JPasswordField:");
@@ -783,6 +801,7 @@ public class FlatTextComponentsTest
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JTextField textField1;
+ private JPanel controlPanel;
private JCheckBox editableCheckBox;
private JSpinner leftPaddingField;
private JSpinner rightPaddingField;
@@ -796,6 +815,7 @@ public class FlatTextComponentsTest
private JCheckBox trailingComponentVisibleCheckBox;
private JCheckBox showClearButtonCheckBox;
private JCheckBox showRevealButtonCheckBox;
+ private JPanel placeholderPanel;
private JComboBox comboBox5;
private JSpinner spinner4;
private JComboBox comboBox6;
@@ -807,6 +827,18 @@ public class FlatTextComponentsTest
private JEditorPane editorPane;
// JFormDesigner - End of variables declaration //GEN-END:variables
+ //---- NotFocusableTraversalPolicy ----------------------------------------
+
+ private static class NotFocusableTraversalPolicy
+ extends FocusTraversalPolicy
+ {
+ @Override public Component getComponentAfter( Container aContainer, Component aComponent ) { return null; }
+ @Override public Component getComponentBefore( Container aContainer, Component aComponent ) { return null; }
+ @Override public Component getFirstComponent( Container aContainer ) { return null; }
+ @Override public Component getLastComponent( Container aContainer ) { return null; }
+ @Override public Component getDefaultComponent( Container aContainer ) { return null; }
+ }
+
//---- TestIcon -----------------------------------------------------------
private static class TestIcon
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd
index 73b5c705..8484ae6f 100644
--- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextComponentsTest.jfd
@@ -1,4 +1,4 @@
-JFDML JFormDesigner: "8.1.0.0.283" Java: "19.0.2" encoding: "UTF-8"
+JFDML JFormDesigner: "8.3" encoding: "UTF-8"
new FormModel {
contentType: "form/swing"
@@ -78,13 +78,17 @@ new FormModel {
"$columnConstraints": "[fill][fill]"
"$rowConstraints": "[][][][][][][]0[][]0[][]0[][][]"
} ) {
- name: "panel1"
+ name: "controlPanel"
"border": new javax.swing.border.TitledBorder( "Control" )
"$client.FlatLaf.internal.testing.ignore": true
+ auxiliary() {
+ "JavaCodeGenerator.variableLocal": false
+ }
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "editableCheckBox"
"text": "editable"
"selected": true
+ "focusable": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
@@ -95,6 +99,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JButton" ) {
name: "button1"
"text": "change text"
+ "focusable": false
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeText", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 1 2 1,alignx left,growx 0"
@@ -162,6 +167,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "leadingIconCheckBox"
"text": "leading icon"
+ "focusable": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
@@ -172,6 +178,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "trailingIconCheckBox"
"text": "trailing icon"
+ "focusable": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
@@ -182,6 +189,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "leadingComponentCheckBox"
"text": "leading component"
+ "focusable": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
@@ -192,6 +200,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "trailingComponentCheckBox"
"text": "trailing component"
+ "focusable": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
@@ -203,6 +212,7 @@ new FormModel {
name: "leadingComponentVisibleCheckBox"
"text": "leading component visible"
"selected": true
+ "focusable": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
@@ -214,6 +224,7 @@ new FormModel {
name: "trailingComponentVisibleCheckBox"
"text": "trailing component visible"
"selected": true
+ "focusable": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
@@ -224,6 +235,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "showClearButtonCheckBox"
"text": "clear button"
+ "focusable": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
@@ -234,6 +246,7 @@ new FormModel {
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "showRevealButtonCheckBox"
"text": "password reveal button"
+ "focusable": false
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
@@ -249,8 +262,11 @@ new FormModel {
"$columnConstraints": "[fill][fill]"
"$rowConstraints": "[][][][][]"
} ) {
- name: "panel2"
+ name: "placeholderPanel"
"border": new javax.swing.border.TitledBorder( "Placeholder" )
+ auxiliary() {
+ "JavaCodeGenerator.variableLocal": false
+ }
add( new FormComponent( "javax.swing.JLabel" ) {
name: "label7"
"text": "leading"
@@ -325,7 +341,7 @@ new FormModel {
"value": "cell 1 4"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
- "value": "cell 5 0 1 9,aligny top,growy 0"
+ "value": "cell 5 0 1 10,aligny top,growy 0"
} )
add( new FormComponent( "javax.swing.JLabel" ) {
name: "passwordFieldLabel"
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextSelectAllOnFocusTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextSelectAllOnFocusTest.java
new file mode 100644
index 00000000..9a27b069
--- /dev/null
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextSelectAllOnFocusTest.java
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2025 FormDev Software GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.formdev.flatlaf.testing;
+
+import static com.formdev.flatlaf.FlatClientProperties.*;
+import java.awt.EventQueue;
+import java.text.ParseException;
+import javax.swing.*;
+import javax.swing.text.DefaultFormatterFactory;
+import javax.swing.text.MaskFormatter;
+import net.miginfocom.swing.*;
+
+/**
+ * @author Karl Tauber
+ */
+public class FlatTextSelectAllOnFocusTest
+ extends FlatSingleComponentTest
+{
+ public static void main( String[] args ) {
+ EventQueue.invokeLater( () -> {
+ launch( FlatTextSelectAllOnFocusTest::new, args );
+ } );
+ }
+
+ @Override
+ protected JComponent createSingleComponent() {
+ initComponents();
+
+ try {
+ MaskFormatter formatter = new MaskFormatter( "###-####-###" );
+ formatter.setPlaceholderCharacter( '_' );
+ DefaultFormatterFactory factory = new DefaultFormatterFactory( formatter );
+
+ formattedTextField1.setFormatterFactory( factory );
+ formattedTextField2.setFormatterFactory( factory );
+ formattedTextField3.setFormatterFactory( factory );
+ formattedTextField4.setFormatterFactory( factory );
+ formattedTextField5.setFormatterFactory( factory );
+ formattedTextField6.setFormatterFactory( factory );
+
+ formattedTextField1.setValue( "123-4567-890" );
+ formattedTextField2.setValue( "123-4567-890" );
+ formattedTextField3.setValue( "123-4567-890" );
+ formattedTextField4.setValue( "123-4567-890" );
+ formattedTextField5.setValue( "123-4567-890" );
+ formattedTextField6.setValue( "123-4567-890" );
+ } catch( ParseException ex ) {
+ ex.printStackTrace();
+ }
+
+ textField2.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_NEVER );
+ textField3.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ONCE );
+ textField4.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ALWAYS );
+ textField5.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ONCE );
+ textField5.putClientProperty( SELECT_ALL_ON_MOUSE_CLICK, true );
+ textField6.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ALWAYS );
+ textField6.putClientProperty( SELECT_ALL_ON_MOUSE_CLICK, true );
+ textField7.select( 5, 7 );
+
+ formattedTextField2.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_NEVER );
+ formattedTextField3.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ONCE );
+ formattedTextField4.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ALWAYS );
+ formattedTextField5.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ONCE );
+ formattedTextField5.putClientProperty( SELECT_ALL_ON_MOUSE_CLICK, true );
+ formattedTextField6.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ALWAYS );
+ formattedTextField6.putClientProperty( SELECT_ALL_ON_MOUSE_CLICK, true );
+
+ comboBox2.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_NEVER );
+ comboBox3.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ONCE );
+ comboBox4.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ALWAYS );
+ comboBox5.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ONCE );
+ comboBox5.putClientProperty( SELECT_ALL_ON_MOUSE_CLICK, true );
+ comboBox6.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ALWAYS );
+ comboBox6.putClientProperty( SELECT_ALL_ON_MOUSE_CLICK, true );
+ ((JTextField)comboBox7.getEditor().getEditorComponent()).select( 5, 7 );
+
+ spinner2.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_NEVER );
+ spinner3.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ONCE );
+ spinner4.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ALWAYS );
+ spinner5.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ONCE );
+ spinner5.putClientProperty( SELECT_ALL_ON_MOUSE_CLICK, true );
+ spinner6.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ALWAYS );
+ spinner6.putClientProperty( SELECT_ALL_ON_MOUSE_CLICK, true );
+
+// textArea1.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ALWAYS );
+// textPane1.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ALWAYS );
+// editorPane1.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ALWAYS );
+//
+// textArea1.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ONCE );
+// textPane1.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ONCE );
+// editorPane1.putClientProperty( SELECT_ALL_ON_FOCUS_POLICY, SELECT_ALL_ON_FOCUS_POLICY_ONCE );
+//
+// textArea1.putClientProperty( SELECT_ALL_ON_MOUSE_CLICK, true );
+// textPane1.putClientProperty( SELECT_ALL_ON_MOUSE_CLICK, true );
+// editorPane1.putClientProperty( SELECT_ALL_ON_MOUSE_CLICK, true );
+//
+// textArea1.select( 5, 7 );
+// textPane1.select( 5, 7 );
+// editorPane1.select( 5, 7 );
+
+ return panel;
+ }
+
+ private void initComponents() {
+ // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
+ panel = new FlatTestPanel();
+ label1 = new JLabel();
+ label2 = new JLabel();
+ label3 = new JLabel();
+ label4 = new JLabel();
+ label5 = new JLabel();
+ label6 = new JLabel();
+ label7 = new JLabel();
+ textFieldLabel = new JLabel();
+ textField1 = new JTextField();
+ textField2 = new JTextField();
+ textField3 = new JTextField();
+ textField4 = new JTextField();
+ textField5 = new JTextField();
+ textField6 = new JTextField();
+ textField7 = new JTextField();
+ formattedTextFieldLabel = new JLabel();
+ formattedTextField1 = new JFormattedTextField();
+ formattedTextField2 = new JFormattedTextField();
+ formattedTextField3 = new JFormattedTextField();
+ formattedTextField4 = new JFormattedTextField();
+ formattedTextField5 = new JFormattedTextField();
+ formattedTextField6 = new JFormattedTextField();
+ comboBoxLabel = new JLabel();
+ comboBox1 = new JComboBox<>();
+ comboBox2 = new JComboBox<>();
+ comboBox3 = new JComboBox<>();
+ comboBox4 = new JComboBox<>();
+ comboBox5 = new JComboBox<>();
+ comboBox6 = new JComboBox<>();
+ comboBox7 = new JComboBox<>();
+ spinnerLabel = new JLabel();
+ spinner1 = new JSpinner();
+ spinner2 = new JSpinner();
+ spinner3 = new JSpinner();
+ spinner4 = new JSpinner();
+ spinner5 = new JSpinner();
+ spinner6 = new JSpinner();
+ scrollPane1 = new JScrollPane();
+ textArea1 = new JTextArea();
+ scrollPane2 = new JScrollPane();
+ textPane1 = new JTextPane();
+ scrollPane3 = new JScrollPane();
+ editorPane1 = new JEditorPane();
+
+ //======== panel ========
+ {
+ panel.setLayout(new MigLayout(
+ "ltr,insets dialog,hidemode 3",
+ // columns
+ "[]" +
+ "[100,sizegroup 1,fill]" +
+ "[sizegroup 1,fill]" +
+ "[sizegroup 1,fill]" +
+ "[sizegroup 1,fill]" +
+ "[sizegroup 1,fill]" +
+ "[fill]" +
+ "[fill]",
+ // rows
+ "[]" +
+ "[]" +
+ "[]" +
+ "[]" +
+ "[]" +
+ "[fill]" +
+ "[30]"));
+
+ //---- label1 ----
+ label1.setText("default");
+ panel.add(label1, "cell 1 0");
+
+ //---- label2 ----
+ label2.setText("never");
+ panel.add(label2, "cell 2 0");
+
+ //---- label3 ----
+ label3.setText("once");
+ panel.add(label3, "cell 3 0");
+
+ //---- label4 ----
+ label4.setText("always");
+ panel.add(label4, "cell 4 0");
+
+ //---- label5 ----
+ label5.setText("once on click");
+ panel.add(label5, "cell 5 0");
+
+ //---- label6 ----
+ label6.setText("always on click");
+ panel.add(label6, "cell 6 0");
+
+ //---- label7 ----
+ label7.setText("custom selection");
+ panel.add(label7, "cell 7 0");
+
+ //---- textFieldLabel ----
+ textFieldLabel.setText("JTextField:");
+ textFieldLabel.setDisplayedMnemonic('T');
+ textFieldLabel.setLabelFor(textField1);
+ panel.add(textFieldLabel, "cell 0 1");
+
+ //---- textField1 ----
+ textField1.setText("1234567890");
+ panel.add(textField1, "cell 1 1");
+
+ //---- textField2 ----
+ textField2.setText("1234567890");
+ panel.add(textField2, "cell 2 1");
+
+ //---- textField3 ----
+ textField3.setText("1234567890");
+ panel.add(textField3, "cell 3 1");
+
+ //---- textField4 ----
+ textField4.setText("1234567890");
+ panel.add(textField4, "cell 4 1");
+
+ //---- textField5 ----
+ textField5.setText("1234567890");
+ panel.add(textField5, "cell 5 1");
+
+ //---- textField6 ----
+ textField6.setText("1234567890");
+ panel.add(textField6, "cell 6 1");
+
+ //---- textField7 ----
+ textField7.setText("1234567890");
+ panel.add(textField7, "cell 7 1");
+
+ //---- formattedTextFieldLabel ----
+ formattedTextFieldLabel.setText("JFormattedTextField:");
+ formattedTextFieldLabel.setDisplayedMnemonic('F');
+ formattedTextFieldLabel.setLabelFor(formattedTextField1);
+ panel.add(formattedTextFieldLabel, "cell 0 2");
+ panel.add(formattedTextField1, "cell 1 2");
+ panel.add(formattedTextField2, "cell 2 2");
+ panel.add(formattedTextField3, "cell 3 2");
+ panel.add(formattedTextField4, "cell 4 2");
+ panel.add(formattedTextField5, "cell 5 2");
+ panel.add(formattedTextField6, "cell 6 2");
+
+ //---- comboBoxLabel ----
+ comboBoxLabel.setText("JComboBox:");
+ comboBoxLabel.setDisplayedMnemonic('C');
+ comboBoxLabel.setLabelFor(comboBox1);
+ panel.add(comboBoxLabel, "cell 0 3");
+
+ //---- comboBox1 ----
+ comboBox1.setEditable(true);
+ comboBox1.setModel(new DefaultComboBoxModel<>(new String[] {
+ "1234567890"
+ }));
+ panel.add(comboBox1, "cell 1 3");
+
+ //---- comboBox2 ----
+ comboBox2.setEditable(true);
+ comboBox2.setModel(new DefaultComboBoxModel<>(new String[] {
+ "1234567890"
+ }));
+ panel.add(comboBox2, "cell 2 3");
+
+ //---- comboBox3 ----
+ comboBox3.setEditable(true);
+ comboBox3.setModel(new DefaultComboBoxModel<>(new String[] {
+ "1234567890"
+ }));
+ panel.add(comboBox3, "cell 3 3");
+
+ //---- comboBox4 ----
+ comboBox4.setEditable(true);
+ comboBox4.setModel(new DefaultComboBoxModel<>(new String[] {
+ "1234567890"
+ }));
+ panel.add(comboBox4, "cell 4 3");
+
+ //---- comboBox5 ----
+ comboBox5.setEditable(true);
+ comboBox5.setModel(new DefaultComboBoxModel<>(new String[] {
+ "1234567890"
+ }));
+ panel.add(comboBox5, "cell 5 3");
+
+ //---- comboBox6 ----
+ comboBox6.setEditable(true);
+ comboBox6.setModel(new DefaultComboBoxModel<>(new String[] {
+ "1234567890"
+ }));
+ panel.add(comboBox6, "cell 6 3");
+
+ //---- comboBox7 ----
+ comboBox7.setEditable(true);
+ comboBox7.setModel(new DefaultComboBoxModel<>(new String[] {
+ "1234567890"
+ }));
+ panel.add(comboBox7, "cell 7 3");
+
+ //---- spinnerLabel ----
+ spinnerLabel.setText("JSpinner:");
+ spinnerLabel.setDisplayedMnemonic('S');
+ spinnerLabel.setLabelFor(spinner1);
+ panel.add(spinnerLabel, "cell 0 4");
+
+ //---- spinner1 ----
+ spinner1.setModel(new SpinnerNumberModel(1234, null, null, 100));
+ panel.add(spinner1, "cell 1 4");
+
+ //---- spinner2 ----
+ spinner2.setModel(new SpinnerNumberModel(1234, null, null, 100));
+ panel.add(spinner2, "cell 2 4");
+
+ //---- spinner3 ----
+ spinner3.setModel(new SpinnerNumberModel(1234, null, null, 100));
+ panel.add(spinner3, "cell 3 4");
+
+ //---- spinner4 ----
+ spinner4.setModel(new SpinnerNumberModel(1234, null, null, 100));
+ panel.add(spinner4, "cell 4 4");
+
+ //---- spinner5 ----
+ spinner5.setModel(new SpinnerNumberModel(1234, null, null, 100));
+ panel.add(spinner5, "cell 5 4");
+
+ //---- spinner6 ----
+ spinner6.setModel(new SpinnerNumberModel(1234, null, null, 100));
+ panel.add(spinner6, "cell 6 4");
+
+ //======== scrollPane1 ========
+ {
+
+ //---- textArea1 ----
+ textArea1.setRows(3);
+ textArea1.setText("1234567890\nabc");
+ scrollPane1.setViewportView(textArea1);
+ }
+ panel.add(scrollPane1, "cell 1 5");
+
+ //======== scrollPane2 ========
+ {
+
+ //---- textPane1 ----
+ textPane1.setText("1234567890\nabc");
+ scrollPane2.setViewportView(textPane1);
+ }
+ panel.add(scrollPane2, "cell 2 5");
+
+ //======== scrollPane3 ========
+ {
+
+ //---- editorPane1 ----
+ editorPane1.setText("1234567890\nabc");
+ scrollPane3.setViewportView(editorPane1);
+ }
+ panel.add(scrollPane3, "cell 3 5 2 1");
+ }
+ // JFormDesigner - End of component initialization //GEN-END:initComponents
+ }
+
+ // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
+ private FlatTestPanel panel;
+ private JLabel label1;
+ private JLabel label2;
+ private JLabel label3;
+ private JLabel label4;
+ private JLabel label5;
+ private JLabel label6;
+ private JLabel label7;
+ private JLabel textFieldLabel;
+ private JTextField textField1;
+ private JTextField textField2;
+ private JTextField textField3;
+ private JTextField textField4;
+ private JTextField textField5;
+ private JTextField textField6;
+ private JTextField textField7;
+ private JLabel formattedTextFieldLabel;
+ private JFormattedTextField formattedTextField1;
+ private JFormattedTextField formattedTextField2;
+ private JFormattedTextField formattedTextField3;
+ private JFormattedTextField formattedTextField4;
+ private JFormattedTextField formattedTextField5;
+ private JFormattedTextField formattedTextField6;
+ private JLabel comboBoxLabel;
+ private JComboBox comboBox1;
+ private JComboBox comboBox2;
+ private JComboBox comboBox3;
+ private JComboBox comboBox4;
+ private JComboBox comboBox5;
+ private JComboBox comboBox6;
+ private JComboBox comboBox7;
+ private JLabel spinnerLabel;
+ private JSpinner spinner1;
+ private JSpinner spinner2;
+ private JSpinner spinner3;
+ private JSpinner spinner4;
+ private JSpinner spinner5;
+ private JSpinner spinner6;
+ private JScrollPane scrollPane1;
+ private JTextArea textArea1;
+ private JScrollPane scrollPane2;
+ private JTextPane textPane1;
+ private JScrollPane scrollPane3;
+ private JEditorPane editorPane1;
+ // JFormDesigner - End of variables declaration //GEN-END:variables
+}
diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextSelectAllOnFocusTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextSelectAllOnFocusTest.jfd
new file mode 100644
index 00000000..d2a327e6
--- /dev/null
+++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTextSelectAllOnFocusTest.jfd
@@ -0,0 +1,327 @@
+JFDML JFormDesigner: "8.3" encoding: "UTF-8"
+
+new FormModel {
+ contentType: "form/swing"
+ root: new FormRoot {
+ add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
+ "$layoutConstraints": "ltr,insets dialog,hidemode 3"
+ "$columnConstraints": "[][100,sizegroup 1,fill][sizegroup 1,fill][sizegroup 1,fill][sizegroup 1,fill][sizegroup 1,fill][fill][fill]"
+ "$rowConstraints": "[][][][][][fill][30]"
+ } ) {
+ name: "panel"
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "label1"
+ "text": "default"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 0"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "label2"
+ "text": "never"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 0"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "label3"
+ "text": "once"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 3 0"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "label4"
+ "text": "always"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 4 0"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "label5"
+ "text": "once on click"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 5 0"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "label6"
+ "text": "always on click"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 6 0"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "label7"
+ "text": "custom selection"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 7 0"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "textFieldLabel"
+ "text": "JTextField:"
+ "displayedMnemonic": 84
+ "labelFor": new FormReference( "textField1" )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 1"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "textField1"
+ "text": "1234567890"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 1"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "textField2"
+ "text": "1234567890"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 1"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "textField3"
+ "text": "1234567890"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 3 1"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "textField4"
+ "text": "1234567890"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 4 1"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "textField5"
+ "text": "1234567890"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 5 1"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "textField6"
+ "text": "1234567890"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 6 1"
+ } )
+ add( new FormComponent( "javax.swing.JTextField" ) {
+ name: "textField7"
+ "text": "1234567890"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 7 1"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "formattedTextFieldLabel"
+ "text": "JFormattedTextField:"
+ "displayedMnemonic": 70
+ "labelFor": new FormReference( "formattedTextField1" )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 2"
+ } )
+ add( new FormComponent( "javax.swing.JFormattedTextField" ) {
+ name: "formattedTextField1"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 2"
+ } )
+ add( new FormComponent( "javax.swing.JFormattedTextField" ) {
+ name: "formattedTextField2"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 2"
+ } )
+ add( new FormComponent( "javax.swing.JFormattedTextField" ) {
+ name: "formattedTextField3"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 3 2"
+ } )
+ add( new FormComponent( "javax.swing.JFormattedTextField" ) {
+ name: "formattedTextField4"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 4 2"
+ } )
+ add( new FormComponent( "javax.swing.JFormattedTextField" ) {
+ name: "formattedTextField5"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 5 2"
+ } )
+ add( new FormComponent( "javax.swing.JFormattedTextField" ) {
+ name: "formattedTextField6"
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 6 2"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "comboBoxLabel"
+ "text": "JComboBox:"
+ "displayedMnemonic": 67
+ "labelFor": new FormReference( "comboBox1" )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 3"
+ } )
+ add( new FormComponent( "javax.swing.JComboBox" ) {
+ name: "comboBox1"
+ "editable": true
+ "model": new javax.swing.DefaultComboBoxModel {
+ selectedItem: "1234567890"
+ addElement( "1234567890" )
+ }
+ auxiliary() {
+ "JavaCodeGenerator.typeParameters": "String"
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 3"
+ } )
+ add( new FormComponent( "javax.swing.JComboBox" ) {
+ name: "comboBox2"
+ "editable": true
+ "model": new javax.swing.DefaultComboBoxModel {
+ selectedItem: "1234567890"
+ addElement( "1234567890" )
+ }
+ auxiliary() {
+ "JavaCodeGenerator.typeParameters": "String"
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 3"
+ } )
+ add( new FormComponent( "javax.swing.JComboBox" ) {
+ name: "comboBox3"
+ "editable": true
+ "model": new javax.swing.DefaultComboBoxModel {
+ selectedItem: "1234567890"
+ addElement( "1234567890" )
+ }
+ auxiliary() {
+ "JavaCodeGenerator.typeParameters": "String"
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 3 3"
+ } )
+ add( new FormComponent( "javax.swing.JComboBox" ) {
+ name: "comboBox4"
+ "editable": true
+ "model": new javax.swing.DefaultComboBoxModel {
+ selectedItem: "1234567890"
+ addElement( "1234567890" )
+ }
+ auxiliary() {
+ "JavaCodeGenerator.typeParameters": "String"
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 4 3"
+ } )
+ add( new FormComponent( "javax.swing.JComboBox" ) {
+ name: "comboBox5"
+ "editable": true
+ "model": &DefaultComboBoxModel0 new javax.swing.DefaultComboBoxModel {
+ selectedItem: "1234567890"
+ addElement( "1234567890" )
+ }
+ auxiliary() {
+ "JavaCodeGenerator.typeParameters": "String"
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 5 3"
+ } )
+ add( new FormComponent( "javax.swing.JComboBox" ) {
+ name: "comboBox6"
+ "editable": true
+ "model": #DefaultComboBoxModel0
+ auxiliary() {
+ "JavaCodeGenerator.typeParameters": "String"
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 6 3"
+ } )
+ add( new FormComponent( "javax.swing.JComboBox" ) {
+ name: "comboBox7"
+ "editable": true
+ "model": #DefaultComboBoxModel0
+ auxiliary() {
+ "JavaCodeGenerator.typeParameters": "String"
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 7 3"
+ } )
+ add( new FormComponent( "javax.swing.JLabel" ) {
+ name: "spinnerLabel"
+ "text": "JSpinner:"
+ "displayedMnemonic": 83
+ "labelFor": new FormReference( "spinner1" )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 0 4"
+ } )
+ add( new FormComponent( "javax.swing.JSpinner" ) {
+ name: "spinner1"
+ "model": new javax.swing.SpinnerNumberModel {
+ stepSize: 100
+ value: 1234
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 4"
+ } )
+ add( new FormComponent( "javax.swing.JSpinner" ) {
+ name: "spinner2"
+ "model": new javax.swing.SpinnerNumberModel {
+ stepSize: 100
+ value: 1234
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 4"
+ } )
+ add( new FormComponent( "javax.swing.JSpinner" ) {
+ name: "spinner3"
+ "model": new javax.swing.SpinnerNumberModel {
+ stepSize: 100
+ value: 1234
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 3 4"
+ } )
+ add( new FormComponent( "javax.swing.JSpinner" ) {
+ name: "spinner4"
+ "model": new javax.swing.SpinnerNumberModel {
+ stepSize: 100
+ value: 1234
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 4 4"
+ } )
+ add( new FormComponent( "javax.swing.JSpinner" ) {
+ name: "spinner5"
+ "model": &SpinnerNumberModel0 new javax.swing.SpinnerNumberModel {
+ stepSize: 100
+ value: 1234
+ }
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 5 4"
+ } )
+ add( new FormComponent( "javax.swing.JSpinner" ) {
+ name: "spinner6"
+ "model": #SpinnerNumberModel0
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 6 4"
+ } )
+ add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
+ name: "scrollPane1"
+ add( new FormComponent( "javax.swing.JTextArea" ) {
+ name: "textArea1"
+ "rows": 3
+ "text": "1234567890\nabc"
+ } )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 1 5"
+ } )
+ add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
+ name: "scrollPane2"
+ add( new FormComponent( "javax.swing.JTextPane" ) {
+ name: "textPane1"
+ "text": "1234567890\nabc"
+ } )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 2 5"
+ } )
+ add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
+ name: "scrollPane3"
+ add( new FormComponent( "javax.swing.JEditorPane" ) {
+ name: "editorPane1"
+ "text": "1234567890\nabc"
+ } )
+ }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
+ "value": "cell 3 5 2 1"
+ } )
+ }, new FormLayoutConstraints( null ) {
+ "location": new java.awt.Point( 0, 0 )
+ "size": new java.awt.Dimension( 995, 285 )
+ } )
+ }
+}
diff --git a/flatlaf-theme-editor/build.gradle.kts b/flatlaf-theme-editor/build.gradle.kts
index ffbd4982..d334d2e8 100644
--- a/flatlaf-theme-editor/build.gradle.kts
+++ b/flatlaf-theme-editor/build.gradle.kts
@@ -46,6 +46,9 @@ tasks {
if( JavaVersion.current() >= JavaVersion.VERSION_1_9 )
attributes( "Multi-Release" to "true" )
+
+ // allow loading FlatLaf native library in Java 24+ (see https://openjdk.org/jeps/472)
+ attributes( "Enable-Native-Access" to "ALL-UNNAMED" )
}
exclude( "module-info.class" )
diff --git a/gradle.properties b/gradle.properties
index 6902d50c..2d00cb10 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -14,8 +14,8 @@
# limitations under the License.
#
-flatlaf.releaseVersion = 3.5.4
-flatlaf.developmentVersion = 3.6-SNAPSHOT
+flatlaf.releaseVersion = 3.6
+flatlaf.developmentVersion = 3.7-SNAPSHOT
org.gradle.parallel = true
# org.gradle.warning.mode = all
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 6bd75ca2..ee8ec1ab 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -24,7 +24,7 @@ junit = "5.10.2"
sigtest = "org.netbeans.tools:sigtest-maven-plugin:1.7"
# flatlaf-extras
-jsvg = "com.github.weisj:jsvg:1.4.0"
+jsvg = "com.github.weisj:jsvg:2.0.0"
# flatlaf-jide-oss
jide-oss = "com.formdev:jide-oss:3.7.15"
@@ -59,4 +59,5 @@ errorprone = "com.google.errorprone:error_prone_core:2.20.0"
[plugins]
+gradle-nexus-publish-plugin = { id = "io.github.gradle-nexus.publish-plugin", version = "2.0.0" }
errorprone = { id = "net.ltgt.errorprone", version = "3.1.0" }
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index a4b76b95..1b33c55b 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index e18bc253..002b867c 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
index f3b75f3b..23d15a93 100755
--- a/gradlew
+++ b/gradlew
@@ -114,7 +114,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -205,7 +205,7 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/gradlew.bat b/gradlew.bat
index 9d21a218..db3a6ac2 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -70,11 +70,11 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+set CLASSPATH=
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell