View Javadoc

1   /*
2    * Copyright 2006-2016 The JGUIraffe Team.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.jguiraffe.gui.builder.components;
17  
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.Locale;
23  import java.util.NoSuchElementException;
24  import java.util.StringTokenizer;
25  
26  /**
27   * <p>
28   * A helper class for dealing with colors.
29   * </p>
30   * <p>
31   * This class defines helper methods for converting color values specified in
32   * form builder Jelly scripts. In this model colors can be defined in the
33   * following different ways:
34   * <ul>
35   * <li>Using a symbolic name. For this purpose this class defines constants
36   * that roughly correspond to the colors defined by the
37   * {@code java.awt.Color} class.</li>
38   * <li>As a hexadecimal numeric value. In this case the color definition must
39   * start with a &quot;#&quot; sign, e.g. {@code #80FF80}. This is
40   * analogous to color definitions in HTML.</li>
41   * <li>As triple of decimal rgb values. Definitions of this type look like
42   * {@code (r, g, b)}, with r, g, b in the range from 0 to 255.</li>
43   * <li>Logic color definitions. These are arbitrary strings which are not
44   * further interpreted, e.g. style sheet names. To be recognized, such a string
45   * must start with a &quot;~&quot; character, e.g. {@code ~MyStyle}.</li>
46   * </ul>
47   * </p>
48   *
49   * @author Oliver Heger
50   * @version $Id: ColorHelper.java 205 2012-01-29 18:29:57Z oheger $
51   */
52  public final class ColorHelper
53  {
54      /** Constant for the RGB color definition prefix. */
55      static final String COLDEF_RGB_PREFIX = "(";
56  
57      /** Constant for the RGB color definition suffix. */
58      static final String COLDEF_RGB_SUFFIX = ")";
59  
60      /** Constant for a separator used by the toString() method. */
61      static final String SEPARATOR = ", ";
62  
63      /** Constant for the RGB color definition delimiters. */
64      private static final String RGB_DELIMITERS = COLDEF_RGB_PREFIX
65              + COLDEF_RGB_SUFFIX + ",; ";
66  
67      /** Constant for the hexadecimal color definition character. */
68      private static final String COLDEF_HEXA = "#";
69  
70      /** Constant for the prefix for logic color definitions. */
71      private static final String COLDEF_LOGIC = "~";
72  
73      /** Constant for the bit mask for removing the high byte. */
74      private static final int BYTE_MASK = 0xFF;
75  
76      /** Constant for shifting a byte. */
77      private static final int BYTE = 8;
78  
79      /** Constant for shifting a word. */
80      private static final int WORD = 16;
81  
82      /** Constant for the base 16. */
83      private static final int BASE_16 = 16;
84  
85      /** A list with the names of the existing predefined color names. */
86      private static final List<String> PREDEFINED_COLOR_NAMES;
87  
88      /**
89       * Private constructor so no instance can be created.
90       */
91      private ColorHelper()
92      {
93      }
94  
95      /**
96       * Returns the predefined color with the given name. The passed in name must
97       * be one of the names returned by the {@code getPredefinedNames()}
98       * method (case does not matter).
99       *
100      * @param name the name of the desired color
101      * @return the color
102      * @throws FormBuilderException if this color does not exist
103      */
104     public static Color getPredefinedColor(String name)
105             throws FormBuilderException
106     {
107         try
108         {
109             return NamedColor.valueOf(name.toUpperCase(Locale.ENGLISH)).getColor();
110         }
111         catch (IllegalArgumentException iex)
112         {
113             throw new FormBuilderException(
114                     "No predefined color found: " + name, iex);
115         }
116         catch (NullPointerException npex)
117         {
118             throw new FormBuilderException(
119                     "Name of predefined color must not be null!");
120         }
121     }
122 
123     /**
124      * Returns an iterator with the names (Strings) of all predefined colors.
125      * These names can be passed to the {@code getPredefinedColor()}
126      * method.
127      *
128      * @return the names of the predefined colors
129      */
130     public static Iterator<String> getPredefinedNames()
131     {
132         return PREDEFINED_COLOR_NAMES.iterator();
133     }
134 
135     /**
136      * The main method for resolving a color definition. This method can be
137      * given a color definition in one of the supported flavors. It will try to
138      * resolve this definition and return the corresponding {@code Color}
139      * object. If this fails, an exception will be thrown.
140      *
141      * @param c the color definition
142      * @return the corresponding color object or <b>null</b> if the passed in
143      * color definition was <b>null</b>
144      * @throws FormBuilderException if the color definition cannot be resolved
145      */
146     public static Color resolveColor(String c) throws FormBuilderException
147     {
148         if (c == null)
149         {
150             return null;
151         }
152         else if (c.startsWith(COLDEF_LOGIC))
153         {
154             return resolveLogicColor(c);
155         }
156         else if (c.startsWith(COLDEF_HEXA))
157         {
158             return resolveHexColor(c);
159         }
160         else if (c.startsWith(COLDEF_RGB_PREFIX)
161                 && c.endsWith(COLDEF_RGB_SUFFIX))
162         {
163             return resolveRGBColor(c);
164         }
165         else
166         {
167             return getPredefinedColor(c);
168         }
169     }
170 
171     /**
172      * Resolves a logic color definition.
173      *
174      * @param c the color definition
175      * @return the resolved {@code Color} instance
176      * @throws FormBuilderException if the definition is invalid
177      */
178     private static Color resolveLogicColor(String c)
179             throws FormBuilderException
180     {
181         try
182         {
183             return Color.newLogicInstance(c.substring(COLDEF_LOGIC.length()));
184         }
185         catch (IllegalArgumentException iex)
186         {
187             throw new FormBuilderException("Invalid logic color definition: "
188                     + c, iex);
189         }
190     }
191 
192     /**
193      * Resolves the given color definition in the hexadecimal flavor.
194      *
195      * @param s the color definition
196      * @return the resolved color
197      * @throws FormBuilderException if the color definition is invalid
198      */
199     private static Color resolveHexColor(String s) throws FormBuilderException
200     {
201         try
202         {
203             int value =
204                     Integer.parseInt(s.substring(COLDEF_HEXA.length()), BASE_16);
205             return Color.newRGBInstance(value >> WORD,
206                     (value >> BYTE) & BYTE_MASK, value & BYTE_MASK);
207         }
208         catch (NumberFormatException nex)
209         {
210             throw new FormBuilderException("Invalid color definition: " + s,
211                     nex);
212         }
213         catch (IllegalArgumentException iex)
214         {
215             throw new FormBuilderException(
216                     "Color component out of range in color definition: " + s,
217                     iex);
218         }
219     }
220 
221     /**
222      * Resolves the given color definition in decimal RGB flavor.
223      *
224      * @param c the color definition
225      * @return the resolved color
226      * @throws FormBuilderException if the color definition is invalid
227      */
228     private static Color resolveRGBColor(String c) throws FormBuilderException
229     {
230         StringTokenizer tok = new StringTokenizer(c, RGB_DELIMITERS);
231         try
232         {
233             Color col = Color.newRGBInstance(Integer.parseInt(tok.nextToken()),
234                     Integer.parseInt(tok.nextToken()), Integer.parseInt(tok
235                             .nextToken()));
236             if (tok.hasMoreTokens())
237             {
238                 throw new FormBuilderException(
239                         "Too many components in color definition: " + c);
240             }
241             return col;
242         }
243 
244         catch (NumberFormatException nex)
245         {
246             throw new FormBuilderException(
247                     "Invalid RGB value in color definition: " + c, nex);
248         }
249         catch (NoSuchElementException nse)
250         {
251             throw new FormBuilderException(
252                     "Too few components in color definition: " + c, nse);
253         }
254         catch (IllegalArgumentException iex)
255         {
256             throw new FormBuilderException(
257                     "Color component out of range in color definition: " + c,
258                     iex);
259         }
260     }
261 
262     // static initializer; initializes the list with the predefined color names
263     static
264     {
265         NamedColor[] values = NamedColor.values();
266         List<String> names = new ArrayList<String>(values.length);
267         for (NamedColor nc : values)
268         {
269             names.add(nc.name());
270         }
271         PREDEFINED_COLOR_NAMES = Collections.unmodifiableList(names);
272     }
273 
274     /**
275      * An enumeration with predefined color constants. The names defined here
276      * can be passed to {@code getPredefinedColor()}.
277      */
278     public static enum NamedColor
279     {
280         /** Default color black. */
281         BLACK(Color.newRGBInstance(0, 0, 0)),
282 
283         /** Default color blue. */
284         BLUE(Color.newRGBInstance(0, 0, 255)),
285 
286         /** Default color cyan. */
287         CYAN(Color.newRGBInstance(0, 255, 255)),
288 
289         /** Default color dark gray. */
290         DARK_GRAY(Color.newRGBInstance(64, 64, 64)),
291 
292         /** Default color gray. */
293         GRAY(Color.newRGBInstance(128, 128, 128)),
294 
295         /** Default color green. */
296         GREEN(Color.newRGBInstance(0, 255, 0)),
297 
298         /** Default color light gray. */
299         LIGHT_GRAY(Color.newRGBInstance(192, 192, 192)),
300 
301         /** Default color magenta. */
302         MAGENTA(Color.newRGBInstance(255, 0, 255)),
303 
304         /** Default color orange. */
305         ORANGE(Color.newRGBInstance(255, 200, 0)),
306 
307         /** Default color pink. */
308         PINK(Color.newRGBInstance(255, 175, 175)),
309 
310         /** Default color red. */
311         RED(Color.newRGBInstance(255, 0, 0)),
312 
313         /** Default color white. */
314         WHITE(Color.newRGBInstance(255, 255, 255)),
315 
316         /** Default color yellow. */
317         YELLOW(Color.newRGBInstance(255, 255, 0));
318 
319         /** Stores the referenced {@code Color} object. */
320         private final Color color;
321 
322         /**
323          * Creates a new instance of {@code NamedColor} and sets the
324          * associated color.
325          *
326          * @param c the associated color
327          */
328         private NamedColor(Color c)
329         {
330             color = c;
331         }
332 
333         /**
334          * Returns the associated {@code Color} object.
335          *
336          * @return the {@code Color} represented by this object
337          */
338         public Color getColor()
339         {
340             return color;
341         }
342     }
343 }