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.io.Serializable;
19  
20  import org.apache.commons.lang.ObjectUtils;
21  import org.apache.commons.lang.StringUtils;
22  
23  /**
24   * <p>
25   * A simple class representing a color in a platform-independent way.
26   * </p>
27   * <p>
28   * In the most basic form, colors are defined using RGB components. In more
29   * complex scenarios a color can be represented by a string - for instance, if
30   * it is determined by a complex style sheet definition. The
31   * {@code isLogicColor()} method can be used to distinguish between these kinds
32   * of objects. If it returns <strong>true</strong>, the color is defined based
33   * on a string, and thus concrete RGB values are not available.
34   * </p>
35   * <p>
36   * {@code Color} objects are created using static factory methods. They are
37   * immutable and thus can be shared between different threads.
38   * </p>
39   *
40   * @author Oliver Heger
41   * @version $Id: Color.java 205 2012-01-29 18:29:57Z oheger $
42   */
43  public class Color implements Serializable
44  {
45      /**
46       * Constant for an undefined color component. This value is returned by the
47       * access methods for the single color components ({@code getRed()},
48       * {@code getGreen()}, or {@code getBlue()} to indicate that this component
49       * is undefined - which is the case for logic colors.
50       *
51       * @since 1.3
52       */
53      public static final int COMPONENT_UNDEFINED = -1;
54  
55      /**
56       * Constant for an undefined color. This constant defines a special instance
57       * which does not have RGB components nor a logic color definition. It can
58       * be used to represent an undefined color.
59       *
60       * @since 1.3
61       */
62      public static final Color UNDEFINED = new Color(COMPONENT_UNDEFINED,
63              COMPONENT_UNDEFINED, COMPONENT_UNDEFINED, null);
64  
65      /**
66       * The serial version UID.
67       */
68      private static final long serialVersionUID = 20130606L;
69  
70      /** Constant for an error message pattern for an invalid color component. */
71      private static final String ERR_INVALID_COMPONENT =
72              "Invalid value for component %s: %d!";
73  
74      /** Constant for the maximum value of a RGB component. */
75      private static final int MAX_RANGE = 255;
76  
77      /** Constant for the buffer size for the string generation. */
78      private static final int BUF_SIZE = 32;
79  
80      /** The logic color definition. */
81      private final String colorDefinition;
82  
83      /** The component for red. */
84      private final int red;
85  
86      /** The component for green. */
87      private final int green;
88  
89      /** The component for blue. */
90      private final int blue;
91  
92      /**
93       * Creates a new instance of {@code Color} and initializes its members.
94       *
95       * @param r the red component
96       * @param g the green component
97       * @param b the blue component
98       * @param def the logic color definition
99       */
100     Color(int r, int g, int b, String def)
101     {
102         red = r;
103         green = g;
104         blue = b;
105         colorDefinition = def;
106     }
107 
108     /**
109      * Returns a flag whether this {@code Color} instance is based on a logic
110      * color definition. This means that it was constructed from a text-based
111      * definition. In this case, the values of the RGB components are undefined.
112      *
113      * @return <strong>true</strong> if this {@code Color} instance is based on
114      *         a logic definition, <strong>false</strong> otherwise
115      * @since 1.3
116      */
117     public boolean isLogicColor()
118     {
119         return getRed() == COMPONENT_UNDEFINED
120                 || getGreen() == COMPONENT_UNDEFINED
121                 || getBlue() == COMPONENT_UNDEFINED;
122     }
123 
124     /**
125      * Returns the blue component of this color. This value is only defined if
126      * {@code isLogicColor()} returns <strong>false</strong>.
127      *
128      * @return the blue component
129      */
130     public int getBlue()
131     {
132         return blue;
133     }
134 
135     /**
136      * Returns the green component of this color. This value is only defined if
137      * {@code isLogicColor()} returns <strong>false</strong>.
138      *
139      * @return the green component
140      */
141     public int getGreen()
142     {
143         return green;
144     }
145 
146     /**
147      * Returns the red component of this color. This value is only defined if
148      * {@code isLogicColor()} returns <strong>false</strong>.
149      *
150      * @return the red component
151      */
152     public int getRed()
153     {
154         return red;
155     }
156 
157     /**
158      * Returns the logic color definition this {@code Color} instance is based
159      * on. This value is only defined of {@code isLogicColor()} returns
160      * <strong>true</strong>.
161      *
162      * @return the logic color definition
163      * @since 1.3
164      */
165     public String getColorDefinition()
166     {
167         return colorDefinition;
168     }
169 
170     /**
171      * Returns a String representation of this object.
172      *
173      * @return a String for this object
174      */
175     @Override
176     public String toString()
177     {
178         StringBuilder buf = new StringBuilder(BUF_SIZE);
179         buf.append(getClass().getSimpleName()).append("[ ");
180 
181         if (isLogicColor())
182         {
183             buf.append("def = '").append(getColorDefinition()).append('\'');
184         }
185         else
186         {
187             buf.append("rgb = ");
188             buf.append(ColorHelper.COLDEF_RGB_PREFIX);
189             buf.append(getRed()).append(ColorHelper.SEPARATOR);
190             buf.append(getGreen()).append(ColorHelper.SEPARATOR);
191             buf.append(getBlue()).append(ColorHelper.COLDEF_RGB_SUFFIX);
192         }
193 
194         buf.append(" ]");
195         return buf.toString();
196     }
197 
198     /**
199      * Tests if a passed in object equals this object. Two {@code Color} objects
200      * are considered equal if and only if all color components are equal.
201      *
202      * @param obj the object to compare to
203      * @return a flag whether the objects are equal
204      */
205     @Override
206     public boolean equals(Object obj)
207     {
208         if (this == obj)
209         {
210             return true;
211         }
212         if (!(obj instanceof Color))
213         {
214             return false;
215         }
216         Color c = (Color) obj;
217         return getRed() == c.getRed()
218                 && getGreen() == c.getGreen()
219                 && getBlue() == c.getBlue()
220                 && ObjectUtils.equals(getColorDefinition(),
221                         c.getColorDefinition());
222     }
223 
224     /**
225      * Determines a hash code for this object.
226      *
227      * @return a hash code
228      */
229     @Override
230     public int hashCode()
231     {
232         final int seed = 13;
233         final int factor = 43;
234 
235         int result = seed;
236         result = result * factor + getRed();
237         result = result * factor + getGreen();
238         result = result * factor + getBlue();
239         if (getColorDefinition() != null)
240         {
241             result = result * factor + getColorDefinition().hashCode();
242         }
243         return result;
244     }
245 
246     /**
247      * Creates a new instance of {@code Color} and initializes the single
248      * components. This method will check whether the passed in values are
249      * valid; if one is out of range, an exception will be thrown.
250      *
251      * @param r the r component
252      * @param g the g component
253      * @param b the b component
254      * @return the new {@code Color} instance
255      * @throws IllegalArgumentException if a component is invalid
256      * @deprecated Use {@code newRGBInstance()} instead.
257      */
258     @Deprecated
259     public static Color newInstance(int r, int g, int b)
260     {
261         return newRGBInstance(r, g, b);
262     }
263 
264     /**
265      * Creates a new instance of {@code Color} and initializes it with the given
266      * components for the red, green, and blue part. This method checks whether
267      * the passed in values are valid; if one argument is out of range, an
268      * exception is thrown.
269      *
270      * @param r the r component
271      * @param g the g component
272      * @param b the b component
273      * @return the new {@code Color} instance
274      * @throws IllegalArgumentException if a component is invalid
275      * @since 1.3
276      */
277     public static Color newRGBInstance(int r, int g, int b)
278     {
279         checkComponent(r, "red");
280         checkComponent(g, "green");
281         checkComponent(b, "blue");
282         return new Color(r, g, b, null);
283     }
284 
285     /**
286      * Creates a new instance of {@code Color} based on a logic, text-based
287      * color definition. The passed in string is just stored and not interpreted
288      * in any form. It must not be <b>null</b>.
289      *
290      * @param coldef the logic color definition
291      * @return the new {@code Color} instance
292      * @throws IllegalArgumentException if the color definition is undefined
293      * @since 1.3
294      */
295     public static Color newLogicInstance(String coldef)
296     {
297         if (StringUtils.isBlank(coldef))
298         {
299             throw new IllegalArgumentException(
300                     "Color definition must be defined!");
301         }
302         return new Color(COMPONENT_UNDEFINED, COMPONENT_UNDEFINED,
303                 COMPONENT_UNDEFINED, coldef);
304     }
305 
306     /**
307      * Checks whether a component of a color is in the correct range. If not, an
308      * exception is thrown.
309      *
310      * @param c the component to be checked
311      * @param name the name of the component (for producing a meaningful
312      *        exception message)
313      * @throws IllegalArgumentException if the component has an invalid value
314      */
315     private static void checkComponent(int c, String name)
316     {
317         if (c < 0 || c > MAX_RANGE)
318         {
319             throw new IllegalArgumentException(String.format(
320                     ERR_INVALID_COMPONENT, name, c));
321         }
322     }
323 }