mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-13 23:37:13 -06:00
Theme Editor: re-implemented support loading/resolving base properties from other editors in opened directory
This commit is contained in:
@@ -23,7 +23,6 @@ import java.awt.Window;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.List;
|
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.InputMap;
|
import javax.swing.InputMap;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
@@ -49,6 +48,7 @@ import org.fife.ui.rsyntaxtextarea.TokenTypes;
|
|||||||
import org.fife.ui.rtextarea.Gutter;
|
import org.fife.ui.rtextarea.Gutter;
|
||||||
import org.fife.ui.rtextarea.RTextArea;
|
import org.fife.ui.rtextarea.RTextArea;
|
||||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||||
|
import com.formdev.flatlaf.util.StringUtils;
|
||||||
import com.formdev.flatlaf.util.UIScale;
|
import com.formdev.flatlaf.util.UIScale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,8 +168,9 @@ class FlatThemeEditorPane
|
|||||||
return textArea.requestFocusInWindow();
|
return textArea.requestFocusInWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBaseFiles( List<File> baseFiles ) {
|
void initBasePropertyProvider( FlatThemePropertiesBaseManager propertiesBaseManager ) {
|
||||||
textArea.propertiesSupport.setBaseFiles( baseFiles );
|
String name = StringUtils.removeTrailing( file.getName(), ".properties" );
|
||||||
|
textArea.propertiesSupport.setBasePropertyProvider( propertiesBaseManager.create( name, textArea.propertiesSupport ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
File getFile() {
|
File getFile() {
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ public class FlatThemeFileEditor
|
|||||||
private Preferences state;
|
private Preferences state;
|
||||||
private boolean inLoadDirectory;
|
private boolean inLoadDirectory;
|
||||||
|
|
||||||
|
private final FlatThemePropertiesBaseManager propertiesBaseManager = new FlatThemePropertiesBaseManager();
|
||||||
|
|
||||||
public static void main( String[] args ) {
|
public static void main( String[] args ) {
|
||||||
File dir = (args.length > 0)
|
File dir = (args.length > 0)
|
||||||
? new File( args[0] )
|
? new File( args[0] )
|
||||||
@@ -187,6 +189,7 @@ public class FlatThemeFileEditor
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this.dir = dir;
|
this.dir = dir;
|
||||||
|
propertiesBaseManager.clear();
|
||||||
|
|
||||||
inLoadDirectory = true;
|
inLoadDirectory = true;
|
||||||
|
|
||||||
@@ -266,6 +269,8 @@ public class FlatThemeFileEditor
|
|||||||
ex.printStackTrace(); // TODO
|
ex.printStackTrace(); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
themeEditorPane.initBasePropertyProvider( propertiesBaseManager );
|
||||||
|
|
||||||
Supplier<String> titleFun = () -> {
|
Supplier<String> titleFun = () -> {
|
||||||
return (themeEditorPane.isDirty() ? "* " : "")
|
return (themeEditorPane.isDirty() ? "* " : "")
|
||||||
+ StringUtils.removeTrailing( themeEditorPane.getFile().getName(), ".properties" );
|
+ StringUtils.removeTrailing( themeEditorPane.getFile().getName(), ".properties" );
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2021 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.themeeditor;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Karl Tauber
|
||||||
|
*/
|
||||||
|
class FlatThemePropertiesBaseManager
|
||||||
|
{
|
||||||
|
private final Map<String, MyBasePropertyProvider> providers = new HashMap<>();
|
||||||
|
|
||||||
|
FlatThemePropertiesSupport.BasePropertyProvider create( String name, FlatThemePropertiesSupport propertiesSupport ) {
|
||||||
|
MyBasePropertyProvider provider = new MyBasePropertyProvider( name, propertiesSupport );
|
||||||
|
providers.put( name, provider );
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
providers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<String> baseFiles( String name, String baseTheme ) {
|
||||||
|
ArrayList<String> result = new ArrayList<>();
|
||||||
|
|
||||||
|
// core themes
|
||||||
|
switch( name ) {
|
||||||
|
case "FlatLaf":
|
||||||
|
result.add( "FlatLightLaf" );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "FlatLightLaf":
|
||||||
|
case "FlatDarkLaf":
|
||||||
|
result.add( "FlatLaf" );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "FlatIntelliJLaf":
|
||||||
|
result.add( "FlatLightLaf" );
|
||||||
|
result.add( "FlatLaf" );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "FlatDarculaLaf":
|
||||||
|
result.add( "FlatDarkLaf" );
|
||||||
|
result.add( "FlatLaf" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom themes based on core themes
|
||||||
|
if( result.isEmpty() ) {
|
||||||
|
if( baseTheme == null )
|
||||||
|
baseTheme = "light";
|
||||||
|
|
||||||
|
switch( baseTheme ) {
|
||||||
|
default:
|
||||||
|
case "light":
|
||||||
|
result.add( "FlatLightLaf" );
|
||||||
|
result.add( "FlatLaf" );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "dark":
|
||||||
|
result.add( "FlatDarkLaf" );
|
||||||
|
result.add( "FlatLaf" );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "intellij":
|
||||||
|
result.add( "FlatIntelliJLaf" );
|
||||||
|
result.add( "FlatLightLaf" );
|
||||||
|
result.add( "FlatLaf" );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "darcula":
|
||||||
|
result.add( "FlatDarculaLaf" );
|
||||||
|
result.add( "FlatLightLaf" );
|
||||||
|
result.add( "FlatLaf" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- class MyBasePropertyProvider ---------------------------------------
|
||||||
|
|
||||||
|
private class MyBasePropertyProvider
|
||||||
|
implements FlatThemePropertiesSupport.BasePropertyProvider
|
||||||
|
{
|
||||||
|
private final String name;
|
||||||
|
private final FlatThemePropertiesSupport propertiesSupport;
|
||||||
|
|
||||||
|
private List<String> baseFiles;
|
||||||
|
private String lastBaseTheme;
|
||||||
|
|
||||||
|
MyBasePropertyProvider( String name, FlatThemePropertiesSupport propertiesSupport ) {
|
||||||
|
this.name = name;
|
||||||
|
this.propertiesSupport = propertiesSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProperty( String key, String baseTheme ) {
|
||||||
|
updateBaseFiles( baseTheme );
|
||||||
|
|
||||||
|
for( String baseFile : baseFiles ) {
|
||||||
|
String value = getPropertyFromBase( baseFile, key );
|
||||||
|
if( value != null )
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPropertyFromBase( String baseFile, String key ) {
|
||||||
|
MyBasePropertyProvider provider = providers.get( baseFile );
|
||||||
|
return (provider != null)
|
||||||
|
? provider.propertiesSupport.getProperties().getProperty( key )
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBaseFiles( String baseTheme ) {
|
||||||
|
if( baseFiles != null && Objects.equals( baseTheme, lastBaseTheme ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
baseFiles = baseFiles( name, baseTheme );
|
||||||
|
lastBaseTheme = baseTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAllKeys( Set<String> allKeys, String baseTheme ) {
|
||||||
|
updateBaseFiles( baseTheme );
|
||||||
|
|
||||||
|
for( String baseFile : baseFiles ) {
|
||||||
|
MyBasePropertyProvider provider = providers.get( baseFile );
|
||||||
|
if( provider == null )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for( Object key : provider.propertiesSupport.getProperties().keySet() )
|
||||||
|
allKeys.add( (String) key );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,14 +17,10 @@
|
|||||||
package com.formdev.flatlaf.themeeditor;
|
package com.formdev.flatlaf.themeeditor;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -45,14 +41,16 @@ class FlatThemePropertiesSupport
|
|||||||
private final FlatSyntaxTextArea textArea;
|
private final FlatSyntaxTextArea textArea;
|
||||||
private final Function<String, String> propertiesGetter;
|
private final Function<String, String> propertiesGetter;
|
||||||
private final Function<String, String> resolver;
|
private final Function<String, String> resolver;
|
||||||
|
private BasePropertyProvider basePropertyProvider;
|
||||||
|
|
||||||
|
// caches
|
||||||
private Properties propertiesCache;
|
private Properties propertiesCache;
|
||||||
private final Map<Integer, Object> parsedValueCache = new HashMap<>();
|
private final Map<Integer, Object> parsedValueCache = new HashMap<>();
|
||||||
|
|
||||||
private File[] baseFiles;
|
|
||||||
private long[] baseFilesLastModified;
|
|
||||||
private Properties[] basePropertiesCache;
|
|
||||||
|
|
||||||
private Set<String> allKeysCache;
|
private Set<String> allKeysCache;
|
||||||
|
private String baseTheme;
|
||||||
|
|
||||||
|
private static long globalCacheInvalidationCounter;
|
||||||
|
private long cacheInvalidationCounter;
|
||||||
|
|
||||||
FlatThemePropertiesSupport( FlatSyntaxTextArea textArea ) {
|
FlatThemePropertiesSupport( FlatSyntaxTextArea textArea ) {
|
||||||
this.textArea = textArea;
|
this.textArea = textArea;
|
||||||
@@ -67,12 +65,8 @@ class FlatThemePropertiesSupport
|
|||||||
textArea.getDocument().addDocumentListener( this );
|
textArea.getDocument().addDocumentListener( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBaseFiles( List<File> baseFiles ) {
|
void setBasePropertyProvider( BasePropertyProvider basePropertyProvider ) {
|
||||||
int size = baseFiles.size();
|
this.basePropertyProvider = basePropertyProvider;
|
||||||
this.baseFiles = baseFiles.toArray( new File[size] );
|
|
||||||
|
|
||||||
baseFilesLastModified = new long[size];
|
|
||||||
basePropertiesCache = new Properties[size];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveValue( String value ) {
|
private String resolveValue( String value ) {
|
||||||
@@ -80,6 +74,8 @@ class FlatThemePropertiesSupport
|
|||||||
}
|
}
|
||||||
|
|
||||||
Object getParsedValueAtLine( int line ) {
|
Object getParsedValueAtLine( int line ) {
|
||||||
|
autoClearCache();
|
||||||
|
|
||||||
Integer lineKey = line;
|
Integer lineKey = line;
|
||||||
Object parsedValue = parsedValueCache.get( lineKey );
|
Object parsedValue = parsedValueCache.get( lineKey );
|
||||||
if( parsedValue != null )
|
if( parsedValue != null )
|
||||||
@@ -96,7 +92,7 @@ class FlatThemePropertiesSupport
|
|||||||
parsedValueCache.put( lineKey, parsedValue );
|
parsedValueCache.put( lineKey, parsedValue );
|
||||||
return parsedValue;
|
return parsedValue;
|
||||||
} catch( Exception ex ) {
|
} catch( Exception ex ) {
|
||||||
System.out.println( ex.getMessage() ); //TODO
|
System.out.println( textArea.getFileName() + ": " + ex.getMessage() ); //TODO
|
||||||
parsedValueCache.put( lineKey, ex );
|
parsedValueCache.put( lineKey, ex );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -128,20 +124,14 @@ class FlatThemePropertiesSupport
|
|||||||
if( value != null )
|
if( value != null )
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
if( baseFiles == null )
|
if( basePropertyProvider == null )
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// look in base properties files
|
// look in base properties files
|
||||||
for( int i = 0; i < baseFiles.length; i++ ) {
|
return basePropertyProvider.getProperty( key, getBaseTheme() );
|
||||||
value = getBaseProperties( i ).getProperty( key );
|
|
||||||
if( value != null )
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Properties getProperties() {
|
Properties getProperties() {
|
||||||
if( propertiesCache != null )
|
if( propertiesCache != null )
|
||||||
return propertiesCache;
|
return propertiesCache;
|
||||||
|
|
||||||
@@ -154,23 +144,9 @@ class FlatThemePropertiesSupport
|
|||||||
return propertiesCache;
|
return propertiesCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Properties getBaseProperties( int index ) {
|
|
||||||
long lastModified = baseFiles[index].lastModified();
|
|
||||||
if( baseFilesLastModified[index] != lastModified || basePropertiesCache[index] == null ) {
|
|
||||||
// (re)load base properties file
|
|
||||||
baseFilesLastModified[index] = lastModified;
|
|
||||||
basePropertiesCache[index] = new Properties();
|
|
||||||
try( InputStream in = new FileInputStream( baseFiles[index] ) ) {
|
|
||||||
basePropertiesCache[index].load( in );
|
|
||||||
} catch( IOException ex ) {
|
|
||||||
ex.printStackTrace(); //TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return basePropertiesCache[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> getAllKeys() {
|
Set<String> getAllKeys() {
|
||||||
|
autoClearCache();
|
||||||
|
|
||||||
if( allKeysCache != null )
|
if( allKeysCache != null )
|
||||||
return allKeysCache;
|
return allKeysCache;
|
||||||
|
|
||||||
@@ -179,21 +155,39 @@ class FlatThemePropertiesSupport
|
|||||||
for( Object key : getProperties().keySet() )
|
for( Object key : getProperties().keySet() )
|
||||||
allKeysCache.add( (String) key );
|
allKeysCache.add( (String) key );
|
||||||
|
|
||||||
if( baseFiles == null )
|
// look in base properties files
|
||||||
return allKeysCache;
|
if( basePropertyProvider != null )
|
||||||
|
basePropertyProvider.addAllKeys( allKeysCache, getBaseTheme() );
|
||||||
for( int i = 0; i < baseFiles.length; i++ ) {
|
|
||||||
for( Object key : getBaseProperties( i ).keySet() )
|
|
||||||
allKeysCache.add( (String) key );
|
|
||||||
}
|
|
||||||
|
|
||||||
return allKeysCache;
|
return allKeysCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getBaseTheme() {
|
||||||
|
if( baseTheme == null )
|
||||||
|
baseTheme = getProperties().getProperty( "@baseTheme", "light" );
|
||||||
|
return baseTheme;
|
||||||
|
}
|
||||||
|
|
||||||
private void clearCache() {
|
private void clearCache() {
|
||||||
propertiesCache = null;
|
propertiesCache = null;
|
||||||
parsedValueCache.clear();
|
parsedValueCache.clear();
|
||||||
allKeysCache = null;
|
allKeysCache = null;
|
||||||
|
baseTheme = null;
|
||||||
|
|
||||||
|
// increase global cache invalidation counter to allow auto-clear caches
|
||||||
|
globalCacheInvalidationCounter++;
|
||||||
|
cacheInvalidationCounter = globalCacheInvalidationCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear caches that may depend on other editors if cache of another editor was invalidated.
|
||||||
|
*/
|
||||||
|
private void autoClearCache() {
|
||||||
|
if( cacheInvalidationCounter == globalCacheInvalidationCounter )
|
||||||
|
return;
|
||||||
|
|
||||||
|
parsedValueCache.clear();
|
||||||
|
allKeysCache = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---- interface DocumentListener ----
|
//---- interface DocumentListener ----
|
||||||
@@ -233,4 +227,11 @@ class FlatThemePropertiesSupport
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- interface BasePropertyProvider -------------------------------------
|
||||||
|
|
||||||
|
interface BasePropertyProvider {
|
||||||
|
String getProperty( String key, String baseTheme );
|
||||||
|
void addAllKeys( Set<String> allKeys, String baseTheme );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user