inprogress
[jalview.git] / forester / java / src / org / forester / archaeopteryx / TreePanel.java
index d5cb54c..2833f8e 100644 (file)
@@ -36,6 +36,7 @@ import java.awt.Graphics2D;
 import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.RenderingHints;
+import java.awt.Stroke;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusAdapter;
@@ -105,6 +106,7 @@ import org.forester.phylogeny.Phylogeny;
 import org.forester.phylogeny.PhylogenyMethods;
 import org.forester.phylogeny.PhylogenyMethods.DESCENDANT_SORT_PRIORITY;
 import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.Accession;
 import org.forester.phylogeny.data.Annotation;
 import org.forester.phylogeny.data.BranchColor;
 import org.forester.phylogeny.data.Confidence;
@@ -126,10 +128,18 @@ import org.forester.util.BasicDescriptiveStatistics;
 import org.forester.util.DescriptiveStatistics;
 import org.forester.util.ForesterConstants;
 import org.forester.util.ForesterUtil;
-import org.forester.util.SequenceIdParser;
+import org.forester.util.SequenceAccessionTools;
+import org.forester.util.TaxonomyUtil;
 
 public final class TreePanel extends JPanel implements ActionListener, MouseWheelListener, Printable {
 
+    private static final BasicStroke     STROKE_2                                           = new BasicStroke( 2f );
+    private static final BasicStroke     STROKE_1                                           = new BasicStroke( 1f );
+    private static final BasicStroke     STROKE_075                                         = new BasicStroke( 0.75f );
+    private static final BasicStroke     STROKE_05                                          = new BasicStroke( 0.5f );
+    private static final BasicStroke     STROKE_025                                         = new BasicStroke( 0.25f );
+    private static final BasicStroke     STROKE_01                                          = new BasicStroke( 0.1f );
+    private static final BasicStroke     STROKE_005                                         = new BasicStroke( 0.05f );
     private static final float           PI                                                 = ( float ) ( Math.PI );
     private static final double          TWO_PI                                             = 2 * Math.PI;
     private static final float           ONEHALF_PI                                         = ( float ) ( 1.5 * Math.PI );
@@ -599,18 +609,23 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                             .getValue()
                             + " " );
                 }
-                if ( getControlPanel().isShowGeneNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
+                if ( getControlPanel().isShowSeqNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
                     sum += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getName() + " " );
                 }
-                if ( getControlPanel().isShowGeneSymbols()
+                if ( getControlPanel().isShowSeqSymbols()
                         && ( node.getNodeData().getSequence().getSymbol().length() > 0 ) ) {
                     sum += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getSymbol() + " " );
                 }
+                if ( getControlPanel().isShowGeneNames()
+                        && ( node.getNodeData().getSequence().getGeneName().length() > 0 ) ) {
+                    sum += getTreeFontSet()._fm_large
+                            .stringWidth( node.getNodeData().getSequence().getGeneName() + " " );
+                }
                 if ( getControlPanel().isShowAnnotation()
                         && ( node.getNodeData().getSequence().getAnnotations() != null )
                         && !node.getNodeData().getSequence().getAnnotations().isEmpty() ) {
-                    sum += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getAnnotation( 0 )
-                            .asSimpleText()
+                    sum += getTreeFontSet()._fm_large.stringWidth( TreePanelUtil.createAnnotationString( node
+                            .getNodeData().getSequence().getAnnotations(), getOptions().isShowAnnotationRefSource() )
                             + " " );
                 }
                 if ( getControlPanel().isShowDomainArchitectures()
@@ -688,23 +703,46 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
     }
 
     final Color calculateTaxonomyBasedColor( final Taxonomy tax ) {
-        String species = tax.getTaxonomyCode();
-        if ( ForesterUtil.isEmpty( species ) ) {
-            species = tax.getScientificName();
-            if ( ForesterUtil.isEmpty( species ) ) {
-                species = tax.getCommonName();
+        if ( getOptions().isColorByTaxonomicGroup() && !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
+            boolean ex = false;
+            String group = null;
+            try {
+                group = TaxonomyUtil.getTaxGroupByTaxCode( tax.getTaxonomyCode() );
+            }
+            catch ( final Exception e ) {
+                ex = true;
+            }
+            if ( !ex && !ForesterUtil.isEmpty( group ) ) {
+                final Color c = ForesterUtil.obtainColorDependingOnTaxonomyGroup( group );
+                if ( c != null ) {
+                    return c;
+                }
             }
-        }
-        if ( ForesterUtil.isEmpty( species ) ) {
             return getTreeColorSet().getTaxonomyColor();
         }
-        // Look in species hash
-        Color c = getControlPanel().getSpeciesColors().get( species );
-        if ( c == null ) {
-            c = AptxUtil.calculateColorFromString( species );
-            getControlPanel().getSpeciesColors().put( species, c );
+        else {
+            if ( ForesterUtil.isEmpty( tax.getTaxonomyCode() ) && ForesterUtil.isEmpty( tax.getScientificName() ) ) {
+                return getTreeColorSet().getTaxonomyColor();
+            }
+            Color c = null;
+            if ( !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
+                c = getControlPanel().getSpeciesColors().get( tax.getTaxonomyCode() );
+            }
+            if ( ( c == null ) && !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
+                c = getControlPanel().getSpeciesColors().get( tax.getScientificName() );
+            }
+            if ( c == null ) {
+                if ( !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
+                    c = TreePanelUtil.calculateColorFromString( tax.getTaxonomyCode(), true );
+                    getControlPanel().getSpeciesColors().put( tax.getTaxonomyCode(), c );
+                }
+                else {
+                    c = TreePanelUtil.calculateColorFromString( tax.getScientificName(), true );
+                    getControlPanel().getSpeciesColors().put( tax.getScientificName(), c );
+                }
+            }
+            return c;
         }
-        return c;
     }
 
     void checkForVectorProperties( final Phylogeny phy ) {
@@ -786,7 +824,7 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         }
         if ( !node.isExternal() && !node.isRoot() ) {
             final boolean collapse = !node.isCollapse();
-            AptxUtil.collapseSubtree( node, collapse );
+            TreePanelUtil.collapseSubtree( node, collapse );
             updateSetOfCollapsedExternalNodes();
             _phylogeny.recalculateNumberOfExternalDescendants( true );
             resetNodeIdToDistToLeafMap();
@@ -805,7 +843,7 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
             return;
         }
         setWaitCursor();
-        AptxUtil.collapseSpeciesSpecificSubtrees( _phylogeny );
+        TreePanelUtil.collapseSpeciesSpecificSubtrees( _phylogeny );
         updateSetOfCollapsedExternalNodes();
         _phylogeny.recalculateNumberOfExternalDescendants( true );
         resetNodeIdToDistToLeafMap();
@@ -823,7 +861,7 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         }
         setWaitCursor();
         AptxUtil.removeBranchColors( _phylogeny );
-        final int colorizations = AptxUtil.colorPhylogenyAccordingToRanks( _phylogeny, rank, this );
+        final int colorizations = TreePanelUtil.colorPhylogenyAccordingToRanks( _phylogeny, rank, this );
         if ( colorizations > 0 ) {
             _control_panel.setColorBranches( true );
             if ( _control_panel.getColorBranchesCb() != null ) {
@@ -869,7 +907,7 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         }
         setWaitCursor();
         AptxUtil.removeBranchColors( _phylogeny );
-        AptxUtil.colorPhylogenyAccordingToConfidenceValues( _phylogeny, this );
+        TreePanelUtil.colorPhylogenyAccordingToConfidenceValues( _phylogeny, this );
         _control_panel.setColorBranches( true );
         if ( _control_panel.getColorBranchesCb() != null ) {
             _control_panel.getColorBranchesCb().setSelected( true );
@@ -1521,7 +1559,7 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                     g.fillRect( graphics_file_x, graphics_file_y, graphics_file_width, graphics_file_height );
                 }
             }
-            g.setStroke( new BasicStroke( 1 ) );
+            setupStroke( g );
         }
         else {
             g.setStroke( new BasicStroke( getOptions().getPrintLineWidth() ) );
@@ -1913,8 +1951,8 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
             DESCENDANT_SORT_PRIORITY pri = DESCENDANT_SORT_PRIORITY.TAXONOMY;
             if ( ( !getControlPanel().isShowTaxonomyScientificNames() && !getControlPanel().isShowTaxonomyCode() && !getControlPanel()
                     .isShowTaxonomyCommonNames() ) ) {
-                if ( ( getControlPanel().isShowSequenceAcc() || getControlPanel().isShowGeneNames() || getControlPanel()
-                        .isShowGeneSymbols() ) ) {
+                if ( ( getControlPanel().isShowSequenceAcc() || getControlPanel().isShowSeqNames() || getControlPanel()
+                        .isShowSeqSymbols() ) ) {
                     pri = DESCENDANT_SORT_PRIORITY.SEQUENCE;
                 }
                 else if ( getControlPanel().isShowNodeNames() ) {
@@ -1959,7 +1997,7 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
             _sub_phylogenies[ _subtree_index ] = _phylogeny;
             _sub_phylogenies_temp_roots[ _subtree_index ] = node;
             ++_subtree_index;
-            _phylogeny = subTree( node, _phylogeny );
+            _phylogeny = TreePanelUtil.subTree( node, _phylogeny );
             updateSubSuperTreeButton();
         }
         else if ( node.isRoot() && isCurrentTreeIsSubtree() ) {
@@ -2009,7 +2047,7 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
             return;
         }
         setWaitCursor();
-        AptxUtil.colorPhylogenyAccordingToExternalTaxonomy( _phylogeny, this );
+        TreePanelUtil.colorPhylogenyAccordingToExternalTaxonomy( _phylogeny, this );
         _control_panel.setColorBranches( true );
         if ( _control_panel.getColorBranchesCb() != null ) {
             _control_panel.getColorBranchesCb().setSelected( true );
@@ -2255,7 +2293,7 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                     }
                 }
                 if ( type == '?' ) {
-                    if ( SequenceIdParser.isProtein( query ) ) {
+                    if ( SequenceAccessionTools.isProteinDbQuery( query ) ) {
                         type = 'p';
                     }
                     else {
@@ -2319,13 +2357,13 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         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() );
+                sb.append( !ForesterUtil.isEmpty( a.getRefValue() ) ? a.getRefValue() : 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 );
+                    c = TreePanelUtil.calculateColorFromString( ann_str, false );
                     getControlPanel().getAnnotationColors().put( ann_str, c );
                 }
                 if ( c == null ) {
@@ -2358,45 +2396,56 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                                        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;
-        }
+    final private void colorizeSubtree( final Color c,
+                                        final PhylogenyNode node,
+                                        final List<PhylogenyNode> additional_nodes ) {
         _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 ) );
+        if ( node != null ) {
+            for( final PreorderTreeIterator it = new PreorderTreeIterator( node ); it.hasNext(); ) {
+                it.next().getBranchData().setBranchColor( new BranchColor( c ) );
+            }
+        }
+        if ( additional_nodes != null ) {
+            for( final PhylogenyNode n : additional_nodes ) {
+                n.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 );
+        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;
+        }
+        _color_chooser.setPreviewPanel( new JPanel() );
+        SubtreeColorizationActionListener al;
+        if ( ( getFoundNodes() != null ) && !getFoundNodes().isEmpty() ) {
+            final List<PhylogenyNode> additional_nodes = getFoundNodesAsListOfPhylogenyNodes();
+            al = new SubtreeColorizationActionListener( _color_chooser, node, additional_nodes );
         }
         else {
-            intitial_color = getTreeColorSet().getBranchColor();
+            al = new SubtreeColorizationActionListener( _color_chooser, node );
         }
-        _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 );
+                .createDialog( this, "Subtree colorization", true, _color_chooser, al, null );
         dialog.setVisible( true );
     }
 
+    private List<PhylogenyNode> getFoundNodesAsListOfPhylogenyNodes() {
+        final List<PhylogenyNode> additional_nodes = new ArrayList<PhylogenyNode>();
+        for( final Long id : getFoundNodes() ) {
+            additional_nodes.add( _phylogeny.getNode( id ) );
+        }
+        return additional_nodes;
+    }
+
     final private void copySubtree( final PhylogenyNode node ) {
         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
             errorMessageNoCutCopyPasteInUnrootedDisplay();
@@ -2414,22 +2463,6 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         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();
@@ -2817,6 +2850,9 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
             case OPEN_TAX_WEB:
                 openTaxWeb( node );
                 break;
+            case OPEN_PDB_WEB:
+                openPdbWeb( node );
+                break;
             case CUT_SUBTREE:
                 cutSubtree( node );
                 break;
@@ -2901,6 +2937,30 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         return Blast.isContainsQueryForBlast( node );
     }
 
+    final private String isCanOpenSeqWeb( final PhylogenyNode node ) {
+        final Accession a = SequenceAccessionTools.obtainAccessorFromDataFields( node );
+        if ( a != null ) {
+            return a.getValue();
+        }
+        return null;
+    }
+
+    final private List<Accession> getPdbAccs( final PhylogenyNode node ) {
+        final List<Accession> pdb_ids = new ArrayList<Accession>();
+        if ( node.getNodeData().isHasSequence() ) {
+            final Sequence seq = node.getNodeData().getSequence();
+            if ( !ForesterUtil.isEmpty( seq.getCrossReferences() ) ) {
+                final SortedSet<Accession> cross_refs = seq.getCrossReferences();
+                for( final Accession acc : cross_refs ) {
+                    if ( acc.getSource().equalsIgnoreCase( "pdb" ) ) {
+                        pdb_ids.add( acc );
+                    }
+                }
+            }
+        }
+        return pdb_ids;
+    }
+
     final private boolean isCanOpenTaxWeb( final PhylogenyNode node ) {
         if ( node.getNodeData().isHasTaxonomy()
                 && ( ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getScientificName() ) )
@@ -3136,6 +3196,41 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                     _node_popup_menu_items[ i ].setEnabled( false );
                 }
             }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.open_pdb_web ][ 0 ] ) ) {
+                final List<Accession> accs = getPdbAccs( node );
+                _node_popup_menu_items[ i ] = new JMenuItem( title );
+                if ( !ForesterUtil.isEmpty( accs ) ) {
+                    if ( accs.size() == 1 ) {
+                        _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " ["
+                                + TreePanelUtil.pdbAccToString( accs, 0 ) + "]" );
+                        _node_popup_menu_items[ i ].setEnabled( true );
+                    }
+                    else if ( accs.size() == 2 ) {
+                        _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " ["
+                                + TreePanelUtil.pdbAccToString( accs, 0 ) + ", "
+                                + TreePanelUtil.pdbAccToString( accs, 1 ) + "]" );
+                        _node_popup_menu_items[ i ].setEnabled( true );
+                    }
+                    else if ( accs.size() == 3 ) {
+                        _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " ["
+                                + TreePanelUtil.pdbAccToString( accs, 0 ) + ", "
+                                + TreePanelUtil.pdbAccToString( accs, 1 ) + ", "
+                                + TreePanelUtil.pdbAccToString( accs, 2 ) + "]" );
+                        _node_popup_menu_items[ i ].setEnabled( true );
+                    }
+                    else {
+                        _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " ["
+                                + TreePanelUtil.pdbAccToString( accs, 0 ) + ", "
+                                + TreePanelUtil.pdbAccToString( accs, 1 ) + ", "
+                                + TreePanelUtil.pdbAccToString( accs, 2 ) + ", + " + ( accs.size() - 3 ) + " more]" );
+                        _node_popup_menu_items[ i ].setEnabled( true );
+                    }
+                }
+                else {
+                    _node_popup_menu_items[ i ].setEnabled( false );
+                }
+                //
+            }
             else if ( title.equals( Configuration.clickto_options[ Configuration.open_tax_web ][ 0 ] ) ) {
                 _node_popup_menu_items[ i ].setEnabled( isCanOpenTaxWeb( node ) );
             }
@@ -3203,6 +3298,8 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         switch ( getOptions().getExtDescNodeDataToReturn() ) {
             case NODE_NAME:
                 return "Node Names";
+            case GENE_NAME:
+                return "Gene Names";
             case SEQUENCE_NAME:
                 return "Sequence Names";
             case SEQUENCE_SYMBOL:
@@ -3217,6 +3314,8 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                 return "Scientific Names";
             case TAXONOMY_CODE:
                 return "Taxonomy Codes";
+            case TAXONOMY_COMM0N_NAME:
+                return "Taxonomy Common Names";
             case UNKNOWN:
                 return "User Selected Data";
             default:
@@ -3225,26 +3324,12 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         }
     }
 
-    final private String isCanOpenSeqWeb( final PhylogenyNode node ) {
-        String v = ForesterUtil.extractUniProtKbProteinSeqIdentifier( node );
-        if ( ForesterUtil.isEmpty( v ) ) {
-            v = ForesterUtil.extractGenbankAccessor( node );
-        }
-        if ( ForesterUtil.isEmpty( v ) ) {
-            v = ForesterUtil.extractRefSeqAccessorAccessor( node );
-        }
-        if ( ForesterUtil.isEmpty( v ) ) {
-            v = ForesterUtil.extractGInumber( node );
-        }
-        return v;
-    }
-
     final private void openSeqWeb( final PhylogenyNode node ) {
         if ( ForesterUtil.isEmpty( isCanOpenSeqWeb( node ) ) ) {
             cannotOpenBrowserWarningMessage( "sequence" );
             return;
         }
-        final String uri_str = AptxUtil.createUriForSeqWeb( node, getConfiguration(), this );
+        final String uri_str = TreePanelUtil.createUriForSeqWeb( node, getConfiguration(), this );
         if ( !ForesterUtil.isEmpty( uri_str ) ) {
             try {
                 AptxUtil.launchWebBrowser( new URI( uri_str ),
@@ -3266,6 +3351,36 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         }
     }
 
+    final private void openPdbWeb( final PhylogenyNode node ) {
+        final List<Accession> pdb_ids = getPdbAccs( node );
+        if ( ForesterUtil.isEmpty( pdb_ids ) ) {
+            cannotOpenBrowserWarningMessage( "PDB" );
+            return;
+        }
+        final List<String> uri_strs = TreePanelUtil.createUrisForPdbWeb( node, pdb_ids, getConfiguration(), this );
+        if ( !ForesterUtil.isEmpty( uri_strs ) ) {
+            for( final String uri_str : uri_strs ) {
+                try {
+                    AptxUtil.launchWebBrowser( new URI( uri_str ),
+                                               isApplet(),
+                                               isApplet() ? obtainApplet() : null,
+                                               "_aptx_seq" );
+                }
+                catch ( final IOException e ) {
+                    AptxUtil.showErrorMessage( this, e.toString() );
+                    e.printStackTrace();
+                }
+                catch ( final URISyntaxException e ) {
+                    AptxUtil.showErrorMessage( this, e.toString() );
+                    e.printStackTrace();
+                }
+            }
+        }
+        else {
+            cannotOpenBrowserWarningMessage( "PDB" );
+        }
+    }
+
     final private void openTaxWeb( final PhylogenyNode node ) {
         if ( !isCanOpenTaxWeb( node ) ) {
             cannotOpenBrowserWarningMessage( "taxonomic" );
@@ -3811,7 +3926,7 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
             if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
                 outline_color = Color.BLACK;
             }
-            else if ( getControlPanel().isEvents() && AptxUtil.isHasAssignedEvent( node ) ) {
+            else if ( getControlPanel().isEvents() && TreePanelUtil.isHasAssignedEvent( node ) ) {
                 final Event event = node.getNodeData().getEvent();
                 if ( event.isDuplication() ) {
                     outline_color = getTreeColorSet().getDuplicationBoxColor();
@@ -3975,13 +4090,19 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
             _sb.append( node.getName() );
         }
         if ( node.getNodeData().isHasSequence() ) {
-            if ( getControlPanel().isShowGeneSymbols() && ( node.getNodeData().getSequence().getSymbol().length() > 0 ) ) {
+            if ( getControlPanel().isShowSeqSymbols() && ( node.getNodeData().getSequence().getSymbol().length() > 0 ) ) {
                 if ( _sb.length() > 0 ) {
                     _sb.append( " " );
                 }
                 _sb.append( node.getNodeData().getSequence().getSymbol() );
             }
-            if ( getControlPanel().isShowGeneNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
+            if ( getControlPanel().isShowGeneNames() && ( node.getNodeData().getSequence().getGeneName().length() > 0 ) ) {
+                if ( _sb.length() > 0 ) {
+                    _sb.append( " " );
+                }
+                _sb.append( node.getNodeData().getSequence().getGeneName() );
+            }
+            if ( getControlPanel().isShowSeqNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
                 if ( _sb.length() > 0 ) {
                     _sb.append( " " );
                 }
@@ -4094,7 +4215,7 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
             else if ( getControlPanel().isColorAccordingToAnnotation() ) {
                 g.setColor( calculateColorForAnnotation( ann ) );
             }
-            final String ann_str = createAnnotationString( ann );
+            final String ann_str = TreePanelUtil.createAnnotationString( ann, getOptions().isShowAnnotationRefSource() );
             TreePanel.drawString( ann_str, node.getXcoord() + x + 3 + half_box_size, node.getYcoord()
                     + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ), g );
             _sb.setLength( 0 );
@@ -4225,7 +4346,7 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                 }
                 _sb.append( node.getNodeData().getSequence().getAccession().getValue() );
             }
-            if ( getControlPanel().isShowGeneNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
+            if ( getControlPanel().isShowSeqNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
                 if ( _sb.length() > 0 ) {
                     _sb.append( " " );
                 }
@@ -4468,22 +4589,35 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                         }
                     }
                     if ( node.getNodeData().isHasSequence() ) {
-                        if ( getControlPanel().isShowGeneNames()
+                        if ( getControlPanel().isShowSeqNames()
                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getName() ) ) ) {
                             x += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getName()
                                     + " " );
                         }
-                        if ( getControlPanel().isShowGeneSymbols()
+                        if ( getControlPanel().isShowSeqSymbols()
                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getSymbol() ) ) ) {
                             x += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getSymbol()
                                     + " " );
                         }
+                        if ( getControlPanel().isShowGeneNames()
+                                && ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getGeneName() ) ) ) {
+                            x += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getGeneName()
+                                    + " " );
+                        }
                         if ( getControlPanel().isShowSequenceAcc()
                                 && ( node.getNodeData().getSequence().getAccession() != null ) ) {
                             x += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence()
                                     .getAccession().toString()
                                     + " " );
                         }
+                        if ( getControlPanel().isShowAnnotation()
+                                && ( node.getNodeData().getSequence().getAnnotations() != null )
+                                && ( !node.getNodeData().getSequence().getAnnotations().isEmpty() ) ) {
+                            x += getTreeFontSet()._fm_large.stringWidth( TreePanelUtil.createAnnotationString( node
+                                    .getNodeData().getSequence().getAnnotations(), getOptions()
+                                    .isShowAnnotationRefSource() )
+                                    + " " );
+                        }
                     }
                     if ( getControlPanel().isShowNodeNames() && !ForesterUtil.isEmpty( node.getName() ) ) {
                         x += getTreeFontSet()._fm_large.stringWidth( node.getName() + " " );
@@ -4527,6 +4661,8 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         final float y = getVisibleRect().y + getOvYPosition() + ( getOvMaxHeight() / y_ratio );
         g.setColor( getTreeColorSet().getFoundColor() );
         getOvRectangle().setRect( x, y, width, height );
+        final Stroke s = g.getStroke();
+        g.setStroke( STROKE_1 );
         if ( ( width < 6 ) && ( height < 6 ) ) {
             drawRectFilled( x, y, 6, 6, g );
             getOvVirtualRectangle().setRect( x, y, 6, 6 );
@@ -4546,6 +4682,7 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
             }
             getOvVirtualRectangle().setRect( x, y, width, height );
         }
+        g.setStroke( s );
     }
 
     final private void paintPhylogenyLite( final Graphics2D g ) {
@@ -4554,11 +4691,12 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                 .setXSecondary( ( float ) ( getVisibleRect().x + getOvXPosition() + ( MOVE / ( getVisibleRect().width / getOvRectangle()
                         .getWidth() ) ) ) );
         _phylogeny.getRoot().setYSecondary( ( getVisibleRect().y + getOvYStart() ) );
-        g.setStroke( new BasicStroke( 0.5f ) ); //TODO
+        final Stroke s = g.getStroke();
+        g.setStroke( STROKE_05 );
         for( final PhylogenyNode element : _nodes_in_preorder ) {
             paintNodeLite( g, element );
         }
-        g.setStroke( new BasicStroke( 1 ) ); //TODO
+        g.setStroke( s );
         paintOvRectangle( g );
     }
 
@@ -4610,12 +4748,15 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         else {
             g.setColor( getTreeColorSet().getBranchLengthColor() );
         }
+        final Stroke s = g.getStroke();
+        g.setStroke( STROKE_1 );
         drawLine( x1, y1, x1, y2, g );
         drawLine( x2, y1, x2, y2, g );
         drawLine( x1, y3, x2, y3, g );
         if ( getScaleLabel() != null ) {
             g.drawString( getScaleLabel(), ( x1 + 2 ), y3 - 2 );
         }
+        g.setStroke( s );
     }
 
     final private int paintTaxonomy( final Graphics2D g,
@@ -4934,11 +5075,11 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                 sb.append( " " );
             }
             final Property p = properties.getProperty( ref );
-            sb.append( getPartAfterColon( p.getRef() ) );
+            sb.append( TreePanelUtil.getPartAfterColon( p.getRef() ) );
             sb.append( "=" );
             sb.append( p.getValue() );
             if ( !ForesterUtil.isEmpty( p.getUnit() ) ) {
-                sb.append( getPartAfterColon( p.getUnit() ) );
+                sb.append( TreePanelUtil.getPartAfterColon( p.getUnit() ) );
             }
         }
         return sb;
@@ -4996,6 +5137,30 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         _scale_label = scale_label;
     }
 
+    private final void setupStroke( final Graphics2D g ) {
+        if ( getYdistance() < 0.001 ) {
+            g.setStroke( STROKE_005 );
+        }
+        else if ( getYdistance() < 0.01 ) {
+            g.setStroke( STROKE_01 );
+        }
+        else if ( getYdistance() < 0.5 ) {
+            g.setStroke( STROKE_025 );
+        }
+        else if ( getYdistance() < 1 ) {
+            g.setStroke( STROKE_05 );
+        }
+        else if ( getYdistance() < 2 ) {
+            g.setStroke( STROKE_075 );
+        }
+        else if ( getYdistance() < 20 ) {
+            g.setStroke( STROKE_1 );
+        }
+        else {
+            g.setStroke( STROKE_2 );
+        }
+    }
+
     final private void setUpUrtFactor() {
         final int d = getVisibleRect().width < getVisibleRect().height ? getVisibleRect().width
                 : getVisibleRect().height;
@@ -5024,7 +5189,15 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
 
     private void showExtDescNodeData( final PhylogenyNode node ) {
         final List<String> data = new ArrayList<String>();
-        for( final PhylogenyNode n : node.getAllExternalDescendants() ) {
+        final List<PhylogenyNode> nodes = node.getAllExternalDescendants();
+        if ( ( getFoundNodes() != null ) && !getFoundNodes().isEmpty() ) {
+            for( final PhylogenyNode n : getFoundNodesAsListOfPhylogenyNodes() ) {
+                if ( !nodes.contains( n ) ) {
+                    nodes.add( n );
+                }
+            }
+        }
+        for( final PhylogenyNode n : nodes ) {
             switch ( getOptions().getExtDescNodeDataToReturn() ) {
                 case NODE_NAME:
                     if ( !ForesterUtil.isEmpty( n.getName() ) ) {
@@ -5037,6 +5210,12 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                         data.add( n.getNodeData().getSequence().getName() );
                     }
                     break;
+                case GENE_NAME:
+                    if ( n.getNodeData().isHasSequence()
+                            && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getGeneName() ) ) {
+                        data.add( n.getNodeData().getSequence().getGeneName() );
+                    }
+                    break;
                 case SEQUENCE_SYMBOL:
                     if ( n.getNodeData().isHasSequence()
                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getSymbol() ) ) {
@@ -5053,14 +5232,52 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                     final StringBuilder sb = new StringBuilder();
                     if ( n.getNodeData().isHasSequence()
                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getMolecularSequence() ) ) {
+                        final StringBuilder ann = new StringBuilder();
+                        if ( !ForesterUtil.isEmpty( n.getName() ) ) {
+                            ann.append( n.getName() );
+                            ann.append( "|" );
+                        }
+                        if ( !ForesterUtil.isEmpty( n.getNodeData().getSequence().getSymbol() ) ) {
+                            ann.append( "SYM=" );
+                            ann.append( n.getNodeData().getSequence().getSymbol() );
+                            ann.append( "|" );
+                        }
                         if ( !ForesterUtil.isEmpty( n.getNodeData().getSequence().getName() ) ) {
-                            sb.append( SequenceWriter.toFasta( n.getNodeData().getSequence().getName(), n.getNodeData()
-                                    .getSequence().getMolecularSequence(), 60 ) );
+                            ann.append( "NAME=" );
+                            ann.append( n.getNodeData().getSequence().getName() );
+                            ann.append( "|" );
+                        }
+                        if ( !ForesterUtil.isEmpty( n.getNodeData().getSequence().getGeneName() ) ) {
+                            ann.append( "GN=" );
+                            ann.append( n.getNodeData().getSequence().getGeneName() );
+                            ann.append( "|" );
+                        }
+                        if ( n.getNodeData().getSequence().getAccession() != null ) {
+                            ann.append( "ACC=" );
+                            ann.append( n.getNodeData().getSequence().getAccession().asText() );
+                            ann.append( "|" );
+                        }
+                        if ( n.getNodeData().isHasTaxonomy() ) {
+                            if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
+                                ann.append( "TAXID=" );
+                                ann.append( n.getNodeData().getTaxonomy().getTaxonomyCode() );
+                                ann.append( "|" );
+                            }
+                            if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getScientificName() ) ) {
+                                ann.append( "SN=" );
+                                ann.append( n.getNodeData().getTaxonomy().getScientificName() );
+                                ann.append( "|" );
+                            }
+                        }
+                        String ann_str;
+                        if ( ann.charAt( ann.length() - 1 ) == '|' ) {
+                            ann_str = ann.substring( 0, ann.length() - 1 );
                         }
                         else {
-                            sb.append( SequenceWriter.toFasta( n.getName(), n.getNodeData().getSequence()
-                                    .getMolecularSequence(), 60 ) );
+                            ann_str = ann.toString();
                         }
+                        sb.append( SequenceWriter.toFasta( ann_str, n.getNodeData().getSequence()
+                                .getMolecularSequence(), 60 ) );
                         data.add( sb.toString() );
                     }
                     break;
@@ -5076,6 +5293,12 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                         data.add( n.getNodeData().getTaxonomy().getScientificName() );
                     }
                     break;
+                case TAXONOMY_COMM0N_NAME:
+                    if ( n.getNodeData().isHasTaxonomy()
+                            && !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getCommonName() ) ) {
+                        data.add( n.getNodeData().getTaxonomy().getCommonName() );
+                    }
+                    break;
                 case TAXONOMY_CODE:
                     if ( n.getNodeData().isHasTaxonomy()
                             && !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
@@ -5083,24 +5306,19 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                     }
                     break;
                 case UNKNOWN:
-                    AptxUtil.showExtDescNodeDataUserSelectedHelper( getControlPanel(), n, data );
+                    TreePanelUtil.showExtDescNodeDataUserSelectedHelper( getControlPanel(), n, data );
                     break;
                 default:
                     throw new IllegalArgumentException( "unknown data element: "
                             + getOptions().getExtDescNodeDataToReturn() );
             }
         } // for loop
+        final StringBuilder sb = new StringBuilder();
+        final int size = TreePanelUtil.makeSB( data, getOptions(), sb );
         if ( ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.CONSOLE )
                 || ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.BUFFER_ONLY ) ) {
-            final StringBuilder sb = new StringBuilder();
-            for( final String d : data ) {
-                if ( !ForesterUtil.isEmpty( d ) ) {
-                    if ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.CONSOLE ) {
-                        System.out.println( d );
-                    }
-                    sb.append( d );
-                    sb.append( ForesterUtil.LINE_SEPARATOR );
-                }
+            if ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.CONSOLE ) {
+                System.out.println( sb );
             }
             if ( sb.length() < 1 ) {
                 clearCurrentExternalNodesDataBuffer();
@@ -5110,25 +5328,33 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
             }
         }
         else if ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.WINODW ) {
-            final StringBuilder sb = new StringBuilder();
-            for( final String d : data ) {
-                if ( !ForesterUtil.isEmpty( d ) ) {
-                    sb.append( d );
-                    sb.append( ForesterUtil.LINE_SEPARATOR );
-                }
-            }
             if ( sb.length() < 1 ) {
-                AptxUtil.showInformationMessage( this,
-                                                 "No Appropriate Data (" + obtainTitleForExtDescNodeData() + ")",
-                                                 "Descendants of selected node do not contain selected data" );
+                TreePanelUtil.showInformationMessage( this, "No Appropriate Data (" + obtainTitleForExtDescNodeData()
+                        + ")", "Descendants of selected node do not contain selected data" );
                 clearCurrentExternalNodesDataBuffer();
             }
             else {
                 setCurrentExternalNodesDataBuffer( sb );
-                final String title = "External Descendants "
-                        + ( getOptions().getExtDescNodeDataToReturn() == NODE_DATA.UNKNOWN ? "Data"
-                                : obtainTitleForExtDescNodeData() ) + " (" + data.size() + "/"
-                        + node.getNumberOfExternalNodes() + ") For Node " + node;
+                String title;
+                if ( ( getFoundNodes() != null ) && !getFoundNodes().isEmpty() ) {
+                    title = ( getOptions().getExtDescNodeDataToReturn() == NODE_DATA.UNKNOWN ? "Data"
+                            : obtainTitleForExtDescNodeData() )
+                            + " for "
+                            + data.size()
+                            + " nodes, unique entries: "
+                            + size;
+                }
+                else {
+                    title = ( getOptions().getExtDescNodeDataToReturn() == NODE_DATA.UNKNOWN ? "Data"
+                            : obtainTitleForExtDescNodeData() )
+                            + " for "
+                            + data.size()
+                            + "/"
+                            + node.getNumberOfExternalNodes()
+                            + " external descendats of node "
+                            + node
+                            + ", unique entries: " + size;
+                }
                 final String s = sb.toString().trim();
                 if ( getMainPanel().getMainFrame() == null ) {
                     // Must be "E" applet version.
@@ -5145,17 +5371,19 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
     final private void showNodeDataPopup( final MouseEvent e, final PhylogenyNode node ) {
         try {
             if ( ( node.getName().length() > 0 )
-                    || ( node.getNodeData().isHasTaxonomy() && !isTaxonomyEmpty( node.getNodeData().getTaxonomy() ) )
-                    || ( node.getNodeData().isHasSequence() && !isSequenceEmpty( node.getNodeData().getSequence() ) )
-                    || ( node.getNodeData().isHasDate() ) || ( node.getNodeData().isHasDistribution() )
-                    || node.getBranchData().isHasConfidences() ) {
+                    || ( node.getNodeData().isHasTaxonomy() && !TreePanelUtil.isTaxonomyEmpty( node.getNodeData()
+                            .getTaxonomy() ) )
+                    || ( node.getNodeData().isHasSequence() && !TreePanelUtil.isSequenceEmpty( node.getNodeData()
+                            .getSequence() ) ) || ( node.getNodeData().isHasDate() )
+                    || ( node.getNodeData().isHasDistribution() ) || node.getBranchData().isHasConfidences() ) {
                 _popup_buffer.setLength( 0 );
                 short lines = 0;
                 if ( node.getName().length() > 0 ) {
                     lines++;
                     _popup_buffer.append( node.getName() );
                 }
-                if ( node.getNodeData().isHasTaxonomy() && !isTaxonomyEmpty( node.getNodeData().getTaxonomy() ) ) {
+                if ( node.getNodeData().isHasTaxonomy()
+                        && !TreePanelUtil.isTaxonomyEmpty( node.getNodeData().getTaxonomy() ) ) {
                     lines++;
                     boolean enc_data = false;
                     final Taxonomy tax = node.getNodeData().getTaxonomy();
@@ -5237,7 +5465,8 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                         }
                     }
                 }
-                if ( node.getNodeData().isHasSequence() && !isSequenceEmpty( node.getNodeData().getSequence() ) ) {
+                if ( node.getNodeData().isHasSequence()
+                        && !TreePanelUtil.isSequenceEmpty( node.getNodeData().getSequence() ) ) {
                     lines++;
                     boolean enc_data = false;
                     if ( _popup_buffer.length() > 0 ) {
@@ -5265,6 +5494,17 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                         _popup_buffer.append( "]" );
                         enc_data = true;
                     }
+                    if ( !ForesterUtil.isEmpty( seq.getGeneName() ) ) {
+                        if ( enc_data ) {
+                            _popup_buffer.append( " [" );
+                        }
+                        else {
+                            _popup_buffer.append( "[" );
+                        }
+                        _popup_buffer.append( seq.getGeneName() );
+                        _popup_buffer.append( "]" );
+                        enc_data = true;
+                    }
                     if ( !ForesterUtil.isEmpty( seq.getName() ) ) {
                         if ( enc_data ) {
                             _popup_buffer.append( " " );
@@ -5316,11 +5556,11 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
                     for( final String ref : properties.getPropertyRefs() ) {
                         _popup_buffer.append( "\n" );
                         final Property p = properties.getProperty( ref );
-                        _popup_buffer.append( getPartAfterColon( p.getRef() ) );
+                        _popup_buffer.append( TreePanelUtil.getPartAfterColon( p.getRef() ) );
                         _popup_buffer.append( "=" );
                         _popup_buffer.append( p.getValue() );
                         if ( !ForesterUtil.isEmpty( p.getUnit() ) ) {
-                            _popup_buffer.append( getPartAfterColon( p.getUnit() ) );
+                            _popup_buffer.append( TreePanelUtil.getPartAfterColon( p.getUnit() ) );
                         }
                     }
                 }
@@ -5440,70 +5680,39 @@ public final class TreePanel extends JPanel implements ActionListener, MouseWhee
         }
     }
 
-    final private static void drawString( final int i, final double x, final double y, final Graphics2D g ) {
-        g.drawString( String.valueOf( i ), ( int ) ( x + 0.5 ), ( int ) ( y + 0.5 ) );
-    }
-
     final private static void drawString( final String str, final double x, final double y, final Graphics2D g ) {
         g.drawString( str, ( int ) ( x + 0.5 ), ( int ) ( y + 0.5 ) );
     }
 
-    final private static String getPartAfterColon( final String s ) {
-        final int i = s.indexOf( ':' );
-        if ( ( i < 1 ) || ( i == ( s.length() - 1 ) ) ) {
-            return s;
-        }
-        return s.substring( i + 1, s.length() );
-    }
-
-    final private static boolean isSequenceEmpty( final Sequence seq ) {
-        return ( seq.getAccession() == null ) && ForesterUtil.isEmpty( seq.getName() )
-                && ForesterUtil.isEmpty( seq.getSymbol() );
-    }
-
-    final private static boolean isTaxonomyEmpty( final Taxonomy tax ) {
-        return ( ( tax.getIdentifier() == null ) && ForesterUtil.isEmpty( tax.getTaxonomyCode() )
-                && ForesterUtil.isEmpty( tax.getCommonName() ) && ForesterUtil.isEmpty( tax.getScientificName() ) && tax
-                .getSynonyms().isEmpty() );
-    }
-
     final private static boolean plusPressed( final int key_code ) {
         return ( ( key_code == KeyEvent.VK_ADD ) || ( key_code == KeyEvent.VK_PLUS )
                 || ( key_code == KeyEvent.VK_EQUALS ) || ( key_code == KeyEvent.VK_SEMICOLON ) || ( key_code == KeyEvent.VK_1 ) );
     }
 
-    final private static Phylogeny subTree( final PhylogenyNode new_root, final Phylogeny source_phy ) {
-        final Phylogeny new_phy = new Phylogeny();
-        new_phy.setRooted( true );
-        new_phy.setName( source_phy.getName() );
-        new_phy.setDescription( source_phy.getDescription() );
-        new_phy.setType( source_phy.getType() );
-        new_phy.setDistanceUnit( source_phy.getDistanceUnit() );
-        new_phy.setConfidence( source_phy.getConfidence() );
-        new_phy.setIdentifier( source_phy.getIdentifier() );
-        new_phy.setRoot( new_root.copyNodeDataShallow() );
-        int i = 0;
-        for( final PhylogenyNode n : new_root.getDescendants() ) {
-            new_phy.getRoot().setChildNode( i++, n );
-        }
-        return new_phy;
-    }
-
     final private class SubtreeColorizationActionListener implements ActionListener {
 
-        JColorChooser _chooser;
-        PhylogenyNode _node;
+        JColorChooser       _chooser          = null;
+        PhylogenyNode       _node             = null;
+        List<PhylogenyNode> _additional_nodes = null;
 
         SubtreeColorizationActionListener( final JColorChooser chooser, final PhylogenyNode node ) {
             _chooser = chooser;
             _node = node;
         }
 
+        SubtreeColorizationActionListener( final JColorChooser chooser,
+                                           final PhylogenyNode node,
+                                           final List<PhylogenyNode> additional_nodes ) {
+            _chooser = chooser;
+            _node = node;
+            _additional_nodes = additional_nodes;
+        }
+
         @Override
         public void actionPerformed( final ActionEvent e ) {
             final Color c = _chooser.getColor();
             if ( c != null ) {
-                colorizeSubtree( c, _node );
+                colorizeSubtree( c, _node, _additional_nodes );
             }
         }
     }