Styling: support specifying multiple style classes in single string

This commit is contained in:
Karl Tauber
2021-09-29 23:49:40 +02:00
parent 3d8c535ffa
commit c4b016c9c8
5 changed files with 262 additions and 10 deletions

View File

@@ -146,8 +146,8 @@ public interface FlatClientProperties
String STYLE = "FlatLaf.style"; String STYLE = "FlatLaf.style";
/** /**
* Specifies the style class(es) of a component as String * Specifies the style class(es) of a component as String (single class or multiple classes separated by space characters)
* or as {@link java.util.List}<String>. * or as {@code String[]} or {@link java.util.List}<String> (multiple classes).
* <p> * <p>
* The style rules must be defined in UI defaults either as strings (in CSS syntax) * The style rules must be defined in UI defaults either as strings (in CSS syntax)
* or as {@link java.util.Map}&lt;String, Object&gt; (with binary values). * or as {@link java.util.Map}&lt;String, Object&gt; (with binary values).

View File

@@ -127,7 +127,7 @@ public class FlatStylingSupport
* UIManager.get( "[style]Button.foo" ) ); * UIManager.get( "[style]Button.foo" ) );
* }</pre> * }</pre>
* *
* @param styleClass the style class(es) either as string (single class) * @param styleClass the style class(es) either as string (single class or multiple classes separated by space characters)
* or as {@code String[]} or {@link java.util.List}&lt;String&gt; (multiple classes) * or as {@code String[]} or {@link java.util.List}&lt;String&gt; (multiple classes)
* @param type the type of the component * @param type the type of the component
* @return the styles * @return the styles
@@ -136,8 +136,11 @@ public class FlatStylingSupport
if( styleClass == null ) if( styleClass == null )
return null; return null;
if( styleClass instanceof String && ((String)styleClass).indexOf( ' ' ) >= 0 )
styleClass = StringUtils.split( (String) styleClass, ' ', true, true );
if( styleClass instanceof String ) if( styleClass instanceof String )
return getStyleForClass( (String) styleClass, type ); return getStyleForClass( ((String)styleClass).trim(), type );
else if( styleClass instanceof String[] ) { else if( styleClass instanceof String[] ) {
Object style = null; Object style = null;
for( String cls : (String[]) styleClass ) for( String cls : (String[]) styleClass )

View File

@@ -17,6 +17,7 @@
package com.formdev.flatlaf.util; package com.formdev.flatlaf.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
@@ -46,16 +47,50 @@ public class StringUtils
} }
public static List<String> split( String str, char delim ) { public static List<String> split( String str, char delim ) {
ArrayList<String> strs = new ArrayList<>(); return split( str, delim, false, false );
}
/**
* Splits a string at the specified delimiter.
* If trimming is enabled, then leading and trailing whitespace characters are removed.
* If excludeEmpty is {@code true}, then only non-empty strings are returned.
*
* @since 2
*/
public static List<String> split( String str, char delim, boolean trim, boolean excludeEmpty ) {
int delimIndex = str.indexOf( delim ); int delimIndex = str.indexOf( delim );
if( delimIndex < 0 ) {
if( trim )
str = str.trim();
return !excludeEmpty || !str.isEmpty()
? Collections.singletonList( str )
: Collections.emptyList();
}
ArrayList<String> strs = new ArrayList<>();
int index = 0; int index = 0;
while( delimIndex >= 0 ) { while( delimIndex >= 0 ) {
strs.add( str.substring( index, delimIndex ) ); add( strs, str, index, delimIndex, trim, excludeEmpty );
index = delimIndex + 1; index = delimIndex + 1;
delimIndex = str.indexOf( delim, index ); delimIndex = str.indexOf( delim, index );
} }
strs.add( str.substring( index ) ); add( strs, str, index, str.length(), trim, excludeEmpty );
return strs; return strs;
} }
private static void add( List<String> strs, String str, int begin, int end, boolean trim, boolean excludeEmpty ) {
if( trim ) {
// skip leading whitespace
while( begin < end && str.charAt( begin ) <= ' ' )
begin++;
// skip trailing whitespace
while( begin < end && str.charAt( end - 1 ) <= ' ' )
end--;
}
if( !excludeEmpty || end > begin )
strs.add( str.substring( begin, end ) );
}
} }

View File

@@ -19,6 +19,7 @@ package com.formdev.flatlaf.ui;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.util.Arrays;
import javax.swing.*; import javax.swing.*;
import javax.swing.table.JTableHeader; import javax.swing.table.JTableHeader;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
@@ -114,10 +115,25 @@ public class TestFlatStyleClasses
assertEquals( assertEquals(
FlatStylingSupport.concatStyles( BUTTON_PRIMARY, SECONDARY ), FlatStylingSupport.concatStyles( BUTTON_PRIMARY, SECONDARY ),
FlatStylingSupport.getStyleForClasses( new String[] { "primary", "secondary" }, "Button" ) ); FlatStylingSupport.getStyleForClasses( "primary secondary", "Button" ) );
assertEquals(
FlatStylingSupport.concatStyles( SECONDARY, BUTTON_PRIMARY ),
FlatStylingSupport.getStyleForClasses( "secondary primary", "Button" ) );
// String
assertEquals(
FlatStylingSupport.concatStyles( SECONDARY, BUTTON_PRIMARY ),
FlatStylingSupport.getStyleForClasses( " secondary primary bla blu ", "Button" ) );
// String[]
assertEquals( assertEquals(
FlatStylingSupport.concatStyles( SECONDARY, BUTTON_PRIMARY ), FlatStylingSupport.concatStyles( SECONDARY, BUTTON_PRIMARY ),
FlatStylingSupport.getStyleForClasses( new String[] { "secondary", "primary" }, "Button" ) ); FlatStylingSupport.getStyleForClasses( new String[] { "secondary", "primary" }, "Button" ) );
// List<String>
assertEquals(
FlatStylingSupport.concatStyles( SECONDARY, BUTTON_PRIMARY ),
FlatStylingSupport.getStyleForClasses( Arrays.asList( "secondary", "primary" ), "Button" ) );
} }
@Test @Test
@@ -132,7 +148,7 @@ public class TestFlatStyleClasses
@Test @Test
void apply2() { void apply2() {
JButton c = new JButton(); JButton c = new JButton();
c.putClientProperty( FlatClientProperties.STYLE_CLASS, new String[] { "primary", "secondary" } ); c.putClientProperty( FlatClientProperties.STYLE_CLASS, "primary secondary" );
assertEquals( new Color( 0x00ff88 ), c.getBackground() ); assertEquals( new Color( 0x00ff88 ), c.getBackground() );
assertEquals( Color.white, c.getForeground() ); assertEquals( Color.white, c.getForeground() );
@@ -141,7 +157,7 @@ public class TestFlatStyleClasses
@Test @Test
void apply3() { void apply3() {
JButton c = new JButton(); JButton c = new JButton();
c.putClientProperty( FlatClientProperties.STYLE_CLASS, new String[] { "secondary", "primary" } ); c.putClientProperty( FlatClientProperties.STYLE_CLASS, "secondary primary" );
assertEquals( new Color( 0x0088ff ), c.getBackground() ); assertEquals( new Color( 0x0088ff ), c.getBackground() );
assertEquals( Color.white, c.getForeground() ); assertEquals( Color.white, c.getForeground() );

View File

@@ -0,0 +1,198 @@
/*
* 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.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
/**
* @author Karl Tauber
*/
public class TestStringUtils
{
@Test
void split() {
// empty
assertEquals(
Arrays.asList( "" ),
StringUtils.split( "", ',' ) );
// not empty
assertEquals(
Arrays.asList( "a" ),
StringUtils.split( "a", ',' ) );
assertEquals(
Arrays.asList( "a", "b" ),
StringUtils.split( "a,b", ',' ) );
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a,b,c", ',' ) );
// empty parts
assertEquals(
Arrays.asList( "", "b", "c" ),
StringUtils.split( ",b,c", ',' ) );
assertEquals(
Arrays.asList( "a", "", "c" ),
StringUtils.split( "a,,c", ',' ) );
assertEquals(
Arrays.asList( "a", "b", "" ),
StringUtils.split( "a,b,", ',' ) );
// parts with leading/trailing spaces
assertEquals(
Arrays.asList( "a", " b", " c" ),
StringUtils.split( "a, b, c", ',' ) );
assertEquals(
Arrays.asList( " a", "b", "c " ),
StringUtils.split( " a,b,c ", ',' ) );
assertEquals(
Arrays.asList( " a", " b ", "c " ),
StringUtils.split( " a, b ,c ", ',' ) );
// space delimiter
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a b c", ' ' ) );
assertEquals(
Arrays.asList( "a", "", "", "b", "", "c" ),
StringUtils.split( "a b c", ' ' ) );
// new line delimiter
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a\nb\nc", '\n' ) );
assertEquals(
Arrays.asList( "a", "", "", "b", "", "c" ),
StringUtils.split( "a\n\n\nb\n\nc", '\n' ) );
}
@Test
void splitTrim() {
// empty
assertEquals(
Arrays.asList( "" ),
StringUtils.split( "", ',', true, false ) );
// not empty
assertEquals(
Arrays.asList( "a" ),
StringUtils.split( "a", ',', true, false ) );
assertEquals(
Arrays.asList( "a", "b" ),
StringUtils.split( "a,b", ',', true, false ) );
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a,b,c", ',', true, false ) );
// empty parts
assertEquals(
Arrays.asList( "", "b", "c" ),
StringUtils.split( ",b,c", ',', true, false ) );
assertEquals(
Arrays.asList( "a", "", "c" ),
StringUtils.split( "a,,c", ',', true, false ) );
assertEquals(
Arrays.asList( "a", "b", "" ),
StringUtils.split( "a,b,", ',', true, false ) );
// parts with leading/trailing spaces
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a, b, c", ',', true, false ) );
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( " a,b,c ", ',', true, false ) );
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( " a, b ,c ", ',', true, false ) );
// space delimiter
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a b c", ' ', true, false ) );
assertEquals(
Arrays.asList( "a", "", "", "b", "", "c" ),
StringUtils.split( "a b c", ' ', true, false ) );
// new line delimiter
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a\nb\nc", '\n', true, false ) );
assertEquals(
Arrays.asList( "a", "", "", "b", "", "c" ),
StringUtils.split( "a\n\n\nb\n\nc", '\n', true, false ) );
}
@Test
void splitTrimAndExcludeEmpty() {
// empty
assertEquals(
Arrays.asList(),
StringUtils.split( "", ',', true, true ) );
// not empty
assertEquals(
Arrays.asList( "a" ),
StringUtils.split( "a", ',', true, true ) );
assertEquals(
Arrays.asList( "a", "b" ),
StringUtils.split( "a,b", ',', true, true ) );
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a,b,c", ',', true, true ) );
// empty parts
assertEquals(
Arrays.asList( "b", "c" ),
StringUtils.split( ",b,c", ',', true, true ) );
assertEquals(
Arrays.asList( "a", "c" ),
StringUtils.split( "a,,c", ',', true, true ) );
assertEquals(
Arrays.asList( "a", "b" ),
StringUtils.split( "a,b,", ',', true, true ) );
// parts with leading/trailing spaces
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a, b, c", ',', true, true ) );
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( " a,b,c ", ',', true, true ) );
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( " a, b ,c ", ',', true, true ) );
// space delimiter
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a b c", ' ', true, true ) );
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a b c", ' ', true, true ) );
// new line delimiter
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a\nb\nc", '\n', true, true ) );
assertEquals(
Arrays.asList( "a", "b", "c" ),
StringUtils.split( "a\n\n\nb\n\nc", '\n', true, true ) );
}
}