99
1010import java .util .Collection ;
1111import java .util .Collections ;
12+ import java .util .HashSet ;
1213import java .util .LinkedHashMap ;
1314import java .util .Map ;
1415import java .util .Optional ;
@@ -133,6 +134,15 @@ void define(final NamedWidgetColor color)
133134 colors .put (color .getName (), color );
134135 }
135136
137+ /** Define a name to point to a named color
138+ * @param name Name of the color
139+ * @param color Named color
140+ */
141+ void defineAlias (String name , final NamedWidgetColor color )
142+ {
143+ colors .put (name , color );
144+ }
145+
136146 /** Get named color
137147 * @param name Name of the color
138148 * @return Named color, if known
@@ -142,6 +152,51 @@ public Optional<NamedWidgetColor> getColor(final String name)
142152 return Optional .ofNullable (colors .get (name ));
143153 }
144154
155+ sealed interface ColorDefinition permits RGBA , FromNamedWidgetColor , Alias {}
156+ private record RGBA (int red , int green , int blue , int alpha ) implements ColorDefinition { }
157+ private record FromNamedWidgetColor (NamedWidgetColor namedWidgetColor ) implements ColorDefinition { };
158+ private record Alias (NamedWidgetColor color ) implements ColorDefinition { };
159+
160+ /** Parse the color definition
161+ * @param colorDefinitionString Color definition
162+ * @return Optionally (when successful), an instance of ColorDefinition representing the result of parsing
163+ */
164+ public Optional <ColorDefinition > parseColorDefinition (final String colorDefinitionString )
165+ {
166+ String colorDefinitionStringTrimmed = colorDefinitionString .trim ();
167+ if (colorDefinitionStringTrimmed .startsWith ("alias" )) {
168+ String colorDefinitionsStringWithoutAlias = colorDefinitionStringTrimmed .substring (5 ).trim ();
169+ if (colorDefinitionsStringWithoutAlias .startsWith ("(" ) && colorDefinitionsStringWithoutAlias .endsWith (")" )) {
170+ String colorName = colorDefinitionsStringWithoutAlias .substring (1 ,colorDefinitionsStringWithoutAlias .length ()-1 ).trim ();
171+ if (colors .containsKey (colorName )) {
172+ NamedWidgetColor color = colors .get (colorName );
173+ return Optional .of (new Alias (color ));
174+ } else {
175+ return Optional .empty ();
176+ }
177+ }
178+ else {
179+ return Optional .empty ();
180+ }
181+ }
182+ else if (colors .containsKey (colorDefinitionStringTrimmed )) {
183+ NamedWidgetColor color = colors .get (colorDefinitionStringTrimmed );
184+ return Optional .of (new FromNamedWidgetColor (color ));
185+ }
186+ else {
187+ final StringTokenizer tokenizer = new StringTokenizer (colorDefinitionString , "," );
188+ try {
189+ final int red = Integer .parseInt (tokenizer .nextToken ().trim ());
190+ final int green = Integer .parseInt (tokenizer .nextToken ().trim ());
191+ final int blue = Integer .parseInt (tokenizer .nextToken ().trim ());
192+ final int alpha = tokenizer .hasMoreTokens () ? Integer .parseInt (tokenizer .nextToken ().trim ()) : 255 ;
193+ return Optional .of (new RGBA (red , green , blue , alpha ));
194+ } catch (Throwable throwable ) {
195+ return Optional .empty ();
196+ }
197+ }
198+ }
199+
145200 /** Resolve a named color
146201 * @param color Predefined color
147202 * @return Color as provided unless it was redefined
@@ -156,35 +211,26 @@ public NamedWidgetColor resolve(final NamedWidgetColor color)
156211 */
157212 public Collection <NamedWidgetColor > getColors ()
158213 {
159- return Collections .unmodifiableCollection ( colors .values ());
214+ return Collections .unmodifiableSet ( new HashSet <>( colors .values () ));
160215 }
161216
162217 @ Override
163218 protected void parse ( final String name , final String value ) throws Exception {
219+ Optional <ColorDefinition > optionalColorDefinition = parseColorDefinition (value );
164220
165- Optional <NamedWidgetColor > optionalColor = getColor (value );
166-
167- if ( optionalColor .isPresent () ) {
168-
169- NamedWidgetColor namedColor = optionalColor .get ();
170-
171- define (new NamedWidgetColor (name , namedColor .getRed (), namedColor .getGreen (), namedColor .getBlue (), namedColor .getAlpha ()));
172-
221+ if (optionalColorDefinition .isEmpty ()) {
222+ throw new Exception ("Cannot parse color '" + name + "' from '" + value + "'" );
173223 } else {
174-
175- final StringTokenizer tokenizer = new StringTokenizer (value , "," );
176-
177- try {
178-
179- final int red = Integer .parseInt (tokenizer .nextToken ().trim ());
180- final int green = Integer .parseInt (tokenizer .nextToken ().trim ());
181- final int blue = Integer .parseInt (tokenizer .nextToken ().trim ());
182- final int alpha = tokenizer .hasMoreTokens () ? Integer .parseInt (tokenizer .nextToken ().trim ()) : 255 ;
183-
184- define (new NamedWidgetColor (name , red , green , blue , alpha ));
185-
186- } catch ( Throwable ex ) {
187- throw new Exception ("Cannot parse color '" + name + "' from '" + value + "'" , ex );
224+ ColorDefinition colorDefinition = optionalColorDefinition .get ();
225+ if (colorDefinition instanceof RGBA rgba ) {
226+ define (new NamedWidgetColor (name , rgba .red , rgba .green , rgba .blue , rgba .alpha ));
227+ } else if (colorDefinition instanceof FromNamedWidgetColor fromNamedWidgetColor ) {
228+ NamedWidgetColor namedWidgetColor = fromNamedWidgetColor .namedWidgetColor ;
229+ define (new NamedWidgetColor (name , namedWidgetColor .getRed (), namedWidgetColor .getGreen (), namedWidgetColor .getBlue (), namedWidgetColor .getAlpha ()));
230+ } else if (colorDefinition instanceof Alias alias ) {
231+ defineAlias (name , alias .color );
232+ } else {
233+ throw new Exception ("Unhandled case: " + colorDefinition .toString ()); // This should never happen.
188234 }
189235
190236 }
0 commit comments