package org.forester.phylogeny.data; import java.awt.Color; import java.awt.Font; import java.io.IOException; import java.io.Writer; import java.util.ArrayList; import java.util.List; import org.forester.phylogeny.data.Property.AppliesTo; import org.forester.util.ForesterUtil; public final class NodeVisualData implements PhylogenyData { public static final String APTX_VISUALIZATION_REF = "style:"; public static final int DEFAULT_SIZE = -1; public static final String FONT_COLOR_REF = APTX_VISUALIZATION_REF + "font_color"; public static final String FONT_COLOR_TYPE = "xsd:token"; public static final String FONT_REF = APTX_VISUALIZATION_REF + "font"; public static final String FONT_SIZE_REF = APTX_VISUALIZATION_REF + "font_size"; public static final String FONT_SIZE_TYPE = "xsd:unsignedByte"; public static final String FONT_STYLE_BOLD = "bold"; public static final String FONT_STYLE_BOLD_ITALIC = "bold_italic"; public static final String FONT_STYLE_ITALIC = "italic"; public static final String FONT_STYLE_PLAIN = "plain"; public static final String FONT_STYLE_REF = APTX_VISUALIZATION_REF + "font_style"; public static final String FONT_STYLE_TYPE = "xsd:token"; public static final String FONT_TYPE = "xsd:token"; public static final String NODE_COLOR_REF = APTX_VISUALIZATION_REF + "node_color"; public static final String NODE_COLOR_TYPE = "xsd:token"; public static final String NODE_FILL_GRADIENT = "gradient"; public static final String NODE_FILL_NONE = "none"; public static final String NODE_FILL_SOLID = "solid"; public static final String NODE_FILL_TYPE_REF = APTX_VISUALIZATION_REF + "node_fill_type"; public static final String NODE_FILL_TYPE_TYPE = "xsd:token"; public static final String NODE_SHAPE_CIRCLE = "circle"; public static final String NODE_SHAPE_RECTANGLE = "rectangle"; public static final String NODE_SHAPE_REF = APTX_VISUALIZATION_REF + "node_shape"; public static final String NODE_SHAPE_TYPE = "xsd:token"; public static final String NODE_SIZE_REF = APTX_VISUALIZATION_REF + "node_size"; public static final String NODE_SIZE_TYPE = "xsd:float"; public static final String NODE_TRANSPARENCY_REF = APTX_VISUALIZATION_REF + "node_transparency"; public static final String NODE_TRANSPARENCY_TYPE = "xsd:float"; private static final byte DEFAULT_FONT_SIZE = -1; private static final int DEFAULT_TRANSPARENCY = -1; private NodeFill _fill_type; private Font _font; private Color _font_color; private String _font_name; private byte _font_size; private FontType _font_style; private Color _node_color; private NodeShape _shape; private float _size; private float _transparency; public NodeVisualData() { init(); } public NodeVisualData( final String font_name, final FontType font_style, final byte font_size, final Color font_color, final NodeShape shape, final NodeFill fill_type, final Color node_color, final float size, final float transparency ) { setFontName( font_name ); setFontStyle( font_style ); setFontSize( font_size ); setFontColor( font_color ); setShape( shape ); setFillType( fill_type ); setNodeColor( node_color ); setSize( size ); setTransparency( transparency ); } @Override public final StringBuffer asSimpleText() { return asText(); } @Override public final StringBuffer asText() { final StringBuffer sb = new StringBuffer(); return sb; } @Override public final PhylogenyData copy() { return new NodeVisualData( !ForesterUtil.isEmpty( getFontName() ) ? new String( getFontName() ) : null, getFontStyle(), getFontSize(), getFontColor() != null ? new Color( getFontColor().getRed(), getFontColor() .getGreen(), getFontColor().getBlue() ) : null, getShape(), getFillType(), getNodeColor() != null ? new Color( getNodeColor().getRed(), getNodeColor() .getGreen(), getNodeColor().getBlue() ) : null, getSize(), getTransparency() ); } public final NodeFill getFillType() { return _fill_type; } public final Font getFont() { if ( _font != null ) { return _font; } else if ( !ForesterUtil.isEmpty( getFontName() ) ) { _font = new Font( getFontName(), getFontStyleInt(), getFontSize() ); return _font; } return null; } public final Color getFontColor() { return _font_color; } public final String getFontName() { return _font_name; } public final byte getFontSize() { return _font_size; } public final FontType getFontStyle() { return _font_style; } public final int getFontStyleInt() { if ( getFontStyle() == FontType.BOLD ) { return Font.BOLD; } else if ( getFontStyle() == FontType.ITALIC ) { return Font.ITALIC; } else if ( getFontStyle() == FontType.BOLD_ITALIC ) { return Font.BOLD + Font.ITALIC; } return Font.PLAIN; } public final Color getNodeColor() { return _node_color; } public final NodeShape getShape() { return _shape; } public final float getSize() { return _size; } public final float getTransparency() { return _transparency; } public final boolean isEmpty() { return ( ForesterUtil.isEmpty( getFontName() ) && ( getFontStyle() == FontType.PLAIN ) && ( getFontSize() == DEFAULT_FONT_SIZE ) && ( getFontColor() == null ) && ( getShape() == NodeShape.DEFAULT ) && ( getFillType() == NodeFill.DEFAULT ) && ( getNodeColor() == null ) && ( getSize() == DEFAULT_SIZE ) && ( getTransparency() == DEFAULT_TRANSPARENCY ) ); } @Override public final boolean isEqual( final PhylogenyData data ) { throw new UnsupportedOperationException(); } public void parseProperty( final Property prop ) { if ( prop.getRef().equals( FONT_REF ) ) { setFontName( prop.getValue().trim() ); } else if ( prop.getRef().equals( FONT_SIZE_REF ) ) { int s = -1; try { s = Integer.parseInt( prop.getValue() ); } catch ( final NumberFormatException e ) { return; } if ( ( s >= 0 ) && ( s < Byte.MAX_VALUE ) ) { setFontSize( s ); } } else if ( prop.getRef().equals( FONT_STYLE_REF ) ) { setFontStyle( prop.getValue() ); } else if ( prop.getRef().equals( FONT_COLOR_REF ) ) { try { setFontColor( Color.decode( prop.getValue() ) ); } catch ( final NumberFormatException e ) { return; } } else if ( prop.getRef().equals( NODE_SIZE_REF ) ) { float s = -1.0f; try { s = Float.parseFloat( prop.getValue() ); } catch ( final NumberFormatException e ) { return; } if ( s >= 0 ) { setSize( s ); } } else if ( prop.getRef().equals( NODE_COLOR_REF ) ) { try { setNodeColor( Color.decode( prop.getValue() ) ); } catch ( final NumberFormatException e ) { return; } } else if ( prop.getRef().equals( NODE_SHAPE_REF ) ) { setShape( prop.getValue() ); } else if ( prop.getRef().equals( NODE_FILL_TYPE_REF ) ) { setFillType( prop.getValue() ); } } public final void setFillType( final NodeFill fill_type ) { _fill_type = fill_type; } public final void setFillType( final String fill ) { if ( fill.equalsIgnoreCase( NODE_FILL_NONE ) ) { setFillType( NodeFill.NONE ); } else if ( fill.equalsIgnoreCase( NODE_FILL_SOLID ) ) { setFillType( NodeFill.SOLID ); } else if ( fill.equalsIgnoreCase( NODE_FILL_GRADIENT ) ) { setFillType( NodeFill.GRADIENT ); } else { setFillType( NodeFill.DEFAULT ); } } public final void setFontColor( final Color font_color ) { _font_color = font_color; } public final void setFontName( final String font_name ) { if ( !ForesterUtil.isEmpty( font_name ) ) { _font_name = font_name; } else { _font_name = null; } _font = null; } public final void setFontSize( final int font_size ) { if ( ( font_size != DEFAULT_FONT_SIZE ) && ( font_size < 0 ) ) { throw new IllegalArgumentException( "negative font size: " + font_size ); } else if ( font_size > Byte.MAX_VALUE ) { throw new IllegalArgumentException( "font size is too large: " + font_size ); } _font_size = ( byte ) font_size; _font = null; } public final void setFontStyle( final FontType font_style ) { _font_style = font_style; _font = null; } public final void setFontStyle( final int font_style ) { if ( ( font_style == ( Font.BOLD + Font.ITALIC ) ) ) { setFontStyle( FontType.BOLD_ITALIC ); } else if ( font_style == Font.ITALIC ) { setFontStyle( FontType.ITALIC ); } else if ( font_style == Font.BOLD ) { setFontStyle( FontType.BOLD ); } else { setFontStyle( FontType.PLAIN ); } } public final void setFontStyle( final String font_style ) { if ( font_style.equalsIgnoreCase( FONT_STYLE_BOLD ) ) { setFontStyle( FontType.BOLD ); } else if ( font_style.equalsIgnoreCase( FONT_STYLE_ITALIC ) ) { setFontStyle( FontType.ITALIC ); } else if ( font_style.equalsIgnoreCase( FONT_STYLE_BOLD_ITALIC ) ) { setFontStyle( FontType.BOLD_ITALIC ); } else { setFontStyle( FontType.PLAIN ); } } public final void setNodeColor( final Color node_color ) { _node_color = node_color; } public final void setShape( final NodeShape shape ) { _shape = shape; } public final void setShape( final String shape ) { if ( shape.equalsIgnoreCase( NODE_SHAPE_CIRCLE ) ) { setShape( NodeShape.CIRCLE ); } else if ( shape.equalsIgnoreCase( NODE_SHAPE_RECTANGLE ) ) { setShape( NodeShape.RECTANGLE ); } else { setShape( NodeShape.DEFAULT ); } } public final void setSize( final float size ) { if ( ( size != DEFAULT_SIZE ) && ( size < 0 ) ) { throw new IllegalArgumentException( "negative size: " + size ); } _size = size; } public final void setTransparency( final float transparency ) { _transparency = transparency; } @Override public final StringBuffer toNHX() { throw new UnsupportedOperationException(); } @Override public final void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException { for( final Property p : toProperties() ) { p.toPhyloXML( writer, level, indentation ); } } @Override public final String toString() { return asText().toString(); } private String colorToHex( final Color c ) { return String.format( "#%02x%02x%02x", c.getRed(), c.getGreen(), c.getBlue() ); } private final void init() { setFontName( null ); setFontStyle( FontType.PLAIN ); setFontSize( DEFAULT_FONT_SIZE ); setFontColor( null ); setShape( NodeShape.DEFAULT ); setFillType( NodeFill.DEFAULT ); setNodeColor( null ); setSize( DEFAULT_SIZE ); setTransparency( DEFAULT_TRANSPARENCY ); _font = null; } private final List toProperties() { final List properties = new ArrayList(); if ( !ForesterUtil.isEmpty( getFontName() ) ) { properties.add( new Property( FONT_REF, getFontName(), "", FONT_TYPE, AppliesTo.NODE ) ); } if ( getFontSize() != DEFAULT_FONT_SIZE ) { properties.add( new Property( FONT_SIZE_REF, String.valueOf( getFontSize() ), "", FONT_SIZE_TYPE, AppliesTo.NODE ) ); } if ( getFontStyle() != FontType.PLAIN ) { String font_style = ""; if ( getFontStyle() == FontType.ITALIC ) { font_style = FONT_STYLE_ITALIC; } else if ( getFontStyle() == FontType.BOLD ) { font_style = FONT_STYLE_BOLD; } else if ( getFontStyle() == FontType.BOLD_ITALIC ) { font_style = FONT_STYLE_BOLD_ITALIC; } else { throw new RuntimeException( "unknown font style" + getShape() ); } properties.add( new Property( FONT_STYLE_REF, font_style, "", FONT_STYLE_TYPE, AppliesTo.NODE ) ); } if ( getFontColor() != null ) { properties.add( new Property( FONT_COLOR_REF, colorToHex( getFontColor() ), "", FONT_COLOR_TYPE, AppliesTo.NODE ) ); } if ( getShape() != NodeShape.DEFAULT ) { String shape = null; if ( getShape() == NodeShape.RECTANGLE ) { shape = NODE_SHAPE_RECTANGLE; } else if ( getShape() == NodeShape.CIRCLE ) { shape = NODE_SHAPE_CIRCLE; } else { throw new RuntimeException( "unknown node shape" + getShape() ); } properties.add( new Property( NODE_SHAPE_REF, shape, "", NODE_SHAPE_TYPE, AppliesTo.NODE ) ); } if ( getSize() != DEFAULT_SIZE ) { properties.add( new Property( NODE_SIZE_REF, String.valueOf( getSize() ), "", NODE_SIZE_TYPE, AppliesTo.NODE ) ); } if ( getNodeColor() != null ) { properties.add( new Property( NODE_COLOR_REF, colorToHex( getNodeColor() ), "", NODE_COLOR_TYPE, AppliesTo.NODE ) ); } if ( getFillType() != NodeFill.DEFAULT ) { String fill = null; if ( getFillType() == NodeFill.GRADIENT ) { fill = NODE_FILL_GRADIENT; } else if ( getFillType() == NodeFill.NONE ) { fill = NODE_FILL_NONE; } else if ( getFillType() == NodeFill.SOLID ) { fill = NODE_FILL_SOLID; } else { throw new RuntimeException( "unknown fill type " + getFillType() ); } properties.add( new Property( NODE_FILL_TYPE_REF, fill, "", NODE_FILL_TYPE_TYPE, AppliesTo.NODE ) ); } if ( getTransparency() != DEFAULT_TRANSPARENCY ) { properties.add( new Property( NODE_TRANSPARENCY_REF, String.valueOf( getTransparency() ), "", NODE_TRANSPARENCY_TYPE, AppliesTo.NODE ) ); } return properties; } public enum FontType { BOLD, BOLD_ITALIC, ITALIC, PLAIN } public enum NodeFill { DEFAULT, GRADIENT, NONE, SOLID } public enum NodeShape { CIRCLE, DEFAULT, RECTANGLE } }