- support key prefixes for Linux desktop environments (issue #974)

- support custom key prefixes (issue #649)
- support multi-prefixed keys
- changed handling of prefixed keys
This commit is contained in:
Karl Tauber
2025-03-08 18:11:38 +01:00
parent babc8aa55d
commit f7495a0a5b
11 changed files with 218 additions and 79 deletions

View File

@@ -31,6 +31,12 @@ FlatLaf Change Log
- Updated to latest versions and fixed various issues. - Updated to latest versions and fixed various issues.
- Support customizing through properties files. (issue #824) - Support customizing through properties files. (issue #824)
- SwingX: Support `JXTipOfTheDay` component. (issue #980) - 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 #### Fixed bugs
@@ -66,6 +72,23 @@ FlatLaf Change Log
`com.formdev.flatlaf.intellijthemes.materialthemeuilite` from `Flat<theme>` `com.formdev.flatlaf.intellijthemes.materialthemeuilite` from `Flat<theme>`
to `FlatMT<theme>`. to `FlatMT<theme>`.
- Removed `Gruvbox Dark Medium` and `Gruvbox Dark Soft` themes. - 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 ## 3.5.4

View File

@@ -37,6 +37,7 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@@ -44,6 +45,7 @@ import java.util.MissingResourceException;
import java.util.Properties; import java.util.Properties;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.ServiceLoader; import java.util.ServiceLoader;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.IntUnaryOperator; import java.util.function.IntUnaryOperator;
@@ -100,6 +102,8 @@ public abstract class FlatLaf
private static Map<String, String> globalExtraDefaults; private static Map<String, String> globalExtraDefaults;
private Map<String, String> extraDefaults; private Map<String, String> extraDefaults;
private static Function<String, Color> systemColorGetter; private static Function<String, Color> systemColorGetter;
private static Set<String> uiKeyPlatformPrefixes;
private static Set<String> uiKeySpecialPrefixes;
private String desktopPropertyName; private String desktopPropertyName;
private String desktopPropertyName2; private String desktopPropertyName2;
@@ -1122,6 +1126,92 @@ public abstract class FlatLaf
FlatLaf.systemColorGetter = systemColorGetter; 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).
* <p>
* By default, the set contains one or more of following prefixes:
* <ul>
* <li>{@code [win]} on Windows
* <li>{@code [mac]} on macOS
* <li>{@code [linux]} on Linux
* <li>{@code [unknown]} on other platforms
* <li>{@code [gnome]} on Linux with GNOME desktop environment
* <li>{@code [kde]} on Linux with KDE desktop environment
* <li>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]})
* </ul>
* <p>
* 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<String> 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" )`.
* <p>
* By default, the set contains following special prefixes:
* <ul>
* <li>{@code [style]}
* </ul>
* <p>
* 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<String> getUIKeySpecialPrefixes() {
if( uiKeySpecialPrefixes == null ) {
uiKeySpecialPrefixes = new HashSet<>();
uiKeySpecialPrefixes.add( "[style]" );
}
return uiKeySpecialPrefixes;
}
private static void reSetLookAndFeel() { private static void reSetLookAndFeel() {
EventQueue.invokeLater( () -> { EventQueue.invokeLater( () -> {
LookAndFeel lookAndFeel = UIManager.getLookAndFeel(); LookAndFeel lookAndFeel = UIManager.getLookAndFeel();

View File

@@ -41,6 +41,7 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Properties; import java.util.Properties;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import javax.swing.Icon; 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.LoggingFacade;
import com.formdev.flatlaf.util.SoftCache; import com.formdev.flatlaf.util.SoftCache;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
/** /**
@@ -105,6 +105,39 @@ class UIDefaultsLoader
return lafClasses; return lafClasses;
} }
static Properties newUIProperties( boolean dark ) {
// UI key prefixes
String lightOrDarkPrefix = FlatLaf.getUIKeyLightOrDarkPrefix( dark );
Set<String> platformPrefixes = FlatLaf.getUIKeyPlatformPrefixes();
Set<String> 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<Class<?>> lafClasses, List<FlatDefaultsAddon> addons, static void loadDefaultsFromProperties( List<Class<?>> lafClasses, List<FlatDefaultsAddon> addons,
Consumer<Properties> intellijThemesHook, Properties additionalDefaults, boolean dark, UIDefaults defaults ) Consumer<Properties> intellijThemesHook, Properties additionalDefaults, boolean dark, UIDefaults defaults )
{ {
@@ -113,8 +146,10 @@ class UIDefaultsLoader
// which avoids that system color getter is invoked multiple times // which avoids that system color getter is invoked multiple times
systemColorCache = (FlatLaf.getSystemColorGetter() != null) ? new HashMap<>() : null; systemColorCache = (FlatLaf.getSystemColorGetter() != null) ? new HashMap<>() : null;
// all properties files will be loaded into this map
Properties properties = newUIProperties( dark );
// load core properties files // load core properties files
Properties properties = new Properties();
for( Class<?> lafClass : lafClasses ) { for( Class<?> lafClass : lafClasses ) {
String propertiesName = '/' + lafClass.getName().replace( '.', '/' ) + ".properties"; String propertiesName = '/' + lafClass.getName().replace( '.', '/' ) + ".properties";
try( InputStream in = lafClass.getResourceAsStream( propertiesName ) ) { try( InputStream in = lafClass.getResourceAsStream( propertiesName ) ) {
@@ -201,41 +236,6 @@ class UIDefaultsLoader
if( additionalDefaults != null ) if( additionalDefaults != null )
properties.putAll( additionalDefaults ); properties.putAll( additionalDefaults );
// collect all platform specific keys (but do not modify properties)
ArrayList<String> 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 // get (and remove) wildcard replacements, which override all other defaults that end with same suffix
HashMap<String, String> wildcards = new HashMap<>(); HashMap<String, String> wildcards = new HashMap<>();
Iterator<Entry<Object, Object>> it = properties.entrySet().iterator(); Iterator<Entry<Object, Object>> it = properties.entrySet().iterator();

View File

@@ -42,7 +42,6 @@ import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.HiDPIUtils; import com.formdev.flatlaf.util.HiDPIUtils;
import com.formdev.flatlaf.util.StringUtils; import com.formdev.flatlaf.util.StringUtils;
import com.formdev.flatlaf.util.SystemInfo;
/** /**
* Support for styling components in CSS syntax. * Support for styling components in CSS syntax.
@@ -325,22 +324,24 @@ public class FlatStylingSupport
return null; return null;
Map<String, Object> oldValues = new HashMap<>(); Map<String, Object> oldValues = new HashMap<>();
outer:
for( Map.Entry<String, Object> e : style.entrySet() ) { for( Map.Entry<String, Object> e : style.entrySet() ) {
String key = e.getKey(); String key = e.getKey();
Object newValue = e.getValue(); Object newValue = e.getValue();
// handle key prefix // handle key prefix
if( key.startsWith( "[" ) ) { while( key.startsWith( "[" ) ) {
if( (SystemInfo.isWindows && key.startsWith( "[win]" )) || int closeIndex = key.indexOf( ']' );
(SystemInfo.isMacOS && key.startsWith( "[mac]" )) || if( closeIndex < 0 )
(SystemInfo.isLinux && key.startsWith( "[linux]" )) || continue outer;
(key.startsWith( "[light]" ) && !FlatLaf.isLafDark()) ||
(key.startsWith( "[dark]" ) && FlatLaf.isLafDark()) ) String prefix = key.substring( 0, closeIndex + 1 );
{ String lightOrDarkPrefix = FlatLaf.getUIKeyLightOrDarkPrefix( FlatLaf.isLafDark() );
// prefix is known and enabled --> remove prefix if( !lightOrDarkPrefix.equals( prefix ) && !FlatLaf.getUIKeyPlatformPrefixes().contains( prefix ) )
key = key.substring( key.indexOf( ']' ) + 1 ); continue outer;
} else
continue; // prefix is known and enabled --> remove prefix
key = key.substring( closeIndex + 1 );
} }
Object oldValue = applyProperty.apply( key, newValue ); Object oldValue = applyProperty.apply( key, newValue );

View File

@@ -31,6 +31,7 @@ public class SystemInfo
public static final boolean isWindows; public static final boolean isWindows;
public static final boolean isMacOS; public static final boolean isMacOS;
public static final boolean isLinux; public static final boolean isLinux;
/** @since 3.6 */ public static final boolean isUnknownOS;
// OS versions // OS versions
public static final long osVersion; public static final long osVersion;
@@ -59,6 +60,7 @@ public class SystemInfo
public static final boolean isJetBrainsJVM_11_orLater; public static final boolean isJetBrainsJVM_11_orLater;
// UI toolkits // UI toolkits
/** @since 3.6 */ public static final boolean isGNOME;
public static final boolean isKDE; public static final boolean isKDE;
// other // other
@@ -75,6 +77,7 @@ public class SystemInfo
isWindows = osName.startsWith( "windows" ); isWindows = osName.startsWith( "windows" );
isMacOS = osName.startsWith( "mac" ); isMacOS = osName.startsWith( "mac" );
isLinux = osName.startsWith( "linux" ); isLinux = osName.startsWith( "linux" );
isUnknownOS = !isWindows && !isMacOS && !isLinux;
// OS versions // OS versions
osVersion = scanVersion( System.getProperty( "os.version" ) ); osVersion = scanVersion( System.getProperty( "os.version" ) );
@@ -104,7 +107,13 @@ public class SystemInfo
isJetBrainsJVM_11_orLater = isJetBrainsJVM && isJava_11_orLater; isJetBrainsJVM_11_orLater = isJetBrainsJVM && isJava_11_orLater;
// UI toolkits // 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 // other
isProjector = Boolean.getBoolean( "org.jetbrains.projector.server.enable" ); isProjector = Boolean.getBoolean( "org.jetbrains.projector.server.enable" );

View File

@@ -50,6 +50,9 @@ mini.font = -3
#defaultFont = ... #defaultFont = ...
# font weights # font weights
# fallback for unknown platform
light.font = +0
semibold.font = +0
# Windows # Windows
[win]light.font = "Segoe UI Light" [win]light.font = "Segoe UI Light"
[win]semibold.font = "Segoe UI Semibold" [win]semibold.font = "Segoe UI Semibold"
@@ -59,15 +62,12 @@ mini.font = -3
# Linux # Linux
[linux]light.font = "Lato Light", "Ubuntu Light", "Cantarell Light" [linux]light.font = "Lato Light", "Ubuntu Light", "Cantarell Light"
[linux]semibold.font = "Lato Semibold", "Ubuntu Medium", "Montserrat SemiBold" [linux]semibold.font = "Lato Semibold", "Ubuntu Medium", "Montserrat SemiBold"
# fallback for unknown platform
light.font = +0
semibold.font = +0
# monospaced # monospaced
monospaced.font = Monospaced
[win]monospaced.font = Monospaced [win]monospaced.font = Monospaced
[mac]monospaced.font = Menlo, Monospaced [mac]monospaced.font = Menlo, Monospaced
[linux]monospaced.font = "Liberation Mono", "Ubuntu Mono", Monospaced [linux]monospaced.font = "Liberation Mono", "Ubuntu Mono", Monospaced
monospaced.font = Monospaced
# styles # styles
[style].h00 = font: $h00.font [style].h00 = font: $h00.font

View File

@@ -95,8 +95,8 @@ Spinner.buttonDisabledArrowColor = $ComboBox.buttonDisabledArrowColor
#---- TabbedPane ---- #---- TabbedPane ----
# colors from JBUI.CurrentTheme.DefaultTabs.inactiveUnderlineColor() # colors from JBUI.CurrentTheme.DefaultTabs.inactiveUnderlineColor()
[light]TabbedPane.inactiveUnderlineColor = #9ca7b8 {*-light}TabbedPane.inactiveUnderlineColor = #9ca7b8
[dark]TabbedPane.inactiveUnderlineColor = #747a80 {*-dark}TabbedPane.inactiveUnderlineColor = #747a80
#---- ToggleButton ---- #---- ToggleButton ----

View File

@@ -17,6 +17,7 @@
package com.formdev.flatlaf; package com.formdev.flatlaf;
import java.util.Collections; import java.util.Collections;
import java.util.Properties;
import java.util.function.Function; import java.util.function.Function;
import com.formdev.flatlaf.UIDefaultsLoader.ValueType; import com.formdev.flatlaf.UIDefaultsLoader.ValueType;
@@ -72,4 +73,8 @@ public class UIDefaultsLoaderAccessor
{ {
return UIDefaultsLoader.parseColorRGBA( value ); return UIDefaultsLoader.parseColorRGBA( value );
} }
public static Properties newUIProperties( boolean dark ) {
return UIDefaultsLoader.newUIProperties( dark );
}
} }

View File

@@ -41,6 +41,7 @@ import org.fife.ui.autocomplete.ParameterChoicesProvider;
import org.fife.ui.autocomplete.ParameterizedCompletion; import org.fife.ui.autocomplete.ParameterizedCompletion;
import org.fife.ui.autocomplete.ParameterizedCompletion.Parameter; import org.fife.ui.autocomplete.ParameterizedCompletion.Parameter;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import com.formdev.flatlaf.FlatLaf;
/** /**
* @author Karl Tauber * @author Karl Tauber
@@ -358,12 +359,18 @@ class FlatCompletionProvider
lastKeys = keys; lastKeys = keys;
completions.clear(); completions.clear();
outer:
for( String key : keys ) { for( String key : keys ) {
if( key.startsWith( "[" ) ) { while( key.startsWith( "[" ) ) {
// remove prefix // remove prefix
int closeIndex = key.indexOf( ']' ); int closeIndex = key.indexOf( ']' );
if( closeIndex < 0 ) 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 ); key = key.substring( closeIndex + 1 );
} }

View File

@@ -76,14 +76,21 @@ class FlatThemePropertiesBaseManager
definedCoreKeys = new HashSet<>(); definedCoreKeys = new HashSet<>();
for( Properties properties : coreThemes.values() ) { for( Properties properties : coreThemes.values() ) {
outer:
for( Object k : properties.keySet() ) { for( Object k : properties.keySet() ) {
String key = (String) k; String key = (String) k;
if( key.startsWith( "*." ) || key.startsWith( "@" ) ) if( key.startsWith( "*." ) || key.startsWith( "@" ) )
continue; continue;
if( key.startsWith( "[" ) ) {
while( key.startsWith( "[" ) ) {
int closeIndex = key.indexOf( ']' ); int closeIndex = key.indexOf( ']' );
if( closeIndex < 0 ) 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 ); key = key.substring( closeIndex + 1 );
} }
definedCoreKeys.add( key ); definedCoreKeys.add( key );

View File

@@ -33,7 +33,6 @@ import javax.swing.event.DocumentListener;
import javax.swing.plaf.basic.BasicLookAndFeel; import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.text.BadLocationException; import javax.swing.text.BadLocationException;
import com.formdev.flatlaf.UIDefaultsLoaderAccessor; import com.formdev.flatlaf.UIDefaultsLoaderAccessor;
import com.formdev.flatlaf.util.SystemInfo;
/** /**
* Supports parsing content of text area in FlatLaf properties syntax. * Supports parsing content of text area in FlatLaf properties syntax.
@@ -54,17 +53,13 @@ class FlatThemePropertiesSupport
private final Map<String, Object> parsedValueCache2 = new HashMap<>(); private final Map<String, Object> parsedValueCache2 = new HashMap<>();
private Set<String> allKeysCache; private Set<String> allKeysCache;
private String baseTheme; private String baseTheme;
private boolean lastDark;
private static long globalCacheInvalidationCounter; private static long globalCacheInvalidationCounter;
private long cacheInvalidationCounter; private long cacheInvalidationCounter;
private static Set<String> wildcardKeys; private static Set<String> wildcardKeys;
private static final String platformPrefix =
SystemInfo.isWindows ? "[win]" :
SystemInfo.isMacOS ? "[mac]" :
SystemInfo.isLinux ? "[linux]" : "[unknown]";
FlatThemePropertiesSupport( FlatSyntaxTextArea textArea ) { FlatThemePropertiesSupport( FlatSyntaxTextArea textArea ) {
this.textArea = textArea; this.textArea = textArea;
@@ -115,6 +110,7 @@ class FlatThemePropertiesSupport
private KeyValue getKeyValueAtLine( int line ) { private KeyValue getKeyValueAtLine( int line ) {
try { try {
// get text at line
int startOffset = textArea.getLineStartOffset( line ); int startOffset = textArea.getLineStartOffset( line );
int endOffset = textArea.getLineEndOffset( line ); int endOffset = textArea.getLineEndOffset( line );
String text = textArea.getText( startOffset, endOffset - startOffset ); String text = textArea.getText( startOffset, endOffset - startOffset );
@@ -134,11 +130,13 @@ class FlatThemePropertiesSupport
text = text.substring( sepIndex + 1 ); text = text.substring( sepIndex + 1 );
} }
// parse line
Properties properties = new Properties(); Properties properties = new Properties();
properties.load( new StringReader( text ) ); properties.load( new StringReader( text ) );
if( properties.isEmpty() ) if( properties.isEmpty() )
return null; return null;
// get key and value for line
String key = (String) properties.keys().nextElement(); String key = (String) properties.keys().nextElement();
String value = properties.getProperty( key ); String value = properties.getProperty( key );
return new KeyValue( key, value ); return new KeyValue( key, value );
@@ -171,17 +169,7 @@ class FlatThemePropertiesSupport
} }
private String getPropertyOrWildcard( String key ) { private String getPropertyOrWildcard( String key ) {
// get platform specific properties String value = getProperty( key );
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 );
if( value != null ) if( value != null )
return value; return value;
@@ -213,9 +201,18 @@ class FlatThemePropertiesSupport
if( propertiesCache != null ) if( propertiesCache != null )
return propertiesCache; return propertiesCache;
propertiesCache = new Properties(); String text = textArea.getText();
try { 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 ) { } catch( IOException ex ) {
ex.printStackTrace(); //TODO ex.printStackTrace(); //TODO
} }