+ else {
+ if ( ( factor == 0 ) || isNonLinedUpCladogram() ) {
+ return getXdistance();
+ }
+ return getXdistance() * factor;
+ }
+ }
+
+ final private Color calculateColorForAnnotation( final SortedSet<Annotation> ann ) {
+ Color c = getTreeColorSet().getAnnotationColor();
+ if ( getControlPanel().isColorAccordingToAnnotation() && ( getControlPanel().getAnnotationColors() != null ) ) {
+ final StringBuilder sb = new StringBuilder();
+ for( final Annotation a : ann ) {
+ sb.append( !ForesterUtil.isEmpty( a.getRef() ) ? a.getRef() : a.getDesc() );
+ }
+ final String ann_str = sb.toString();
+ if ( !ForesterUtil.isEmpty( ann_str ) ) {
+ c = getControlPanel().getAnnotationColors().get( ann_str );
+ if ( c == null ) {
+ c = AptxUtil.calculateColorFromString( ann_str );
+ getControlPanel().getAnnotationColors().put( ann_str, c );
+ }
+ if ( c == null ) {
+ c = getTreeColorSet().getAnnotationColor();
+ }
+ }
+ }
+ return c;
+ }
+
+ final private float calculateOvBranchLengthToParent( final PhylogenyNode node, final int factor ) {
+ if ( getControlPanel().isDrawPhylogram() ) {
+ if ( node.getDistanceToParent() < 0.0 ) {
+ return 0.0f;
+ }
+ return ( float ) ( getOvXcorrectionFactor() * node.getDistanceToParent() );
+ }
+ else {
+ if ( ( factor == 0 ) || isNonLinedUpCladogram() ) {
+ return getOvXDistance();
+ }
+ return getOvXDistance() * factor;
+ }
+ }
+
+ final private void cannotOpenBrowserWarningMessage( final String type_type ) {
+ JOptionPane.showMessageDialog( this,
+ "Cannot launch web browser for " + type_type + " data of this node",
+ "Cannot launch web browser",
+ JOptionPane.WARNING_MESSAGE );
+ }
+
+ final private void colorizeSubtree( final Color c, final PhylogenyNode node ) {
+ if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+ JOptionPane.showMessageDialog( this,
+ "Cannot colorize subtree in unrooted display type",
+ "Attempt to colorize subtree in unrooted display",
+ JOptionPane.WARNING_MESSAGE );
+ return;
+ }
+ _control_panel.setColorBranches( true );
+ if ( _control_panel.getColorBranchesCb() != null ) {
+ _control_panel.getColorBranchesCb().setSelected( true );
+ }
+ for( final PreorderTreeIterator it = new PreorderTreeIterator( node ); it.hasNext(); ) {
+ it.next().getBranchData().setBranchColor( new BranchColor( c ) );
+ }
+ repaint();
+ }
+
+ final private void colorSubtree( final PhylogenyNode node ) {
+ Color intitial_color = null;
+ if ( getControlPanel().isColorBranches() && ( PhylogenyMethods.getBranchColorValue( node ) != null )
+ && ( ( ( !node.isRoot() && ( node.getParent().getNumberOfDescendants() < 3 ) ) ) || ( node.isRoot() ) ) ) {
+ intitial_color = PhylogenyMethods.getBranchColorValue( node );
+ }
+ else {
+ intitial_color = getTreeColorSet().getBranchColor();
+ }
+ _color_chooser.setColor( intitial_color );
+ _color_chooser.setPreviewPanel( new JPanel() );
+ final JDialog dialog = JColorChooser
+ .createDialog( this,
+ "Subtree colorization",
+ true,
+ _color_chooser,
+ new SubtreeColorizationActionListener( _color_chooser, node ),
+ null );
+ dialog.setVisible( true );
+ }
+
+ final private void copySubtree( final PhylogenyNode node ) {
+ if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+ errorMessageNoCutCopyPasteInUnrootedDisplay();
+ return;
+ }
+ setNodeInPreorderToNull();
+ setCutOrCopiedTree( _phylogeny.copy( node ) );
+ final List<PhylogenyNode> nodes = PhylogenyMethods.getAllDescendants( node );
+ final Set<Long> node_ids = new HashSet<Long>( nodes.size() );
+ for( final PhylogenyNode n : nodes ) {
+ node_ids.add( n.getId() );
+ }
+ node_ids.add( node.getId() );
+ setCopiedAndPastedNodes( node_ids );
+ repaint();
+ }
+
+ private String createAnnotationString( final SortedSet<Annotation> ann ) {
+ final StringBuilder sb = new StringBuilder();
+ boolean first = true;
+ for( final Annotation a : ann ) {
+ if ( !first ) {
+ sb.append( "+" );
+ }
+ else {
+ first = false;
+ }
+ sb.append( a.asSimpleText() );
+ }
+ final String ann_str = sb.toString();
+ return ann_str;
+ }
+
+ final private String createASimpleTextRepresentationOfANode( final PhylogenyNode node ) {
+ final String tax = PhylogenyMethods.getSpecies( node );
+ String label = node.getName();
+ if ( !ForesterUtil.isEmpty( label ) && !ForesterUtil.isEmpty( tax ) ) {
+ label = label + " " + tax;
+ }
+ else if ( !ForesterUtil.isEmpty( tax ) ) {
+ label = tax;
+ }
+ else {
+ label = "";
+ }
+ if ( !ForesterUtil.isEmpty( label ) ) {
+ label = " [" + label + "]";
+ }
+ return label;
+ }
+
+ final private void cutSubtree( final PhylogenyNode node ) {
+ if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+ errorMessageNoCutCopyPasteInUnrootedDisplay();
+ return;
+ }
+ if ( node.isRoot() ) {
+ JOptionPane.showMessageDialog( this,
+ "Cannot cut entire tree as subtree",
+ "Attempt to cut entire tree",
+ JOptionPane.ERROR_MESSAGE );
+ return;
+ }
+ final String label = createASimpleTextRepresentationOfANode( node );
+ final int r = JOptionPane.showConfirmDialog( null,
+ "Cut subtree" + label + "?",
+ "Confirm Cutting of Subtree",
+ JOptionPane.YES_NO_OPTION );
+ if ( r != JOptionPane.OK_OPTION ) {
+ return;
+ }
+ setNodeInPreorderToNull();
+ setCopiedAndPastedNodes( null );
+ setCutOrCopiedTree( _phylogeny.copy( node ) );
+ _phylogeny.deleteSubtree( node, true );
+ _phylogeny.clearHashIdToNodeMap();
+ _phylogeny.recalculateNumberOfExternalDescendants( true );
+ resetNodeIdToDistToLeafMap();
+ setEdited( true );
+ repaint();
+ }
+
+ final private void cycleColors() {
+ getMainPanel().getTreeColorSet().cycleColorScheme();
+ for( final TreePanel tree_panel : getMainPanel().getTreePanels() ) {
+ tree_panel.setBackground( getMainPanel().getTreeColorSet().getBackgroundColor() );
+ }
+ }
+
+ final private void decreaseOvSize() {
+ if ( ( getOvMaxWidth() > 20 ) && ( getOvMaxHeight() > 20 ) ) {
+ setOvMaxWidth( getOvMaxWidth() - 5 );
+ setOvMaxHeight( getOvMaxHeight() - 5 );
+ updateOvSettings();
+ getControlPanel().displayedPhylogenyMightHaveChanged( false );
+ }
+ }
+
+ final private void deleteNodeOrSubtree( final PhylogenyNode node ) {
+ if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+ errorMessageNoCutCopyPasteInUnrootedDisplay();
+ return;
+ }
+ if ( node.isRoot() && ( node.getNumberOfDescendants() != 1 ) ) {
+ JOptionPane.showMessageDialog( this,
+ "Cannot delete entire tree",
+ "Attempt to delete entire tree",
+ JOptionPane.ERROR_MESSAGE );
+ return;
+ }
+ final String label = createASimpleTextRepresentationOfANode( node );
+ final Object[] options = { "Node only", "Entire subtree", "Cancel" };
+ final int r = JOptionPane.showOptionDialog( this,
+ "Delete" + label + "?",
+ "Delete Node/Subtree",
+ JOptionPane.CLOSED_OPTION,
+ JOptionPane.QUESTION_MESSAGE,
+ null,
+ options,
+ options[ 2 ] );
+ setNodeInPreorderToNull();
+ boolean node_only = true;
+ if ( r == 1 ) {
+ node_only = false;
+ }
+ else if ( r != 0 ) {
+ return;
+ }
+ if ( node_only ) {
+ PhylogenyMethods.removeNode( node, _phylogeny );
+ }
+ else {
+ _phylogeny.deleteSubtree( node, true );
+ }
+ _phylogeny.externalNodesHaveChanged();
+ _phylogeny.clearHashIdToNodeMap();
+ _phylogeny.recalculateNumberOfExternalDescendants( true );
+ resetNodeIdToDistToLeafMap();
+ setEdited( true );
+ repaint();
+ }
+
+ final private void displayNodePopupMenu( final PhylogenyNode node, final int x, final int y ) {
+ makePopupMenus( node );
+ _node_popup_menu.putClientProperty( NODE_POPMENU_NODE_CLIENT_PROPERTY, node );
+ _node_popup_menu.show( this, x, y );
+ }
+
+ final private void drawArc( final double x,
+ final double y,
+ final double width,
+ final double heigth,
+ final double start_angle,
+ final double arc_angle,
+ final Graphics2D g ) {
+ _arc.setArc( x, y, width, heigth, _180_OVER_PI * start_angle, _180_OVER_PI * arc_angle, Arc2D.OPEN );
+ g.draw( _arc );
+ }
+
+ final private void drawLine( final double x1, final double y1, final double x2, final double y2, final Graphics2D g ) {
+ if ( ( x1 == x2 ) && ( y1 == y2 ) ) {
+ return;
+ }
+ _line.setLine( x1, y1, x2, y2 );
+ g.draw( _line );
+ }
+
+ final private void drawOval( final double x,
+ final double y,
+ final double width,
+ final double heigth,
+ final Graphics2D g ) {
+ _ellipse.setFrame( x, y, width, heigth );
+ g.draw( _ellipse );
+ }
+
+ final private void drawOvalFilled( final double x,
+ final double y,
+ final double width,
+ final double heigth,
+ final Graphics2D g ) {
+ _ellipse.setFrame( x, y, width, heigth );
+ g.fill( _ellipse );
+ }
+
+ final private void drawOvalGradient( final double x,
+ final double y,
+ final double width,
+ final double heigth,
+ final Graphics2D g,
+ final Color color_1,
+ final Color color_2,
+ final Color color_border ) {
+ _ellipse.setFrame( x, y, width, heigth );
+ g.setPaint( new GradientPaint( ( float ) x,
+ ( float ) y,
+ color_1,
+ ( float ) ( x + width ),
+ ( float ) ( y + heigth ),
+ color_2,
+ false ) );
+ g.fill( _ellipse );
+ if ( color_border != null ) {
+ g.setPaint( color_border );
+ g.draw( _ellipse );
+ }
+ }
+
+ final private void drawRect( final float x, final float y, final float width, final float heigth, final Graphics2D g ) {
+ _rectangle.setFrame( x, y, width, heigth );
+ g.draw( _rectangle );
+ }
+
+ final private void drawRectFilled( final double x,
+ final double y,
+ final double width,
+ final double heigth,
+ final Graphics2D g ) {
+ _rectangle.setFrame( x, y, width, heigth );
+ g.fill( _rectangle );
+ }
+
+ final private void drawRectGradient( final double x,
+ final double y,
+ final double width,
+ final double heigth,
+ final Graphics2D g,
+ final Color color_1,
+ final Color color_2,
+ final Color color_border ) {
+ _rectangle.setFrame( x, y, width, heigth );
+ g.setPaint( new GradientPaint( ( float ) x,
+ ( float ) y,
+ color_1,
+ ( float ) ( x + width ),
+ ( float ) ( y + heigth ),
+ color_2,
+ false ) );
+ g.fill( _rectangle );
+ if ( color_border != null ) {
+ g.setPaint( color_border );
+ g.draw( _rectangle );
+ }
+ }
+
+ private double drawTaxonomyImage( final double x, final double y, final PhylogenyNode node, final Graphics2D g ) {
+ final List<Uri> us = new ArrayList<Uri>();
+ for( final Taxonomy t : node.getNodeData().getTaxonomies() ) {
+ for( final Uri uri : t.getUris() ) {
+ us.add( uri );
+ }
+ }
+ double offset = 0;
+ for( final Uri uri : us ) {
+ if ( uri != null ) {
+ final String uri_str = uri.getValue().toString().toLowerCase();
+ if ( getImageMap().containsKey( uri_str ) ) {
+ final BufferedImage bi = getImageMap().get( uri_str );
+ if ( ( bi != null ) && ( bi.getHeight() > 5 ) && ( bi.getWidth() > 5 ) ) {
+ double scaling_factor = 1;
+ if ( getOptions().isAllowMagnificationOfTaxonomyImages()
+ || ( bi.getHeight() > ( 1.8 * getYdistance() ) ) ) {
+ scaling_factor = ( 1.8 * getYdistance() ) / bi.getHeight();
+ }
+ // y = y - ( 0.9 * getYdistance() );
+ final double hs = bi.getHeight() * scaling_factor;
+ double ws = ( bi.getWidth() * scaling_factor ) + offset;
+ final double my_y = y - ( 0.5 * hs );
+ final int x_w = ( int ) ( x + ws + 0.5 );
+ final int y_h = ( int ) ( my_y + hs + 0.5 );
+ if ( ( ( x_w - x ) > 7 ) && ( ( y_h - my_y ) > 7 ) ) {
+ g.drawImage( bi,
+ ( int ) ( x + 0.5 + offset ),
+ ( int ) ( my_y + 0.5 ),
+ x_w,
+ y_h,
+ 0,
+ 0,
+ bi.getWidth(),
+ bi.getHeight(),
+ null );
+ ws += 8;
+ }
+ else {
+ ws = 0.0;
+ }
+ offset = ws;
+ }
+ }
+ }
+ }
+ return offset;
+ }
+
+ final private void errorMessageNoCutCopyPasteInUnrootedDisplay() {
+ JOptionPane.showMessageDialog( this,
+ "Cannot cut, copy, paste, add, or delete subtrees/nodes in unrooted display",
+ "Attempt to cut/copy/paste/add/delete in unrooted display",
+ JOptionPane.ERROR_MESSAGE );
+ }
+
+ final private Set<Long> getCopiedAndPastedNodes() {
+ return getMainPanel().getCopiedAndPastedNodes();
+ }
+
+ final private Set<Long> getCurrentExternalNodes() {
+ return _current_external_nodes;
+ }
+
+ final private Phylogeny getCutOrCopiedTree() {
+ return getMainPanel().getCutOrCopiedTree();
+ }
+
+ final private float getLastDragPointX() {
+ return _last_drag_point_x;
+ }
+
+ final private float getLastDragPointY() {
+ return _last_drag_point_y;
+ }
+
+ final private short getMaxBranchesToLeaf( final PhylogenyNode node ) {
+ if ( !_nodeid_dist_to_leaf.containsKey( node.getId() ) ) {
+ final short m = PhylogenyMethods.calculateMaxBranchesToLeaf( node );
+ _nodeid_dist_to_leaf.put( node.getId(), m );
+ return m;
+ }
+ else {
+ return _nodeid_dist_to_leaf.get( node.getId() );
+ }
+ }
+
+ final private double getMaxDistanceToRoot() {
+ if ( _max_distance_to_root < 0 ) {
+ recalculateMaxDistanceToRoot();
+ }
+ return _max_distance_to_root;
+ }
+
+ final private float getOvMaxHeight() {
+ return _ov_max_height;
+ }
+
+ final private float getOvMaxWidth() {
+ return _ov_max_width;
+ }
+
+ final private float getOvXcorrectionFactor() {
+ return _ov_x_correction_factor;
+ }
+
+ final private float getOvXDistance() {
+ return _ov_x_distance;
+ }
+
+ final private int getOvXPosition() {
+ return _ov_x_position;
+ }
+
+ final private float getOvYDistance() {
+ return _ov_y_distance;
+ }
+
+ final private int getOvYPosition() {
+ return _ov_y_position;
+ }
+
+ final private int getOvYStart() {
+ return _ov_y_start;
+ }
+
+ final private double getScaleDistance() {
+ return _scale_distance;
+ }
+
+ final private String getScaleLabel() {
+ return _scale_label;
+ }
+
+ final private TreeFontSet getTreeFontSet() {
+ return getMainPanel().getTreeFontSet();
+ }
+
+ final private float getUrtFactor() {
+ return _urt_factor;
+ }
+
+ final private float getUrtFactorOv() {
+ return _urt_factor_ov;
+ }
+
+ final private void handleClickToAction( final NodeClickAction action, final PhylogenyNode node ) {
+ switch ( action ) {
+ case SHOW_DATA:
+ showNodeFrame( node );
+ break;
+ case COLLAPSE:
+ collapse( node );
+ break;
+ case REROOT:
+ reRoot( node );
+ break;
+ case SUBTREE:
+ subTree( node );
+ break;
+ case SWAP:
+ swap( node );
+ break;
+ case COLOR_SUBTREE:
+ colorSubtree( node );
+ break;
+ case OPEN_SEQ_WEB:
+ openSeqWeb( node );
+ break;
+ case BLAST:
+ blast( node );
+ break;
+ case OPEN_TAX_WEB:
+ openTaxWeb( node );
+ break;
+ case CUT_SUBTREE:
+ cutSubtree( node );
+ break;
+ case COPY_SUBTREE:
+ copySubtree( node );
+ break;
+ case PASTE_SUBTREE:
+ pasteSubtree( node );
+ break;
+ case DELETE_NODE_OR_SUBTREE:
+ deleteNodeOrSubtree( node );
+ break;
+ case ADD_NEW_NODE:
+ addEmptyNode( node );
+ break;
+ case EDIT_NODE_DATA:
+ showNodeEditFrame( node );
+ break;
+ case SELECT_NODES:
+ selectNode( node );
+ break;
+ case SORT_DESCENDENTS:
+ sortDescendants( node );
+ break;
+ case GET_EXT_DESC_DATA:
+ showExtDescNodeData( node );
+ break;
+ default:
+ throw new IllegalArgumentException( "unknown action: " + action );
+ }
+ }
+
+ final private void increaseCurrentExternalNodesDataBufferChangeCounter() {
+ _current_external_nodes_data_buffer_change_counter++;
+ }
+
+ final private void increaseOvSize() {
+ if ( ( getOvMaxWidth() < ( getMainPanel().getCurrentScrollPane().getViewport().getVisibleRect().getWidth() / 2 ) )
+ && ( getOvMaxHeight() < ( getMainPanel().getCurrentScrollPane().getViewport().getVisibleRect()
+ .getHeight() / 2 ) ) ) {
+ setOvMaxWidth( getOvMaxWidth() + 5 );
+ setOvMaxHeight( getOvMaxHeight() + 5 );
+ updateOvSettings();
+ getControlPanel().displayedPhylogenyMightHaveChanged( false );
+ }
+ }
+
+ final private void init() {
+ _color_chooser = new JColorChooser();
+ _rollover_popup = new JTextArea();
+ _rollover_popup.setFont( POPUP_FONT );
+ resetNodeIdToDistToLeafMap();
+ setTextAntialias();
+ setTreeFile( null );
+ setEdited( false );
+ initializeOvSettings();
+ setStartingAngle( ( TWO_PI * 3 ) / 4 );
+ final ImageLoader il = new ImageLoader( this );
+ new Thread( il ).start();