inprogress
[jalview.git] / forester / java / src / org / forester / phylogeny / data / NodeVisualData.java
1 \r
2 package org.forester.phylogeny.data;\r
3 \r
4 import java.awt.Color;\r
5 import java.awt.Font;\r
6 import java.io.IOException;\r
7 import java.io.Writer;\r
8 import java.util.ArrayList;\r
9 import java.util.List;\r
10 \r
11 import org.forester.phylogeny.data.Property.AppliesTo;\r
12 import org.forester.util.ForesterUtil;\r
13 \r
14 public final class NodeVisualData implements PhylogenyData {\r
15 \r
16     public static final String APTX_VISUALIZATION_REF = "style:";\r
17     public static final String FONT_COLOR_REF         = APTX_VISUALIZATION_REF + "font_color";\r
18     public static final String FONT_COLOR_TYPE        = "xsd:token";\r
19     public static final String FONT_REF               = APTX_VISUALIZATION_REF + "font";\r
20     public static final String FONT_SIZE_REF          = APTX_VISUALIZATION_REF + "font_size";\r
21     public static final String FONT_SIZE_TYPE         = "xsd:unsignedByte";\r
22     public static final String FONT_STYLE_BOLD        = "bold";\r
23     public static final String FONT_STYLE_BOLD_ITALIC = "bold_italic";\r
24     public static final String FONT_STYLE_ITALIC      = "italic";\r
25     public static final String FONT_STYLE_PLAIN       = "plain";\r
26     public static final String FONT_STYLE_REF         = APTX_VISUALIZATION_REF + "font_style";\r
27     public static final String FONT_STYLE_TYPE        = "xsd:token";\r
28     public static final String FONT_TYPE              = "xsd:token";\r
29     public static final String NODE_BORDER_COLOR_REF  = APTX_VISUALIZATION_REF + "node_border_color";\r
30     public static final String NODE_BORDER_COLOR_TYPE = "xsd:token";\r
31     public static final String NODE_FILL_COLOR_REF    = APTX_VISUALIZATION_REF + "node_fill_color";\r
32     public static final String NODE_FILL_COLOR_TYPE   = "xsd:token";\r
33     public static final String NODE_FILL_GRADIENT     = "gradient";\r
34     public static final String NODE_FILL_NONE         = "none";\r
35     public static final String NODE_FILL_SOLID        = "solid";\r
36     public static final String NODE_FILL_TYPE_REF     = APTX_VISUALIZATION_REF + "node_fill_type";\r
37     public static final String NODE_FILL_TYPE_TYPE    = "xsd:token";\r
38     public static final String NODE_SHAPE_CIRCLE      = "cicle";\r
39     public static final String NODE_SHAPE_RECTANGLE   = "rectangle";\r
40     public static final String NODE_SHAPE_REF         = APTX_VISUALIZATION_REF + "node_shape";\r
41     public static final String NODE_SHAPE_TYPE        = "xsd:token";\r
42     public static final String NODE_SIZE_REF          = APTX_VISUALIZATION_REF + "node_size";\r
43     public static final String NODE_SIZE_TYPE         = "xsd:float";\r
44     public static final String NODE_TRANSPARENCY_REF  = APTX_VISUALIZATION_REF + "node_transparency";\r
45     public static final String NODE_TRANSPARENCY_TYPE = "xsd:float";\r
46     private static final byte  DEFAULT_FONT_SIZE      = -1;\r
47     private static final int   DEFAULT_SIZE           = -1;\r
48     private static final int   DEFAULT_TRANSPARENCY   = -1;\r
49     private Color              _border_color;\r
50     private Color              _fill_color;\r
51     private NodeFill           _fill_type;\r
52     private Font               _font;\r
53     private Color              _font_color;\r
54     private String             _font_name;\r
55     private byte               _font_size;\r
56     private FontType           _font_style;\r
57     private NodeShape          _shape;\r
58     private float              _size;\r
59     private float              _transparency;\r
60 \r
61     public NodeVisualData() {\r
62         init();\r
63     }\r
64 \r
65     public NodeVisualData( final String font_name,\r
66                            final FontType font_style,\r
67                            final byte font_size,\r
68                            final Color font_color,\r
69                            final NodeShape shape,\r
70                            final NodeFill fill_type,\r
71                            final Color border_color,\r
72                            final Color fill_color,\r
73                            final float size,\r
74                            final float transparency ) {\r
75         setFontName( font_name );\r
76         setFontStyle( font_style );\r
77         setFontSize( font_size );\r
78         setFontColor( font_color );\r
79         setShape( shape );\r
80         setFillType( fill_type );\r
81         setBorderColor( border_color );\r
82         setFillColor( fill_color );\r
83         setSize( size );\r
84         setTransparency( transparency );\r
85     }\r
86 \r
87     @Override\r
88     public final StringBuffer asSimpleText() {\r
89         return asText();\r
90     }\r
91 \r
92     @Override\r
93     public final StringBuffer asText() {\r
94         final StringBuffer sb = new StringBuffer();\r
95         return sb;\r
96     }\r
97 \r
98     @Override\r
99     public final PhylogenyData copy() {\r
100         return new NodeVisualData( !ForesterUtil.isEmpty( getFontName() ) ? new String( getFontName() ) : null,\r
101                                    getFontStyle(),\r
102                                    getFontSize(),\r
103                                    getFontColor() != null ? new Color( getFontColor().getRed(), getFontColor()\r
104                                            .getGreen(), getFontColor().getBlue() ) : null,\r
105                                    getShape(),\r
106                                    getFillType(),\r
107                                    getBorderColor() != null ? new Color( getBorderColor().getRed(), getBorderColor()\r
108                                            .getGreen(), getBorderColor().getBlue() ) : null,\r
109                                    getFillColor() != null ? new Color( getFillColor().getRed(), getFillColor()\r
110                                            .getGreen(), getFillColor().getBlue() ) : null,\r
111                                    getSize(),\r
112                                    getTransparency() );\r
113     }\r
114 \r
115     public final Color getBorderColor() {\r
116         return _border_color;\r
117     }\r
118 \r
119     public final Color getFillColor() {\r
120         return _fill_color;\r
121     }\r
122 \r
123     public final NodeFill getFillType() {\r
124         return _fill_type;\r
125     }\r
126 \r
127     public final Font getFont() {\r
128         if ( _font != null ) {\r
129             return _font;\r
130         }\r
131         else if ( !ForesterUtil.isEmpty( getFontName() ) ) {\r
132             _font = new Font( getFontName(), getFontStyleInt(), getFontSize() );\r
133             return _font;\r
134         }\r
135         return null;\r
136     }\r
137 \r
138     public final Color getFontColor() {\r
139         return _font_color;\r
140     }\r
141 \r
142     public final String getFontName() {\r
143         return _font_name;\r
144     }\r
145 \r
146     public final byte getFontSize() {\r
147         return _font_size;\r
148     }\r
149 \r
150     public final FontType getFontStyle() {\r
151         return _font_style;\r
152     }\r
153 \r
154     public final int getFontStyleInt() {\r
155         if ( getFontStyle() == FontType.BOLD ) {\r
156             return Font.BOLD;\r
157         }\r
158         else if ( getFontStyle() == FontType.ITALIC ) {\r
159             return Font.ITALIC;\r
160         }\r
161         else if ( getFontStyle() == FontType.BOLD_ITALIC ) {\r
162             return Font.BOLD + Font.ITALIC;\r
163         }\r
164         return Font.PLAIN;\r
165     }\r
166 \r
167     public final NodeShape getShape() {\r
168         return _shape;\r
169     }\r
170 \r
171     public final float getSize() {\r
172         return _size;\r
173     }\r
174 \r
175     public final float getTransparency() {\r
176         return _transparency;\r
177     }\r
178 \r
179     public final boolean isEmpty() {\r
180         return ( ForesterUtil.isEmpty( getFontName() ) && ( getFontStyle() == FontType.PLAIN )\r
181                 && ( getFontSize() == DEFAULT_FONT_SIZE ) && ( getFontColor() == null )\r
182                 && ( getShape() == NodeShape.DEFAULT ) && ( getFillType() == NodeFill.DEFAULT )\r
183                 && ( getBorderColor() == null ) && ( getFillColor() == null ) && ( getSize() == DEFAULT_SIZE ) && ( getTransparency() == DEFAULT_TRANSPARENCY ) );\r
184     }\r
185 \r
186     @Override\r
187     public final boolean isEqual( final PhylogenyData data ) {\r
188         throw new UnsupportedOperationException();\r
189     }\r
190 \r
191     public void parseProperty( final Property prop ) {\r
192         if ( prop.getRef().equals( FONT_REF ) ) {\r
193             setFontName( prop.getValue().trim() );\r
194         }\r
195         else if ( prop.getRef().equals( FONT_SIZE_REF ) ) {\r
196             int s = -1;\r
197             try {\r
198                 s = Integer.parseInt( prop.getValue() );\r
199             }\r
200             catch ( final NumberFormatException e ) {\r
201                 return;\r
202             }\r
203             if ( ( s >= 0 ) && ( s < Byte.MAX_VALUE ) ) {\r
204                 setFontSize( s );\r
205             }\r
206         }\r
207         else if ( prop.getRef().equals( FONT_STYLE_REF ) ) {\r
208             setFontStyle( prop.getValue() );\r
209         }\r
210         else if ( prop.getRef().equals( FONT_COLOR_REF ) ) {\r
211             try {\r
212                 setFontColor( Color.decode( prop.getValue() ) );\r
213             }\r
214             catch ( final NumberFormatException e ) {\r
215                 return;\r
216             }\r
217         }\r
218         //\r
219         else if ( prop.getRef().equals( NODE_SIZE_REF ) ) {\r
220             int s = -1;\r
221             try {\r
222                 s = Integer.parseInt( prop.getValue() );\r
223             }\r
224             catch ( final NumberFormatException e ) {\r
225                 return;\r
226             }\r
227             if ( s >= 0 ) {\r
228                 setSize( s );\r
229             }\r
230         }\r
231         else if ( prop.getRef().equals( NODE_FILL_COLOR_REF ) ) {\r
232             try {\r
233                 setFillColor( Color.decode( prop.getValue() ) );\r
234             }\r
235             catch ( final NumberFormatException e ) {\r
236                 return;\r
237             }\r
238         }\r
239         else if ( prop.getRef().equals( NODE_BORDER_COLOR_REF ) ) {\r
240             try {\r
241                 setBorderColor( Color.decode( prop.getValue() ) );\r
242             }\r
243             catch ( final NumberFormatException e ) {\r
244                 return;\r
245             }\r
246         }\r
247         else if ( prop.getRef().equals( NODE_SHAPE_REF ) ) {\r
248             try {\r
249                 setShape( prop.getValue() );\r
250             }\r
251             catch ( final NumberFormatException e ) {\r
252                 return;\r
253             }\r
254         }\r
255     }\r
256 \r
257     public final void setBorderColor( final Color border_color ) {\r
258         _border_color = border_color;\r
259     }\r
260 \r
261     public final void setFillColor( final Color fill_color ) {\r
262         _fill_color = fill_color;\r
263     }\r
264 \r
265     public final void setFillType( final NodeFill fill_type ) {\r
266         _fill_type = fill_type;\r
267     }\r
268 \r
269     public final void setFontColor( final Color font_color ) {\r
270         _font_color = font_color;\r
271     }\r
272 \r
273     public final void setFontName( final String font_name ) {\r
274         if ( !ForesterUtil.isEmpty( font_name ) ) {\r
275             _font_name = font_name;\r
276         }\r
277         else {\r
278             _font_name = null;\r
279         }\r
280         _font = null;\r
281     }\r
282 \r
283     public final void setFontSize( final int font_size ) {\r
284         if ( ( font_size != DEFAULT_FONT_SIZE ) && ( font_size < 0 ) ) {\r
285             throw new IllegalArgumentException( "negative font size: " + font_size );\r
286         }\r
287         else if ( font_size > Byte.MAX_VALUE ) {\r
288             throw new IllegalArgumentException( "font size is too large: " + font_size );\r
289         }\r
290         _font_size = ( byte ) font_size;\r
291         _font = null;\r
292     }\r
293 \r
294     public final void setFontStyle( final FontType font_style ) {\r
295         _font_style = font_style;\r
296         _font = null;\r
297     }\r
298 \r
299     public final void setFontStyle( final int font_style ) {\r
300         if ( ( font_style == ( Font.BOLD + Font.ITALIC ) ) ) {\r
301             setFontStyle( FontType.BOLD_ITALIC );\r
302         }\r
303         else if ( font_style == Font.ITALIC ) {\r
304             setFontStyle( FontType.ITALIC );\r
305         }\r
306         else if ( font_style == Font.BOLD ) {\r
307             setFontStyle( FontType.BOLD );\r
308         }\r
309         else {\r
310             setFontStyle( FontType.PLAIN );\r
311         }\r
312     }\r
313 \r
314     public final void setFontStyle( final String font_style ) {\r
315         if ( font_style.equalsIgnoreCase( FONT_STYLE_BOLD ) ) {\r
316             setFontStyle( FontType.BOLD );\r
317         }\r
318         else if ( font_style.equalsIgnoreCase( FONT_STYLE_ITALIC ) ) {\r
319             setFontStyle( FontType.ITALIC );\r
320         }\r
321         else if ( font_style.equalsIgnoreCase( FONT_STYLE_BOLD_ITALIC ) ) {\r
322             setFontStyle( FontType.BOLD_ITALIC );\r
323         }\r
324         else {\r
325             setFontStyle( FontType.PLAIN );\r
326         }\r
327     }\r
328 \r
329     public final void setShape( final NodeShape shape ) {\r
330         _shape = shape;\r
331     }\r
332 \r
333     public final void setShape( final String shape ) {\r
334         if ( shape.equalsIgnoreCase( NODE_SHAPE_CIRCLE ) ) {\r
335             setShape( NodeShape.CIRCLE );\r
336         }\r
337         else if ( shape.equalsIgnoreCase( NODE_SHAPE_RECTANGLE ) ) {\r
338             setShape( NodeShape.RECTANGLE );\r
339         }\r
340         else {\r
341             setShape( NodeShape.DEFAULT );\r
342         }\r
343     }\r
344 \r
345     public final void setSize( final float size ) {\r
346         if ( ( size != DEFAULT_SIZE ) && ( size < 0 ) ) {\r
347             throw new IllegalArgumentException( "negative size: " + size );\r
348         }\r
349         _size = size;\r
350     }\r
351 \r
352     public final void setTransparency( final float transparency ) {\r
353         _transparency = transparency;\r
354     }\r
355 \r
356     @Override\r
357     public final StringBuffer toNHX() {\r
358         throw new UnsupportedOperationException();\r
359     }\r
360 \r
361     @Override\r
362     public final void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException {\r
363         for( final Property p : toProperties() ) {\r
364             p.toPhyloXML( writer, level, indentation );\r
365         }\r
366     }\r
367 \r
368     @Override\r
369     public final String toString() {\r
370         return asText().toString();\r
371     }\r
372 \r
373     private String colorToHex( final Color c ) {\r
374         return String.format( "#%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue() );\r
375     }\r
376 \r
377     private final void init() {\r
378         setFontName( null );\r
379         setFontStyle( FontType.PLAIN );\r
380         setFontSize( DEFAULT_FONT_SIZE );\r
381         setFontColor( null );\r
382         setShape( NodeShape.DEFAULT );\r
383         setFillType( NodeFill.DEFAULT );\r
384         setBorderColor( null );\r
385         setFillColor( null );\r
386         setSize( DEFAULT_SIZE );\r
387         setTransparency( DEFAULT_TRANSPARENCY );\r
388         _font = null;\r
389     }\r
390 \r
391     private final List<Property> toProperties() {\r
392         final List<Property> properties = new ArrayList<Property>();\r
393         if ( !ForesterUtil.isEmpty( getFontName() ) ) {\r
394             properties.add( new Property( FONT_REF, getFontName(), "", FONT_TYPE, AppliesTo.NODE ) );\r
395         }\r
396         if ( getFontSize() != DEFAULT_FONT_SIZE ) {\r
397             properties.add( new Property( FONT_SIZE_REF,\r
398                                           String.valueOf( getFontSize() ),\r
399                                           "",\r
400                                           FONT_SIZE_TYPE,\r
401                                           AppliesTo.NODE ) );\r
402         }\r
403         if ( getFontStyle() != FontType.PLAIN ) {\r
404             String font_style = "";\r
405             if ( getFontStyle() == FontType.ITALIC ) {\r
406                 font_style = FONT_STYLE_ITALIC;\r
407             }\r
408             else if ( getFontStyle() == FontType.BOLD ) {\r
409                 font_style = FONT_STYLE_BOLD;\r
410             }\r
411             else if ( getFontStyle() == FontType.BOLD_ITALIC ) {\r
412                 font_style = FONT_STYLE_BOLD_ITALIC;\r
413             }\r
414             else {\r
415                 throw new RuntimeException( "unknown font style" + getShape() );\r
416             }\r
417             properties.add( new Property( FONT_STYLE_REF, font_style, "", FONT_STYLE_TYPE, AppliesTo.NODE ) );\r
418         }\r
419         if ( getFontColor() != null ) {\r
420             properties.add( new Property( FONT_COLOR_REF,\r
421                                           colorToHex( getFontColor() ),\r
422                                           "",\r
423                                           FONT_COLOR_TYPE,\r
424                                           AppliesTo.NODE ) );\r
425         }\r
426         if ( getShape() != NodeShape.DEFAULT ) {\r
427             String shape = null;\r
428             if ( getShape() == NodeShape.RECTANGLE ) {\r
429                 shape = NODE_SHAPE_RECTANGLE;\r
430             }\r
431             else if ( getShape() == NodeShape.CIRCLE ) {\r
432                 shape = NODE_SHAPE_CIRCLE;\r
433             }\r
434             else {\r
435                 throw new RuntimeException( "unknown node shape" + getShape() );\r
436             }\r
437             properties.add( new Property( NODE_SHAPE_REF, shape, "", NODE_SHAPE_TYPE, AppliesTo.NODE ) );\r
438         }\r
439         if ( getSize() != DEFAULT_SIZE ) {\r
440             properties.add( new Property( NODE_SIZE_REF,\r
441                                           String.valueOf( getSize() ),\r
442                                           "",\r
443                                           NODE_SIZE_TYPE,\r
444                                           AppliesTo.NODE ) );\r
445         }\r
446         if ( getFillColor() != null ) {\r
447             properties.add( new Property( NODE_FILL_COLOR_REF,\r
448                                           colorToHex( getFillColor() ),\r
449                                           "",\r
450                                           NODE_FILL_COLOR_TYPE,\r
451                                           AppliesTo.NODE ) );\r
452         }\r
453         if ( getBorderColor() != null ) {\r
454             properties.add( new Property( NODE_BORDER_COLOR_REF,\r
455                                           colorToHex( getBorderColor() ),\r
456                                           "",\r
457                                           NODE_BORDER_COLOR_TYPE,\r
458                                           AppliesTo.NODE ) );\r
459         }\r
460         if ( getFillType() != NodeFill.DEFAULT ) {\r
461             String fill = null;\r
462             if ( getFillType() == NodeFill.GRADIENT ) {\r
463                 fill = NODE_FILL_GRADIENT;\r
464             }\r
465             else if ( getFillType() == NodeFill.NONE ) {\r
466                 fill = NODE_FILL_NONE;\r
467             }\r
468             else if ( getFillType() == NodeFill.SOLID ) {\r
469                 fill = NODE_FILL_SOLID;\r
470             }\r
471             else {\r
472                 throw new RuntimeException( "unknown fill type " + getFillType() );\r
473             }\r
474             properties.add( new Property( NODE_FILL_TYPE_REF, fill, "", NODE_FILL_TYPE_TYPE, AppliesTo.NODE ) );\r
475         }\r
476         if ( getTransparency() != DEFAULT_TRANSPARENCY ) {\r
477             properties.add( new Property( NODE_TRANSPARENCY_REF,\r
478                                           String.valueOf( getTransparency() ),\r
479                                           "",\r
480                                           NODE_TRANSPARENCY_TYPE,\r
481                                           AppliesTo.NODE ) );\r
482         }\r
483         return properties;\r
484     }\r
485 \r
486     public enum FontType {\r
487         BOLD, BOLD_ITALIC, ITALIC, PLAIN\r
488     }\r
489 \r
490     public enum NodeFill {\r
491         DEFAULT, GRADIENT, NONE, SOLID\r
492     }\r
493 \r
494     public enum NodeShape {\r
495         CIRCLE, DEFAULT, RECTANGLE\r
496     }\r
497 }\r