View Javadoc
1   /*
2   
3       dsh-color-scheme  Color schemes.
4       Copyright (c) 2009-2016 held jointly by the individual authors.
5   
6       This library is free software; you can redistribute it and/or modify it
7       under the terms of the GNU Lesser General Public License as published
8       by the Free Software Foundation; either version 3 of the License, or (at
9       your option) any later version.
10  
11      This library is distributed in the hope that it will be useful, but WITHOUT
12      ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
13      FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14      License for more details.
15  
16      You should have received a copy of the GNU Lesser General Public License
17      along with this library;  if not, write to the Free Software Foundation,
18      Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
19  
20      > http://www.fsf.org/licensing/licenses/lgpl.html
21      > http://www.opensource.org/licenses/lgpl-license.php
22  
23  */
24  package org.dishevelled.color.scheme.impl;
25  
26  import java.awt.Color;
27  
28  import java.io.InputStream;
29  
30  import java.util.ArrayList;
31  import java.util.List;
32  
33  import java.util.regex.Matcher;
34  import java.util.regex.Pattern;
35  
36  import javax.xml.parsers.SAXParserFactory;
37  
38  import net.sf.stax.SAX2StAXAdaptor;
39  import net.sf.stax.StAXContentHandlerBase;
40  import net.sf.stax.StAXContext;
41  import net.sf.stax.StAXDelegationContext;
42  
43  import org.apache.commons.io.IOUtils;
44  
45  import org.dishevelled.color.scheme.ColorFactory;
46  import org.dishevelled.color.scheme.ColorScheme;
47  import org.dishevelled.color.scheme.factory.DefaultColorFactory;
48  
49  import org.xml.sax.XMLReader;
50  import org.xml.sax.Attributes;
51  import org.xml.sax.InputSource;
52  import org.xml.sax.SAXException;
53  import org.xml.sax.ContentHandler;
54  
55  /**
56   * Color schemes.
57   *
58   * @author  Michael Heuer
59   */
60  public final class ColorSchemes
61  {
62      /** Color scheme pattern. */
63      private static final Pattern COLOR_SCHEME = Pattern.compile("^([a-z]+)-([a-z0-9-]+)-([0-9]+)$");
64  
65      /** Color factory. */
66      private static final ColorFactory COLOR_FACTORY = new DefaultColorFactory();
67  
68  
69      /**
70       * Private no-arg constructor.
71       */
72      private ColorSchemes()
73      {
74          // empty
75      }
76  
77  
78      /**
79       * Parse the specified value into a color scheme.
80       *
81       * @param value value to parse
82       * @return the specified value parsed into a color scheme
83       */
84      public static ColorScheme parseColorScheme(final String value)
85      {
86          if (value == null)
87          {
88              throw new IllegalArgumentException("value must not be null");
89          }
90          Matcher matcher = COLOR_SCHEME.matcher(value);
91          if (!matcher.matches())
92          {
93              throw new IllegalArgumentException("color scheme " + value + " not valid format");
94          }
95          String type = matcher.group(1);
96          String name = matcher.group(2);
97          int colors = Integer.parseInt(matcher.group(3));
98          if ("discrete".equals(type))
99          {
100             return getDiscreteColorScheme(name, colors);
101         }
102         else if ("continuous".equals(type))
103         {
104             return getContinuousColorScheme(name, colors);
105         }
106         else
107         {
108             throw new IllegalArgumentException("color scheme type " + type + " not valid type");
109         }
110     }
111 
112     /**
113      * Create and return a discrete color scheme with the specified name and number of colors, if any.
114      * The color schemes are defined in a simple XML format and read from the color-scheme library classpath.
115      *
116      * @since 2.1
117      * @param name name
118      * @param colors number of colors
119      * @return a discrete color scheme with the specified name and number of colors, or
120      *    <code>null</code> if no such discrete color scheme exists
121      */
122     public static ColorScheme getDiscreteColorScheme(final String name,
123                                                      final int colors)
124     {
125         InputStream inputStream = null;
126         ColorScheme colorScheme = null;
127         try
128         {
129             inputStream = ColorSchemes.class.getResourceAsStream(name + "-" + colors + ".xml");
130             XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
131             InputSource inputSource = new InputSource(inputStream);
132             ColorSchemeHandler colorSchemeHandler = new ColorSchemeHandler();
133             ContentHandler contentHandler = new SAX2StAXAdaptor(colorSchemeHandler);
134             xmlReader.setContentHandler(contentHandler);
135             xmlReader.parse(inputSource);
136             if ("divergent".equals(colorSchemeHandler.getType()))
137             {
138                 colorScheme = new DiscreteDivergentColorScheme(colorSchemeHandler.getName(),
139                                                                colorSchemeHandler.getColors(), 0.0d, 0.5d, 1.0d,
140                                                                COLOR_FACTORY);
141             }
142             else
143             {
144                 colorScheme = new DiscreteColorScheme(colorSchemeHandler.getName(),
145                                                       colorSchemeHandler.getColors(), 0.0d, 1.0d,
146                                                       COLOR_FACTORY);
147             }
148         }
149         catch (Exception e)
150         {
151             //e.printStackTrace();
152         }
153         finally
154         {
155             IOUtils.closeQuietly(inputStream);
156         }
157         return colorScheme;
158     }
159 
160     /**
161      * Create and return a continuous color scheme with the specified name and number of colors, if any.
162      * The color schemes are defined in a simple XML format and read from the color-scheme library classpath.
163      *
164      * @since 2.1
165      * @param name name
166      * @param colors number of colors
167      * @return a continuous color scheme with the specified name and number of colors, or
168      *    <code>null</code> if no such continuous color scheme exists
169      */
170     public static ColorScheme getContinuousColorScheme(final String name,
171                                                        final int colors)
172     {
173         InputStream inputStream = null;
174         ColorScheme colorScheme = null;
175         try
176         {
177             inputStream = ColorSchemes.class.getResourceAsStream(name + "-" + colors + ".xml");
178             XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
179             InputSource inputSource = new InputSource(inputStream);
180             ColorSchemeHandler colorSchemeHandler = new ColorSchemeHandler();
181             ContentHandler contentHandler = new SAX2StAXAdaptor(colorSchemeHandler);
182             xmlReader.setContentHandler(contentHandler);
183             xmlReader.parse(inputSource);
184             if ("divergent".equals(colorSchemeHandler.getType()))
185             {
186                 colorScheme = new ContinuousDivergentColorScheme(colorSchemeHandler.getName(),
187                                                                  colorSchemeHandler.getColors(), 0.0d, 0.5d, 1.0d,
188                                                                  COLOR_FACTORY);
189             }
190             else
191             {
192                 colorScheme = new ContinuousColorScheme(colorSchemeHandler.getName(),
193                                                         colorSchemeHandler.getColors(), 0.0d, 1.0d,
194                                                         COLOR_FACTORY);
195             }
196         }
197         catch (Exception e)
198         {
199             //e.printStackTrace();
200         }
201         finally
202         {
203             IOUtils.closeQuietly(inputStream);
204         }
205         return colorScheme;
206     }
207 
208     /**
209      * Color scheme handler.
210      */
211     private static final class ColorSchemeHandler
212         extends StAXContentHandlerBase
213     {
214         /** Name. */
215         private String name;
216 
217         /** Type. */
218         private String type;
219 
220         /** List of colors. */
221         private final List<Color> colors = new ArrayList<Color>();
222 
223         /** Color handler. */
224         private final ColorHandler colorHandler = new ColorHandler();
225 
226 
227         @Override
228         public void startElement(final String nsURI,
229                                  final String localName,
230                                  final String qName,
231                                  final Attributes attrs,
232                                  final StAXDelegationContext dctx)
233             throws SAXException
234         {
235             if ("color".equals(qName))
236             {
237                 dctx.delegate(colorHandler);
238             }
239             else if ("color-scheme".equals(qName))
240             {
241                 name = attrs.getValue("name");
242                 type = attrs.getValue("type");
243             }
244         }
245 
246         @Override
247         public void endElement(final String nsURI,
248                                final String localName,
249                                final String qName,
250                                final Object result,
251                                final StAXContext context)
252             throws SAXException
253         {
254             if ("color".equals(qName))
255             {
256                 Color color = (Color) result;
257                 colors.add(color);
258             }
259         }
260 
261         /**
262          * Return the name for this color scheme handler.
263          *
264          * @return the name for this color scheme handler
265          */
266         String getName()
267         {
268             return name;
269         }
270 
271         /**
272          * Return the type for this color scheme handler.
273          *
274          * @return the type for this color scheme handler
275          */
276         String getType()
277         {
278             return type;
279         }
280 
281         /**
282          * Return the list of colors for this color scheme handler.
283          *
284          * @return the list of colors for this color scheme handler
285          */
286         List<Color> getColors()
287         {
288             return colors;
289         }
290     }
291 
292     /**
293      * Color handler.
294      */
295     private static final class ColorHandler
296         extends StAXContentHandlerBase
297     {
298         /** Color. */
299         private Color color;
300 
301 
302         @Override
303         public void startElement(final String nsURI,
304                                  final String localName,
305                                  final String qName,
306                                  final Attributes attrs,
307                                  final StAXDelegationContext dctx)
308             throws SAXException
309         {
310             int r = Integer.parseInt(attrs.getValue("red"));
311             int g = Integer.parseInt(attrs.getValue("green"));
312             int b = Integer.parseInt(attrs.getValue("blue"));
313             float a = Float.parseFloat(attrs.getValue("alpha"));
314             this.color = COLOR_FACTORY.createColor(r, g, b, a);
315         }
316 
317         @Override
318         public Object endTree(final StAXContext context)
319             throws SAXException
320         {
321             return color;
322         }
323     }
324 }