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