diff --git a/CHANGELOG.md b/CHANGELOG.md index 52587209..39833d21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,12 @@ FlatLaf Change Log - Updated to latest versions and fixed various issues. - Support customizing through properties files. (issue #824) - SwingX: Support `JXTipOfTheDay` component. (issue #980) +- Support key prefixes for Linux desktop environments (e.g. `[gnome]`, `[kde]` + or `[xfce]`) in properties files. (issue #974) +- Support custom key prefixes (e.g. `[win10]` or `[test]`) in properties files. + (issue #649) +- Support multi-prefixed keys (e.g. `[dark][gnome]TitlePane.buttonBackground`). + The value is only used if all prefixes match current platform/theme. #### Fixed bugs @@ -66,6 +72,23 @@ FlatLaf Change Log `com.formdev.flatlaf.intellijthemes.materialthemeuilite` from `Flat` to `FlatMT`. - Removed `Gruvbox Dark Medium` and `Gruvbox Dark Soft` themes. +- Prefixed keys in properties files (e.g. `[dark]Button.background` or + `[win]Button.arc`) are now handled earlier than before. In previous versions, + prefixed keys always had higher priority than unprefixed keys and did always + overwrite unprefixed keys. Now prefixed keys are handled in same order as + unprefixed keys, which means that if a key is prefixed and unprefixed (e.g. + `[win]Button.arc` and `Button.arc`), the one which is last specified in + properties file is used.\ + Following worked in previous versions, but now `Button.arc` is always `6`: + ~~~properties + [win]Button.arc = 12 + Button.arc = 6 + ~~~ + This works in new (and old) versions: + ~~~properties + Button.arc = 6 + [win]Button.arc = 12 + ~~~ ## 3.5.4 diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java index 803783fe..06601bc1 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java @@ -37,6 +37,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -44,6 +45,7 @@ import java.util.MissingResourceException; import java.util.Properties; import java.util.ResourceBundle; import java.util.ServiceLoader; +import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.IntUnaryOperator; @@ -100,6 +102,8 @@ public abstract class FlatLaf private static Map globalExtraDefaults; private Map extraDefaults; private static Function systemColorGetter; + private static Set uiKeyPlatformPrefixes; + private static Set uiKeySpecialPrefixes; private String desktopPropertyName; private String desktopPropertyName2; @@ -1122,6 +1126,92 @@ public abstract class FlatLaf FlatLaf.systemColorGetter = systemColorGetter; } + /** + * Returns UI key prefix, used in FlatLaf properties files, for light or dark themes. + * Return value is either {@code [light]} or {@code [dark]}. + * + * @since 3.6 + */ + public static String getUIKeyLightOrDarkPrefix( boolean dark ) { + return dark ? "[dark]" : "[light]"; + } + + /** + * Returns set of UI key prefixes, used in FlatLaf properties files, for current platform. + * If UI keys in properties files start with a prefix (e.g. {@code [someprefix]Button.background}), + * then they are only used if that prefix is contained in this set + * (or is one of {@code [light]} or {@code [dark]} depending on current theme). + *

+ * By default, the set contains one or more of following prefixes: + *

    + *
  • {@code [win]} on Windows + *
  • {@code [mac]} on macOS + *
  • {@code [linux]} on Linux + *
  • {@code [unknown]} on other platforms + *
  • {@code [gnome]} on Linux with GNOME desktop environment + *
  • {@code [kde]} on Linux with KDE desktop environment + *
  • on Linux, the value of the environment variable {@code XDG_CURRENT_DESKTOP}, + * split at colons and converted to lower case (e.g. if value of {@code XDG_CURRENT_DESKTOP} + * is {@code ubuntu:GNOME}, then {@code [ubuntu]} and {@code [gnome]}) + *
+ *

+ * You can add own prefixes to the set. + * The prefixes must start with '[' and end with ']' characters, otherwise they will be ignored. + * + * @since 3.6 + */ + public static Set getUIKeyPlatformPrefixes() { + if( uiKeyPlatformPrefixes == null ) { + uiKeyPlatformPrefixes = new HashSet<>(); + uiKeyPlatformPrefixes.add( + SystemInfo.isWindows ? "[win]" : + SystemInfo.isMacOS ? "[mac]" : + SystemInfo.isLinux ? "[linux]" : "[unknown]" ); + + // Linux + if( SystemInfo.isLinux ) { + if( SystemInfo.isGNOME ) + uiKeyPlatformPrefixes.add( "[gnome]" ); + else if( SystemInfo.isKDE ) + uiKeyPlatformPrefixes.add( "[kde]" ); + + // add values from XDG_CURRENT_DESKTOP for other desktops + String desktop = System.getenv( "XDG_CURRENT_DESKTOP" ); + if( desktop != null ) { + // XDG_CURRENT_DESKTOP is a colon-separated list of strings + // https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html#key-onlyshowin + // e.g. "ubuntu:GNOME" on Ubuntu 24.10 or "GNOME-Classic:GNOME" on CentOS 7 + for( String desk : StringUtils.split( desktop.toLowerCase( Locale.ENGLISH ), ':', true, true ) ) + uiKeyPlatformPrefixes.add( '[' + desk + ']' ); + } + } + } + return uiKeyPlatformPrefixes; + } + + /** + * Returns set of special UI key prefixes, used in FlatLaf properties files. + * Unlike other prefixes, properties with special prefixes are preserved. + * You can access them using `UIManager`. E.g. `UIManager.get( "[someSpecialPrefix]someKey" )`. + *

+ * By default, the set contains following special prefixes: + *

    + *
  • {@code [style]} + *
+ *

+ * You can add own prefixes to the set. + * The prefixes must start with '[' and end with ']' characters, otherwise they will be ignored. + * + * @since 3.6 + */ + public static Set getUIKeySpecialPrefixes() { + if( uiKeySpecialPrefixes == null ) { + uiKeySpecialPrefixes = new HashSet<>(); + uiKeySpecialPrefixes.add( "[style]" ); + } + return uiKeySpecialPrefixes; + } + private static void reSetLookAndFeel() { EventQueue.invokeLater( () -> { LookAndFeel lookAndFeel = UIManager.getLookAndFeel(); 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 6ab832cc..81a58196 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java @@ -41,6 +41,7 @@ import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; +import java.util.Set; import java.util.function.Consumer; import java.util.function.Function; import javax.swing.Icon; @@ -62,7 +63,6 @@ import com.formdev.flatlaf.util.HSLColor; import com.formdev.flatlaf.util.LoggingFacade; import com.formdev.flatlaf.util.SoftCache; import com.formdev.flatlaf.util.StringUtils; -import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.UIScale; /** @@ -105,6 +105,39 @@ class UIDefaultsLoader return lafClasses; } + static Properties newUIProperties( boolean dark ) { + // UI key prefixes + String lightOrDarkPrefix = FlatLaf.getUIKeyLightOrDarkPrefix( dark ); + Set platformPrefixes = FlatLaf.getUIKeyPlatformPrefixes(); + Set specialPrefixes = FlatLaf.getUIKeySpecialPrefixes(); + + return new Properties() { + @Override + public synchronized Object put( Object k, Object value ) { + // process key prefixes (while loading properties files) + String key = (String) k; + while( key.startsWith( "[" ) ) { + int closeIndex = key.indexOf( ']' ); + if( closeIndex < 0 ) + return null; // ignore property with invalid prefix + + String prefix = key.substring( 0, closeIndex + 1 ); + + if( specialPrefixes.contains( prefix ) ) + break; // keep special prefix + + if( !lightOrDarkPrefix.equals( prefix ) && !platformPrefixes.contains( prefix ) ) + return null; // ignore property + + // prefix is known and enabled --> remove prefix + key = key.substring( closeIndex + 1 ); + } + + return super.put( key, value ); + } + }; + } + static void loadDefaultsFromProperties( List> lafClasses, List addons, Consumer intellijThemesHook, Properties additionalDefaults, boolean dark, UIDefaults defaults ) { @@ -113,8 +146,10 @@ class UIDefaultsLoader // which avoids that system color getter is invoked multiple times systemColorCache = (FlatLaf.getSystemColorGetter() != null) ? new HashMap<>() : null; + // all properties files will be loaded into this map + Properties properties = newUIProperties( dark ); + // load core properties files - Properties properties = new Properties(); for( Class lafClass : lafClasses ) { String propertiesName = '/' + lafClass.getName().replace( '.', '/' ) + ".properties"; try( InputStream in = lafClass.getResourceAsStream( propertiesName ) ) { @@ -201,41 +236,6 @@ class UIDefaultsLoader if( additionalDefaults != null ) properties.putAll( additionalDefaults ); - // collect all platform specific keys (but do not modify properties) - ArrayList platformSpecificKeys = new ArrayList<>(); - for( Object okey : properties.keySet() ) { - String key = (String) okey; - if( key.startsWith( "[" ) && - (key.startsWith( "[win]" ) || - key.startsWith( "[mac]" ) || - key.startsWith( "[linux]" ) || - key.startsWith( "[light]" ) || - key.startsWith( "[dark]" )) ) - platformSpecificKeys.add( key ); - } - - // remove platform specific properties and re-add only properties - // for current platform, but with platform prefix removed - if( !platformSpecificKeys.isEmpty() ) { - // handle light/dark specific properties - String lightOrDarkPrefix = dark ? "[dark]" : "[light]"; - for( String key : platformSpecificKeys ) { - if( key.startsWith( lightOrDarkPrefix ) ) - properties.put( key.substring( lightOrDarkPrefix.length() ), properties.remove( key ) ); - } - - // handle platform specific properties - String platformPrefix = - SystemInfo.isWindows ? "[win]" : - SystemInfo.isMacOS ? "[mac]" : - SystemInfo.isLinux ? "[linux]" : "[unknown]"; - for( String key : platformSpecificKeys ) { - Object value = properties.remove( key ); - if( key.startsWith( platformPrefix ) ) - properties.put( key.substring( platformPrefix.length() ), value ); - } - } - // get (and remove) wildcard replacements, which override all other defaults that end with same suffix HashMap wildcards = new HashMap<>(); Iterator> it = properties.entrySet().iterator(); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStylingSupport.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStylingSupport.java index e8c8bff8..ebb35271 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStylingSupport.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatStylingSupport.java @@ -42,7 +42,6 @@ import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.StringUtils; -import com.formdev.flatlaf.util.SystemInfo; /** * Support for styling components in CSS syntax. @@ -325,22 +324,24 @@ public class FlatStylingSupport return null; Map oldValues = new HashMap<>(); + outer: for( Map.Entry e : style.entrySet() ) { String key = e.getKey(); Object newValue = e.getValue(); // handle key prefix - if( key.startsWith( "[" ) ) { - if( (SystemInfo.isWindows && key.startsWith( "[win]" )) || - (SystemInfo.isMacOS && key.startsWith( "[mac]" )) || - (SystemInfo.isLinux && key.startsWith( "[linux]" )) || - (key.startsWith( "[light]" ) && !FlatLaf.isLafDark()) || - (key.startsWith( "[dark]" ) && FlatLaf.isLafDark()) ) - { - // prefix is known and enabled --> remove prefix - key = key.substring( key.indexOf( ']' ) + 1 ); - } else - continue; + while( key.startsWith( "[" ) ) { + int closeIndex = key.indexOf( ']' ); + if( closeIndex < 0 ) + continue outer; + + String prefix = key.substring( 0, closeIndex + 1 ); + String lightOrDarkPrefix = FlatLaf.getUIKeyLightOrDarkPrefix( FlatLaf.isLafDark() ); + if( !lightOrDarkPrefix.equals( prefix ) && !FlatLaf.getUIKeyPlatformPrefixes().contains( prefix ) ) + continue outer; + + // prefix is known and enabled --> remove prefix + key = key.substring( closeIndex + 1 ); } Object oldValue = applyProperty.apply( key, newValue ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemInfo.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemInfo.java index 81cf4b41..e60f177c 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemInfo.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/SystemInfo.java @@ -31,6 +31,7 @@ public class SystemInfo public static final boolean isWindows; public static final boolean isMacOS; public static final boolean isLinux; + /** @since 3.6 */ public static final boolean isUnknownOS; // OS versions public static final long osVersion; @@ -59,6 +60,7 @@ public class SystemInfo public static final boolean isJetBrainsJVM_11_orLater; // UI toolkits + /** @since 3.6 */ public static final boolean isGNOME; public static final boolean isKDE; // other @@ -75,6 +77,7 @@ public class SystemInfo isWindows = osName.startsWith( "windows" ); isMacOS = osName.startsWith( "mac" ); isLinux = osName.startsWith( "linux" ); + isUnknownOS = !isWindows && !isMacOS && !isLinux; // OS versions osVersion = scanVersion( System.getProperty( "os.version" ) ); @@ -104,7 +107,13 @@ public class SystemInfo isJetBrainsJVM_11_orLater = isJetBrainsJVM && isJava_11_orLater; // UI toolkits - isKDE = (isLinux && System.getenv( "KDE_FULL_SESSION" ) != null); + String desktop = isLinux ? System.getenv( "XDG_CURRENT_DESKTOP" ) : null; + isGNOME = (isLinux && + (System.getenv( "GNOME_DESKTOP_SESSION_ID" ) != null || + (desktop != null && desktop.contains( "GNOME" )))); + isKDE = (isLinux && + (System.getenv( "KDE_FULL_SESSION" ) != null || + (desktop != null && desktop.contains( "KDE" )))); // other isProjector = Boolean.getBoolean( "org.jetbrains.projector.server.enable" ); 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 db0f7d8b..9a9f3c90 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -50,6 +50,9 @@ mini.font = -3 #defaultFont = ... # font weights +# fallback for unknown platform +light.font = +0 +semibold.font = +0 # Windows [win]light.font = "Segoe UI Light" [win]semibold.font = "Segoe UI Semibold" @@ -59,15 +62,12 @@ mini.font = -3 # Linux [linux]light.font = "Lato Light", "Ubuntu Light", "Cantarell Light" [linux]semibold.font = "Lato Semibold", "Ubuntu Medium", "Montserrat SemiBold" -# fallback for unknown platform -light.font = +0 -semibold.font = +0 # monospaced +monospaced.font = Monospaced [win]monospaced.font = Monospaced [mac]monospaced.font = Menlo, Monospaced [linux]monospaced.font = "Liberation Mono", "Ubuntu Mono", Monospaced -monospaced.font = Monospaced # styles [style].h00 = font: $h00.font diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/IntelliJTheme$ThemeLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/IntelliJTheme$ThemeLaf.properties index d10d034f..77b2aef3 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/IntelliJTheme$ThemeLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/IntelliJTheme$ThemeLaf.properties @@ -95,8 +95,8 @@ Spinner.buttonDisabledArrowColor = $ComboBox.buttonDisabledArrowColor #---- TabbedPane ---- # colors from JBUI.CurrentTheme.DefaultTabs.inactiveUnderlineColor() -[light]TabbedPane.inactiveUnderlineColor = #9ca7b8 -[dark]TabbedPane.inactiveUnderlineColor = #747a80 +{*-light}TabbedPane.inactiveUnderlineColor = #9ca7b8 +{*-dark}TabbedPane.inactiveUnderlineColor = #747a80 #---- ToggleButton ---- diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/UIDefaultsLoaderAccessor.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/UIDefaultsLoaderAccessor.java index a1093b39..209b99c5 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/UIDefaultsLoaderAccessor.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/UIDefaultsLoaderAccessor.java @@ -17,6 +17,7 @@ package com.formdev.flatlaf; import java.util.Collections; +import java.util.Properties; import java.util.function.Function; import com.formdev.flatlaf.UIDefaultsLoader.ValueType; @@ -72,4 +73,8 @@ public class UIDefaultsLoaderAccessor { return UIDefaultsLoader.parseColorRGBA( value ); } + + public static Properties newUIProperties( boolean dark ) { + return UIDefaultsLoader.newUIProperties( dark ); + } } diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatCompletionProvider.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatCompletionProvider.java index 164e8a89..0bb400fb 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatCompletionProvider.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatCompletionProvider.java @@ -41,6 +41,7 @@ import org.fife.ui.autocomplete.ParameterChoicesProvider; import org.fife.ui.autocomplete.ParameterizedCompletion; import org.fife.ui.autocomplete.ParameterizedCompletion.Parameter; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import com.formdev.flatlaf.FlatLaf; /** * @author Karl Tauber @@ -358,12 +359,18 @@ class FlatCompletionProvider lastKeys = keys; completions.clear(); + outer: for( String key : keys ) { - if( key.startsWith( "[" ) ) { + while( key.startsWith( "[" ) ) { // remove prefix int closeIndex = key.indexOf( ']' ); if( closeIndex < 0 ) - continue; + continue outer; + + String prefix = key.substring( 0, closeIndex + 1 ); + if( FlatLaf.getUIKeySpecialPrefixes().contains( prefix ) ) + continue outer; // can not reference properties with special prefix + key = key.substring( closeIndex + 1 ); } diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePropertiesBaseManager.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePropertiesBaseManager.java index f53faee1..ad2e0cfd 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePropertiesBaseManager.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePropertiesBaseManager.java @@ -76,14 +76,21 @@ class FlatThemePropertiesBaseManager definedCoreKeys = new HashSet<>(); for( Properties properties : coreThemes.values() ) { + outer: for( Object k : properties.keySet() ) { String key = (String) k; if( key.startsWith( "*." ) || key.startsWith( "@" ) ) continue; - if( key.startsWith( "[" ) ) { + + while( key.startsWith( "[" ) ) { int closeIndex = key.indexOf( ']' ); if( closeIndex < 0 ) - continue; + continue outer; + + String prefix = key.substring( 0, closeIndex + 1 ); + if( FlatLaf.getUIKeySpecialPrefixes().contains( prefix ) ) + break; // keep special prefix + key = key.substring( closeIndex + 1 ); } definedCoreKeys.add( key ); diff --git a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePropertiesSupport.java b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePropertiesSupport.java index 0f28c256..0ce5345b 100644 --- a/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePropertiesSupport.java +++ b/flatlaf-theme-editor/src/main/java/com/formdev/flatlaf/themeeditor/FlatThemePropertiesSupport.java @@ -33,7 +33,6 @@ import javax.swing.event.DocumentListener; import javax.swing.plaf.basic.BasicLookAndFeel; import javax.swing.text.BadLocationException; import com.formdev.flatlaf.UIDefaultsLoaderAccessor; -import com.formdev.flatlaf.util.SystemInfo; /** * Supports parsing content of text area in FlatLaf properties syntax. @@ -54,17 +53,13 @@ class FlatThemePropertiesSupport private final Map parsedValueCache2 = new HashMap<>(); private Set allKeysCache; private String baseTheme; + private boolean lastDark; private static long globalCacheInvalidationCounter; private long cacheInvalidationCounter; private static Set wildcardKeys; - private static final String platformPrefix = - SystemInfo.isWindows ? "[win]" : - SystemInfo.isMacOS ? "[mac]" : - SystemInfo.isLinux ? "[linux]" : "[unknown]"; - FlatThemePropertiesSupport( FlatSyntaxTextArea textArea ) { this.textArea = textArea; @@ -115,6 +110,7 @@ class FlatThemePropertiesSupport private KeyValue getKeyValueAtLine( int line ) { try { + // get text at line int startOffset = textArea.getLineStartOffset( line ); int endOffset = textArea.getLineEndOffset( line ); String text = textArea.getText( startOffset, endOffset - startOffset ); @@ -134,11 +130,13 @@ class FlatThemePropertiesSupport text = text.substring( sepIndex + 1 ); } + // parse line Properties properties = new Properties(); properties.load( new StringReader( text ) ); if( properties.isEmpty() ) return null; + // get key and value for line String key = (String) properties.keys().nextElement(); String value = properties.getProperty( key ); return new KeyValue( key, value ); @@ -171,17 +169,7 @@ class FlatThemePropertiesSupport } private String getPropertyOrWildcard( String key ) { - // get platform specific properties - String value = getProperty( platformPrefix + key ); - if( value != null ) - return value; - - // get light/dark specific properties - value = getProperty( (isDark( getBaseTheme() ) ? "[dark]" : "[light]") + key ); - if( value != null ) - return value; - - value = getProperty( key ); + String value = getProperty( key ); if( value != null ) return value; @@ -213,9 +201,18 @@ class FlatThemePropertiesSupport if( propertiesCache != null ) return propertiesCache; - propertiesCache = new Properties(); + String text = textArea.getText(); try { - propertiesCache.load( new StringReader( textArea.getText() ) ); + propertiesCache = UIDefaultsLoaderAccessor.newUIProperties( lastDark ); + propertiesCache.load( new StringReader( text ) ); + + // re-load if dark has changed (getBaseTheme() invokes getProperties()!!!) + boolean dark = isDark( getBaseTheme() ); + if( lastDark != dark ) { + lastDark = dark; + propertiesCache = UIDefaultsLoaderAccessor.newUIProperties( lastDark ); + propertiesCache.load( new StringReader( text ) ); + } } catch( IOException ex ) { ex.printStackTrace(); //TODO }