initial commit
authorcmzmasek@gmail.com <cmzmasek@gmail.com@ca865154-3058-d1c3-3e42-d8f55a55bdbd>
Wed, 9 Feb 2011 01:07:28 +0000 (01:07 +0000)
committercmzmasek@gmail.com <cmzmasek@gmail.com@ca865154-3058-d1c3-3e42-d8f55a55bdbd>
Wed, 9 Feb 2011 01:07:28 +0000 (01:07 +0000)
42 files changed:
forester/java/src/org/forester/archaeopteryx/AncestralTaxonomyInferrer.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/Archaeopteryx.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/ArchaeopteryxA.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/ArchaeopteryxE.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/Blast.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/ColorSchemeChooser.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/Configuration.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/Constants.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/ControlPanel.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/FontChooser.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/ImageLoader.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/MainFrame.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/MainFrameApplet.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/MainFrameApplication.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/MainPanel.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/MainPanelApplets.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/MainPanelEdit.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/MouseListener.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/NodeEditPanel.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/NodeFrame.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/NodePanel.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/Options.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/PdfExporter.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/PhyloInferenceDialog.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/PhylogeneticInferenceOptions.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/PhylogeneticInferrer.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/Printer.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/TaxonomyDataObtainer.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/TextFrame.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/TreeColorSet.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/TreeFontSet.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/TreePanel.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/UrlTreeReader.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/Util.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/WebLink.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/phylogeny/data/RenderableDomainArchitecture.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/phylogeny/data/RenderablePhylogenyData.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/phylogeny/data/RenderableVector.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/webservices/BasicPhylogeniesWebserviceClient.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/webservices/PhylogeniesWebserviceClient.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/webservices/WebserviceUtil.java [new file with mode: 0644]
forester/java/src/org/forester/archaeopteryx/webservices/WebservicesManager.java [new file with mode: 0644]

diff --git a/forester/java/src/org/forester/archaeopteryx/AncestralTaxonomyInferrer.java b/forester/java/src/org/forester/archaeopteryx/AncestralTaxonomyInferrer.java
new file mode 100644 (file)
index 0000000..c1c92cc
--- /dev/null
@@ -0,0 +1,144 @@
+// Exp $
+// forester -- software libraries and applications
+// for genomics and evolutionary biology research.
+//
+// Copyright (C) 2010 Christian M Zmasek
+// Copyright (C) 2010 Sanford-Burnham Medical Research Institute
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.net.UnknownHostException;
+import java.util.SortedSet;
+
+import javax.swing.JOptionPane;
+
+import org.forester.analysis.AncestralTaxonomyInference;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.ws.uniprot.UniProtWsTools;
+
+public class AncestralTaxonomyInferrer implements Runnable {
+
+    private final Phylogeny            _phy;
+    private final MainFrameApplication _mf;
+    private final TreePanel            _treepanel;
+
+    AncestralTaxonomyInferrer( final MainFrameApplication mf, final TreePanel treepanel, final Phylogeny phy ) {
+        _phy = phy;
+        _mf = mf;
+        _treepanel = treepanel;
+    }
+
+    private String getBaseUrl() {
+        return UniProtWsTools.BASE_URL;
+    }
+
+    private void inferTaxonomies() {
+        _mf.getMainPanel().getCurrentTreePanel().setWaitCursor();
+        SortedSet<String> not_found = null;
+        try {
+            not_found = AncestralTaxonomyInference.inferTaxonomyFromDescendents( _phy );
+        }
+        catch ( final IllegalArgumentException e ) {
+            _mf.getMainPanel().getCurrentTreePanel().setArrowCursor();
+            JOptionPane.showMessageDialog( _mf,
+                                           e.getMessage(),
+                                           "Error during ancestral taxonomy inference",
+                                           JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        catch ( final UnknownHostException e ) {
+            _mf.getMainPanel().getCurrentTreePanel().setArrowCursor();
+            JOptionPane.showMessageDialog( _mf,
+                                           "Could not connect to \"" + getBaseUrl() + "\"",
+                                           "Network error during ancestral taxonomy inference",
+                                           JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        catch ( final Exception e ) {
+            _mf.getMainPanel().getCurrentTreePanel().setArrowCursor();
+            e.printStackTrace();
+            JOptionPane.showMessageDialog( _mf,
+                                           e.toString(),
+                                           "Unexpected error during ancestral taxonomy inference",
+                                           JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        _mf.getMainPanel().getCurrentTreePanel().setArrowCursor();
+        _phy.setRerootable( false );
+        _treepanel.setTree( _phy );
+        _mf.showWhole();
+        _treepanel.setEdited( true );
+        if ( ( not_found != null ) && ( not_found.size() > 0 ) ) {
+            int max = not_found.size();
+            boolean more = false;
+            if ( max > 20 ) {
+                more = true;
+                max = 20;
+            }
+            final StringBuffer sb = new StringBuffer();
+            sb.append( "Not all taxonomies could be resolved.\n" );
+            sb.append( "The result is incomplete, and, possibly, misleading.\n" );
+            if ( not_found.size() == 1 ) {
+                sb.append( "The following taxonomy was not found:\n" );
+            }
+            else {
+                sb.append( "The following taxonomies were not found (total: " + not_found.size() + "):\n" );
+            }
+            int i = 0;
+            for( final String string : not_found ) {
+                if ( i > 19 ) {
+                    break;
+                }
+                sb.append( string );
+                sb.append( "\n" );
+                ++i;
+            }
+            if ( more ) {
+                sb.append( "..." );
+            }
+            try {
+                JOptionPane.showMessageDialog( _mf,
+                                               sb.toString(),
+                                               "Ancestral Taxonomy Inference Completed",
+                                               JOptionPane.WARNING_MESSAGE );
+            }
+            catch ( final Exception e ) {
+                // Not important if this fails, do nothing. 
+            }
+        }
+        else {
+            try {
+                JOptionPane.showMessageDialog( _mf,
+                                               "Ancestral taxonomy inference successfully completed",
+                                               "Ancestral Taxonomy Inference Completed",
+                                               JOptionPane.INFORMATION_MESSAGE );
+            }
+            catch ( final Exception e ) {
+                // Not important if this fails, do nothing.
+            }
+        }
+    }
+
+    @Override
+    public void run() {
+        inferTaxonomies();
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/Archaeopteryx.java b/forester/java/src/org/forester/archaeopteryx/Archaeopteryx.java
new file mode 100644 (file)
index 0000000..7d7b9ec
--- /dev/null
@@ -0,0 +1,176 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.io.File;
+
+import org.forester.io.parsers.PhylogenyParser;
+import org.forester.io.parsers.nexus.NexusPhylogeniesParser;
+import org.forester.io.parsers.nhx.NHXParser;
+import org.forester.io.parsers.phyloxml.PhyloXmlParser;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
+import org.forester.util.ForesterUtil;
+
+// 
+// java -javaagent:shiftone-jrat.jar -cp
+// $HOME/SOFTWARE_DEV/ECLIPSE_WORKSPACE/forester-atv/java/forester.jar:.
+// org.forester.archaeopteryx.Archaeopteryx
+// -c $HOME/SOFTWARE_DEV/ECLIPSE_WORKSPACE/forester-atv/_aptx_configuration_file
+//
+public final class Archaeopteryx {
+
+    private final static boolean TEST = false; //TODO remove me!
+
+    public static MainFrame createApplication( final Phylogeny phylogeny ) {
+        final Phylogeny[] phylogenies = new Phylogeny[ 1 ];
+        phylogenies[ 0 ] = phylogeny;
+        return createApplication( phylogenies, "", "" );
+    }
+
+    public static MainFrame createApplication( final Phylogeny[] phylogenies ) {
+        return createApplication( phylogenies, "", "" );
+    }
+
+    public static MainFrame createApplication( final Phylogeny[] phylogenies,
+                                               final String config_file_name,
+                                               final String title ) {
+        return MainFrameApplication.createInstance( phylogenies, config_file_name, title );
+    }
+
+    public static void main( final String args[] ) {
+        Phylogeny[] phylogenies = null;
+        String config_filename = null;
+        Configuration conf = null;
+        File f = null;
+        try {
+            int filename_index = 0;
+            if ( args.length == 0 ) {
+                conf = new Configuration( null, false, false );
+            }
+            else if ( args.length > 0 ) {
+                // check for a config file
+                if ( args[ 0 ].startsWith( "-c" ) ) {
+                    config_filename = args[ 1 ];
+                    filename_index += 2;
+                }
+                if ( args[ 0 ].startsWith( "-open" ) ) {
+                    filename_index += 1;
+                }
+                conf = new Configuration( config_filename, false, false );
+                if ( args.length > filename_index ) {
+                    f = new File( args[ filename_index ] );
+                    final String err = ForesterUtil.isReadableFile( f );
+                    if ( !ForesterUtil.isEmpty( err ) ) {
+                        ForesterUtil.fatalError( Constants.PRG_NAME, err );
+                    }
+                    boolean nhx_or_nexus = false;
+                    final PhylogenyParser p = ForesterUtil.createParserDependingOnFileType( f, conf
+                            .isValidatePhyloXmlAgainstSchema() );
+                    if ( p instanceof NHXParser ) {
+                        nhx_or_nexus = true;
+                        final NHXParser nhx = ( NHXParser ) p;
+                        nhx.setReplaceUnderscores( conf.isReplaceUnderscoresInNhParsing() );
+                        nhx.setIgnoreQuotes( false );
+                        ForesterUtil.TAXONOMY_EXTRACTION te = ForesterUtil.TAXONOMY_EXTRACTION.NO;
+                        if ( conf.isExtractPfamTaxonomyCodesInNhParsing() ) {
+                            te = ForesterUtil.TAXONOMY_EXTRACTION.PFAM_STYLE_ONLY;
+                        }
+                        nhx.setTaxonomyExtraction( te );
+                    }
+                    else if ( p instanceof NexusPhylogeniesParser ) {
+                        nhx_or_nexus = true;
+                        final NexusPhylogeniesParser nex = ( NexusPhylogeniesParser ) p;
+                        nex.setReplaceUnderscores( conf.isReplaceUnderscoresInNhParsing() );
+                        nex.setIgnoreQuotes( false );
+                    }
+                    else if ( p instanceof PhyloXmlParser ) {
+                        MainFrameApplication.warnIfNotPhyloXmlValidation( conf );
+                    }
+                    phylogenies = Util.readPhylogenies( p, f );
+                    if ( nhx_or_nexus && conf.isInternalNumberAreConfidenceForNhParsing() ) {
+                        for( final Phylogeny phy : phylogenies ) {
+                            ForesterUtil.transferInternalNodeNamesToConfidence( phy );
+                        }
+                    }
+                    //
+                    //                                        Phylogeny py = phylogenies[ 0 ];
+                    //                                        for( final PhylogenyNodeIterator iter = py.iteratorExternalForward(); iter.hasNext(); ) {
+                    //                                            final PhylogenyNode node = iter.next();
+                    //                                            System.out.println( node.getNodeData().getTaxonomy().getScientificName() + "\t"
+                    //                                                    + node.getNodeData().getBinaryCharacters().getPresentCount() );
+                    //                                        }
+                    //                                        for( final PhylogenyNodeIterator iter = py.iteratorPreorder(); iter.hasNext(); ) {
+                    //                                            final PhylogenyNode node = iter.next();
+                    //                                            if ( !node.isExternal() ) {
+                    //                                                System.out.println( node.getNodeData().getTaxonomy().getScientificName() + "\t"
+                    //                                                        + node.getNodeData().getBinaryCharacters().getPresentCount() );
+                    //                                            }
+                    //                                        }
+                    //
+                }
+            }
+        }
+        catch ( final Exception e ) {
+            ForesterUtil.fatalError( Constants.PRG_NAME, "failed to start: " + e.getLocalizedMessage() );
+        }
+        String title = "";
+        if ( f != null ) {
+            title = f.getName();
+        }
+        try {
+            String s = "";
+            if ( TEST ) {
+                s = "/home/czmasek/888.xml";
+                if ( ForesterUtil.isReadableFile( s ) != null ) {
+                    s = "/Users/zma/888.xml";
+                    if ( ForesterUtil.isReadableFile( s ) != null ) {
+                        s = "C:\\888.xml";
+                        if ( ForesterUtil.isReadableFile( s ) != null ) {
+                            s = "C:\\Documents and Settings\\czmasek\\";
+                        }
+                    }
+                }
+            }
+            if ( !TEST ) {
+                MainFrameApplication.createInstance( phylogenies, conf, title );
+            }
+            else {
+                MainFrameApplication.createInstance( ParserBasedPhylogenyFactory.getInstance()
+                        .create( s, new PhyloXmlParser() ), conf, title );
+            }
+        }
+        // catch ( final IOException ex ) {
+        //     ForesterUtil.fatalError( Constants.PRG_NAME, "failed to start: " + ex.getLocalizedMessage() );
+        // }
+        catch ( final Exception ex ) {
+            Util.unexpectedException( ex );
+        }
+        catch ( final Error err ) {
+            Util.unexpectedError( err );
+        }
+    }
+}
\ No newline at end of file
diff --git a/forester/java/src/org/forester/archaeopteryx/ArchaeopteryxA.java b/forester/java/src/org/forester/archaeopteryx/ArchaeopteryxA.java
new file mode 100644 (file)
index 0000000..bea6a7b
--- /dev/null
@@ -0,0 +1,188 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.KeyboardFocusManager;
+import java.io.File;
+import java.net.URL;
+
+import javax.swing.JApplet;
+import javax.swing.UIManager;
+
+import org.forester.phylogeny.Phylogeny;
+import org.forester.util.ForesterUtil;
+
+public class ArchaeopteryxA extends JApplet {
+
+    private static final long  serialVersionUID    = 2314899014580484146L;
+    private final static Color background_color    = new Color( 0, 0, 0 );
+    private final static Color font_color          = new Color( 0, 255, 0 );
+    private final static Color ex_background_color = new Color( 0, 0, 0 );
+    private final static Color ex_font_color       = new Color( 255, 0, 0 );
+    private final static Font  font                = new Font( Configuration.getDefaultFontFamilyName(), Font.BOLD, 9 );
+    private MainFrameApplet    _mainframe_applet;
+    private String             _url_string         = "";
+    private String             _message_1          = "";
+    private String             _message_2          = "";
+    public final static String NAME                = "ArchaeopteryxA";
+
+    @Override
+    public void destroy() {
+        Util.printAppletMessage( NAME, "going to be destroyed" );
+        if ( getMainFrameApplet() != null ) {
+            getMainFrameApplet().close();
+        }
+    }
+
+    private MainFrameApplet getMainFrameApplet() {
+        return _mainframe_applet;
+    }
+
+    private String getMessage1() {
+        return _message_1;
+    }
+
+    private String getMessage2() {
+        return _message_2;
+    }
+
+    public String getUrlString() {
+        return _url_string;
+    }
+
+    @Override
+    public void init() {
+        boolean has_exception = false;
+        setName( NAME );
+        setUrlString( getParameter( Constants.APPLET_PARAM_NAME_FOR_URL_OF_TREE_TO_LOAD ) );
+        Util.printAppletMessage( NAME, "URL of phylogenies to load: \"" + getUrlString() + "\"" );
+        setBackground( background_color );
+        setForeground( font_color );
+        setFont( font );
+        repaint();
+        String s = null;
+        try {
+            s = System.getProperty( "java.version" );
+        }
+        catch ( final Exception e ) {
+            ForesterUtil.printWarningMessage( NAME, "minor error: " + e.getLocalizedMessage() );
+        }
+        if ( ( s != null ) && ( s.length() > 0 ) ) {
+            setMessage2( "[Your Java version: " + s + "]" );
+            repaint();
+        }
+        final String config_filename = getParameter( Constants.APPLET_PARAM_NAME_FOR_CONFIG_FILE_URL );
+        Util.printAppletMessage( NAME, "URL for configuration file is: " + config_filename );
+        final Configuration configuration = new Configuration( config_filename, true, true );
+        try {
+            if ( configuration.isUseNativeUI() ) {
+                UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
+            }
+            else {
+                UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
+            }
+            setVisible( false );
+            _mainframe_applet = new MainFrameApplet( this, configuration );
+            URL url = null;
+            url = new URL( getUrlString() );
+            final Phylogeny[] phys = Util.readPhylogeniesFromUrl( url, configuration.isValidatePhyloXmlAgainstSchema() );
+            Util.addPhylogeniesToTabs( phys, new File( url.getFile() ).getName(), getUrlString(), getMainFrameApplet()
+                    .getConfiguration(), getMainFrameApplet().getMainPanel() );
+            getMainFrameApplet().getMainPanel().getControlPanel().showWholeAll();
+            getMainFrameApplet().getMainPanel().getControlPanel().showWhole();
+            setVisible( true );
+        }
+        catch ( final Exception e ) {
+            ForesterUtil.printErrorMessage( NAME, e.toString() );
+            setBackground( ex_background_color );
+            setForeground( ex_font_color );
+            has_exception = true;
+            setMessage1( "Exception: " + e );
+            e.printStackTrace();
+            repaint();
+        }
+        if ( !has_exception ) {
+            setMessage1( NAME + " is now ready!" );
+            repaint();
+            Util.printAppletMessage( NAME, "successfully initialized" );
+        }
+        KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
+        getMainFrameApplet().requestFocus();
+        getMainFrameApplet().requestFocusInWindow();
+        getMainFrameApplet().requestFocus();
+        /* GUILHEM_BEG */
+        final String default_relation = getParameter( Constants.APPLET_PARAM_NAME_FOR_DEFAULT_SEQUENCE_RELATION_TYPE );
+        if ( default_relation != null ) {
+            getMainFrameApplet().getMainPanel().getControlPanel().getSequenceRelationTypeBox()
+                    .setSelectedItem( default_relation );
+        }
+        final String default_sequence = getParameter( Constants.APPLET_PARAM_NAME_FOR_DEFAULT_QUERY_SEQUENCE );
+        if ( default_sequence != null ) {
+            getMainFrameApplet().getMainPanel().getControlPanel().getSequenceRelationBox()
+                    .setSelectedItem( default_sequence );
+            /* GUILHEM_END */
+        }
+    }
+
+    /**
+     * Prints message when initialization is finished. Called automatically.
+     * 
+     * @param g
+     *            Graphics
+     */
+    @Override
+    public void paint( final Graphics g ) {
+        g.setColor( background_color );
+        g.fillRect( 0, 0, 300, 60 );
+        g.setColor( font_color );
+        g.drawString( getMessage2(), 10, 20 );
+        g.drawString( getMessage1(), 10, 40 );
+    }
+
+    private void setMessage1( final String message_1 ) {
+        _message_1 = message_1;
+    }
+
+    private void setMessage2( final String message_2 ) {
+        _message_2 = message_2;
+    }
+
+    private void setUrlString( final String url_string ) {
+        _url_string = url_string;
+    }
+
+    @Override
+    public void start() {
+        getMainFrameApplet().getMainPanel().validate();
+        getMainFrameApplet().requestFocus();
+        getMainFrameApplet().requestFocusInWindow();
+        getMainFrameApplet().requestFocus();
+        Util.printAppletMessage( NAME, "started" );
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/ArchaeopteryxE.java b/forester/java/src/org/forester/archaeopteryx/ArchaeopteryxE.java
new file mode 100644 (file)
index 0000000..b4e4e87
--- /dev/null
@@ -0,0 +1,998 @@
+
+package org.forester.archaeopteryx;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.List;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JApplet;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.forester.archaeopteryx.Options.CLADOGRAM_TYPE;
+import org.forester.archaeopteryx.Options.NODE_LABEL_DIRECTION;
+import org.forester.archaeopteryx.Options.PHYLOGENY_GRAPHICS_TYPE;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.phylogeny.data.SequenceRelation;
+import org.forester.util.ForesterUtil;
+
+// Use like this:
+// <applet archive="forester.jar"
+// code="org.forester.archaeopteryx.ArchaeopteryxE.class"
+// codebase="http://www.myserver.org/path/to/forester"
+// width="600"
+// height="500"
+// alt="ArchaeopteryxE is not working on your system (requires at least Sun Java 1.5)!">
+// <param name="url_of_tree_to_load"
+// value="http://www.myserver.org/examples/data/apaf.xml">
+// <param name="config_file"
+// value="http://www.myserver.org/examples/config/config_file.txt">
+// </applet>
+public class ArchaeopteryxE extends JApplet implements ActionListener {
+
+    private final static String  NAME             = "ArchaeopteryxE";
+    private static final long    serialVersionUID = -1220055577935759443L;
+    private Configuration        _configuration;
+    private MainPanelApplets     _main_panel;
+    private JMenuBar             _jmenubar;
+    private JMenu                _options_jmenu;
+    private JMenu                _font_size_menu;
+    private JMenuItem            _super_tiny_fonts_mi;
+    private JMenuItem            _tiny_fonts_mi;
+    private JMenuItem            _small_fonts_mi;
+    private JMenuItem            _medium_fonts_mi;
+    private JMenuItem            _large_fonts_mi;
+    private TextFrame            _textframe;
+    private JMenu                _tools_menu;
+    private JMenuItem            _taxcolor_item;
+    private JMenuItem            _confcolor_item;
+    private JMenuItem            _midpoint_root_item;
+    private JMenu                _view_jmenu;
+    private JMenuItem            _view_as_XML_item;
+    private JMenuItem            _view_as_NH_item;
+    private JMenuItem            _view_as_NHX_item;
+    private JMenuItem            _view_as_nexus_item;
+    private JMenu                _type_menu;
+    private JCheckBoxMenuItem    _rectangular_type_cbmi;
+    private JCheckBoxMenuItem    _triangular_type_cbmi;
+    private JCheckBoxMenuItem    _curved_type_cbmi;
+    private JCheckBoxMenuItem    _convex_type_cbmi;
+    private JCheckBoxMenuItem    _euro_type_cbmi;
+    private JCheckBoxMenuItem    _rounded_type_cbmi;
+    private JCheckBoxMenuItem    _unrooted_type_cbmi;
+    private JCheckBoxMenuItem    _circular_type_cbmi;
+    private JMenuItem            _help_item;
+    private JMenuItem            _about_item;
+    private JMenu                _help_jmenu;
+    private JMenuItem            _website_item;
+    private JMenuItem            _phyloxml_website_item;
+    private JMenuItem            _phyloxml_ref_item;
+    private JMenuItem            _aptx_ref_item;
+    private JMenuItem            _remove_branch_color_item;
+    private JMenuItem            _infer_common_sn_names_item;
+    private JCheckBoxMenuItem    _show_domain_labels;
+    private JCheckBoxMenuItem    _color_labels_same_as_parent_branch;
+    private JCheckBoxMenuItem    _abbreviate_scientific_names;
+    private JCheckBoxMenuItem    _screen_antialias_cbmi;
+    private JCheckBoxMenuItem    _background_gradient_cbmi;
+    private JRadioButtonMenuItem _non_lined_up_cladograms_rbmi;
+    private JRadioButtonMenuItem _uniform_cladograms_rbmi;
+    private JRadioButtonMenuItem _ext_node_dependent_cladogram_rbmi;
+    private Options              _options;
+    private JMenuItem            _choose_font_mi;
+    private JMenuItem            _switch_colors_mi;
+    JCheckBoxMenuItem            _label_direction_cbmi;
+    private JCheckBoxMenuItem    _show_node_boxes_cbmi;
+    private JCheckBoxMenuItem    _show_scale_cbmi;
+    private JCheckBoxMenuItem    _search_case_senstive_cbmi;
+    private JCheckBoxMenuItem    _search_whole_words_only_cbmi;
+    private JCheckBoxMenuItem    _inverse_search_result_cbmi;
+    private JCheckBoxMenuItem    _show_overview_cbmi;
+    private JMenuItem            _choose_minimal_confidence_mi;
+    private JCheckBoxMenuItem    _show_branch_length_values_cbmi;
+    private JMenuItem            _collapse_species_specific_subtrees;
+    private JMenuItem            _overview_placment_mi;
+    private ButtonGroup          _radio_group_1;
+
+    public void actionPerformed( final ActionEvent e ) {
+        final Object o = e.getSource();
+        if ( o == _midpoint_root_item ) {
+            getMainPanel().getCurrentTreePanel().midpointRoot();
+        }
+        else if ( o == _taxcolor_item ) {
+            getMainPanel().getCurrentTreePanel().taxColor();
+        }
+        else if ( o == _confcolor_item ) {
+            getMainPanel().getCurrentTreePanel().confColor();
+        }
+        else if ( o == _infer_common_sn_names_item ) {
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().inferCommonPartOfScientificNames();
+            }
+        }
+        else if ( o == _collapse_species_specific_subtrees ) {
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().collapseSpeciesSpecificSubtrees();
+            }
+        }
+        else if ( o == _remove_branch_color_item ) {
+            removeBranchColors();
+        }
+        else if ( o == _switch_colors_mi ) {
+            switchColors();
+        }
+        else if ( o == _view_as_NH_item ) {
+            viewAsNH();
+        }
+        else if ( o == _view_as_NHX_item ) {
+            viewAsNHX();
+        }
+        else if ( o == _view_as_XML_item ) {
+            viewAsXML();
+        }
+        else if ( o == _view_as_nexus_item ) {
+            viewAsNexus();
+        }
+        else if ( o == _super_tiny_fonts_mi ) {
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().setSuperTinyFonts();
+                getCurrentTreePanel().repaint();
+            }
+        }
+        else if ( o == _tiny_fonts_mi ) {
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().setTinyFonts();
+                getCurrentTreePanel().repaint();
+            }
+        }
+        else if ( o == _small_fonts_mi ) {
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().setSmallFonts();
+                getCurrentTreePanel().repaint();
+            }
+        }
+        else if ( o == _medium_fonts_mi ) {
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().setMediumFonts();
+                getCurrentTreePanel().repaint();
+            }
+        }
+        else if ( o == _large_fonts_mi ) {
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().setLargeFonts();
+                getCurrentTreePanel().repaint();
+            }
+        }
+        else if ( o == _choose_font_mi ) {
+            chooseFont();
+        }
+        else if ( o == _choose_minimal_confidence_mi ) {
+            chooseMinimalConfidence();
+        }
+        else if ( o == _overview_placment_mi ) {
+            MainFrame.cycleOverview( getOptions(), getCurrentTreePanel() );
+        }
+        else if ( o == _show_node_boxes_cbmi ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _non_lined_up_cladograms_rbmi ) {
+            updateOptions( getOptions() );
+            _main_panel.getControlPanel().showWhole();
+        }
+        else if ( o == _uniform_cladograms_rbmi ) {
+            updateOptions( getOptions() );
+            _main_panel.getControlPanel().showWhole();
+        }
+        else if ( o == _ext_node_dependent_cladogram_rbmi ) {
+            updateOptions( getOptions() );
+            _main_panel.getControlPanel().showWhole();
+        }
+        else if ( o == _search_case_senstive_cbmi ) {
+            updateOptions( getOptions() );
+            getMainPanel().getControlPanel().search();
+        }
+        else if ( o == _search_whole_words_only_cbmi ) {
+            updateOptions( getOptions() );
+            getMainPanel().getControlPanel().search();
+        }
+        else if ( o == _inverse_search_result_cbmi ) {
+            updateOptions( getOptions() );
+            getMainPanel().getControlPanel().search();
+        }
+        else if ( o == _show_scale_cbmi ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _show_branch_length_values_cbmi ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _label_direction_cbmi ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _show_overview_cbmi ) {
+            updateOptions( getOptions() );
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().updateOvSizes();
+            }
+        }
+        else if ( ( o == _rectangular_type_cbmi ) || ( o == _triangular_type_cbmi ) || ( o == _curved_type_cbmi )
+                || ( o == _convex_type_cbmi ) || ( o == _rounded_type_cbmi ) || ( o == _euro_type_cbmi )
+                || ( o == _unrooted_type_cbmi ) || ( o == _circular_type_cbmi ) ) {
+            typeChanged( o );
+        }
+        else if ( o == _screen_antialias_cbmi ) {
+            updateOptions( getOptions() );
+            setupScreenTextAntialias( getMainPanel().getTreePanels(), isScreenAntialias() );
+        }
+        else if ( o == _background_gradient_cbmi ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _show_domain_labels ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _color_labels_same_as_parent_branch ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _about_item ) {
+            MainFrame.about();
+        }
+        else if ( o == _help_item ) {
+            MainFrame.help( getConfiguration().getWebLinks() );
+        }
+        else if ( o == _website_item ) {
+            try {
+                Util.openWebsite( Constants.APTX_WEB_SITE, true, this );
+            }
+            catch ( final IOException e1 ) {
+                ForesterUtil.printErrorMessage( Constants.PRG_NAME, e1.toString() );
+            }
+        }
+        else if ( o == _phyloxml_website_item ) {
+            try {
+                Util.openWebsite( Constants.PHYLOXML_WEB_SITE, true, this );
+            }
+            catch ( final IOException e1 ) {
+                ForesterUtil.printErrorMessage( Constants.PRG_NAME, e1.toString() );
+            }
+        }
+        else if ( o == _aptx_ref_item ) {
+            try {
+                Util.openWebsite( Constants.APTX_REFERENCE_URL, true, this );
+            }
+            catch ( final IOException e1 ) {
+                ForesterUtil.printErrorMessage( Constants.PRG_NAME, e1.toString() );
+            }
+        }
+        else if ( o == _phyloxml_ref_item ) {
+            try {
+                Util.openWebsite( Constants.PHYLOXML_REFERENCE_URL, true, this );
+            }
+            catch ( final IOException e1 ) {
+                ForesterUtil.printErrorMessage( Constants.PRG_NAME, e1.toString() );
+            }
+        }
+        repaint();
+    }
+
+    void buildFontSizeMenu() {
+        _font_size_menu = MainFrame.createMenu( MainFrame.FONT_SIZE_MENU_LABEL, getConfiguration() );
+        _font_size_menu.add( _super_tiny_fonts_mi = new JMenuItem( "Super tiny fonts" ) );
+        _font_size_menu.add( _tiny_fonts_mi = new JMenuItem( "Tiny fonts" ) );
+        _font_size_menu.add( _small_fonts_mi = new JMenuItem( "Small fonts" ) );
+        _font_size_menu.add( _medium_fonts_mi = new JMenuItem( "Medium fonts" ) );
+        _font_size_menu.add( _large_fonts_mi = new JMenuItem( "Large fonts" ) );
+        customizeJMenuItem( _super_tiny_fonts_mi );
+        customizeJMenuItem( _tiny_fonts_mi );
+        customizeJMenuItem( _small_fonts_mi );
+        customizeJMenuItem( _medium_fonts_mi );
+        customizeJMenuItem( _large_fonts_mi );
+        _jmenubar.add( _font_size_menu );
+    }
+
+    void buildHelpMenu() {
+        _help_jmenu = MainFrame.createMenu( "Help", getConfiguration() );
+        _help_jmenu.add( _help_item = new JMenuItem( "Help" ) );
+        _help_jmenu.add( _website_item = new JMenuItem( "Archaeopteryx Home" ) );
+        _aptx_ref_item = new JMenuItem( "Archaeopteryx Reference" );
+        _help_jmenu.add( _phyloxml_website_item = new JMenuItem( "phyloXML Home" ) );
+        _help_jmenu.add( _phyloxml_ref_item = new JMenuItem( "phyloXML Reference" ) );
+        _help_jmenu.addSeparator();
+        _help_jmenu.add( _about_item = new JMenuItem( "About" ) );
+        customizeJMenuItem( _help_item );
+        customizeJMenuItem( _website_item );
+        customizeJMenuItem( _phyloxml_website_item );
+        customizeJMenuItem( _aptx_ref_item );
+        customizeJMenuItem( _phyloxml_ref_item );
+        customizeJMenuItem( _about_item );
+        _phyloxml_ref_item.setToolTipText( MainFrame.PHYLOXML_REF_TOOL_TIP );
+        _aptx_ref_item.setToolTipText( MainFrame.APTX_REF_TOOL_TIP );
+        _jmenubar.add( _help_jmenu );
+    }
+
+    void buildOptionsMenu() {
+        _options_jmenu = MainFrame.createMenu( MainFrame.OPTIONS_HEADER, getConfiguration() );
+        _options_jmenu.addChangeListener( new ChangeListener() {
+
+            public void stateChanged( final ChangeEvent e ) {
+                MainFrame.setOvPlacementColorChooseMenuItem( _overview_placment_mi, getCurrentTreePanel() );
+                MainFrame.setTextColorChooseMenuItem( _switch_colors_mi, getCurrentTreePanel() );
+                MainFrame
+                        .setTextMinSupportMenuItem( _choose_minimal_confidence_mi, getOptions(), getCurrentTreePanel() );
+                MainFrame.setTextForFontChooserMenuItem( _choose_font_mi, MainFrame
+                        .createCurrentFontDesc( getMainPanel().getTreeFontSet() ) );
+                MainFrame.updateOptionsMenuDependingOnPhylogenyType( getMainPanel(),
+                                                                     _show_scale_cbmi,
+                                                                     _show_branch_length_values_cbmi,
+                                                                     _non_lined_up_cladograms_rbmi,
+                                                                     _uniform_cladograms_rbmi,
+                                                                     _ext_node_dependent_cladogram_rbmi,
+                                                                     _label_direction_cbmi );
+            }
+        } );
+        _options_jmenu.add( MainFrame.customizeMenuItemAsLabel( new JMenuItem( MainFrame.DISPLAY_SUBHEADER ),
+                                                                getConfiguration() ) );
+        _options_jmenu
+                .add( _ext_node_dependent_cladogram_rbmi = new JRadioButtonMenuItem( MainFrame.NONUNIFORM_CLADOGRAMS_LABEL ) );
+        _options_jmenu.add( _uniform_cladograms_rbmi = new JRadioButtonMenuItem( MainFrame.UNIFORM_CLADOGRAMS_LABEL ) );
+        _options_jmenu
+                .add( _non_lined_up_cladograms_rbmi = new JRadioButtonMenuItem( MainFrame.NON_LINED_UP_CLADOGRAMS_LABEL ) );
+        _radio_group_1 = new ButtonGroup();
+        _radio_group_1.add( _ext_node_dependent_cladogram_rbmi );
+        _radio_group_1.add( _uniform_cladograms_rbmi );
+        _radio_group_1.add( _non_lined_up_cladograms_rbmi );
+        _options_jmenu.add( _show_node_boxes_cbmi = new JCheckBoxMenuItem( MainFrame.DISPLAY_NODE_BOXES_LABEL ) );
+        _options_jmenu.add( _show_scale_cbmi = new JCheckBoxMenuItem( MainFrame.DISPLAY_SCALE_LABEL ) );
+        _options_jmenu
+                .add( _show_branch_length_values_cbmi = new JCheckBoxMenuItem( MainFrame.DISPLAY_BRANCH_LENGTH_VALUES_LABEL ) );
+        _options_jmenu.add( _show_overview_cbmi = new JCheckBoxMenuItem( MainFrame.SHOW_OVERVIEW_LABEL ) );
+        _options_jmenu.add( _label_direction_cbmi = new JCheckBoxMenuItem( MainFrame.LABEL_DIRECTION_LABEL ) );
+        _options_jmenu
+                .add( _color_labels_same_as_parent_branch = new JCheckBoxMenuItem( MainFrame.COLOR_LABELS_LABEL ) );
+        _color_labels_same_as_parent_branch.setToolTipText( MainFrame.COLOR_LABELS_TIP );
+        _options_jmenu.add( _abbreviate_scientific_names = new JCheckBoxMenuItem( MainFrame.ABBREV_SN_LABEL ) );
+        _label_direction_cbmi.setToolTipText( MainFrame.LABEL_DIRECTION_TIP );
+        _options_jmenu.add( _screen_antialias_cbmi = new JCheckBoxMenuItem( MainFrame.SCREEN_ANTIALIAS_LABEL ) );
+        _options_jmenu.add( _background_gradient_cbmi = new JCheckBoxMenuItem( MainFrame.BG_GRAD_LABEL ) );
+        if ( getConfiguration().doDisplayOption( Configuration.show_domain_architectures ) ) {
+            _options_jmenu.add( _show_domain_labels = new JCheckBoxMenuItem( MainFrame.SHOW_DOMAIN_LABELS_LABEL ) );
+        }
+        _options_jmenu.add( _choose_minimal_confidence_mi = new JMenuItem( "" ) );
+        _options_jmenu.add( _overview_placment_mi = new JMenuItem( "" ) );
+        _options_jmenu.add( _switch_colors_mi = new JMenuItem( "" ) );
+        _options_jmenu.add( _choose_font_mi = new JMenuItem( "" ) );
+        _options_jmenu.addSeparator();
+        _options_jmenu.add( MainFrame.customizeMenuItemAsLabel( new JMenuItem( MainFrame.SEARCH_SUBHEADER ),
+                                                                getConfiguration() ) );
+        _options_jmenu
+                .add( _search_case_senstive_cbmi = new JCheckBoxMenuItem( MainFrame.SEARCH_CASE_SENSITIVE_LABEL ) );
+        _options_jmenu.add( _search_whole_words_only_cbmi = new JCheckBoxMenuItem( MainFrame.SEARCH_TERMS_ONLY_LABEL ) );
+        _options_jmenu
+                .add( _inverse_search_result_cbmi = new JCheckBoxMenuItem( MainFrame.INVERSE_SEARCH_RESULT_LABEL ) );
+        customizeJMenuItem( _choose_font_mi );
+        customizeJMenuItem( _choose_minimal_confidence_mi );
+        customizeJMenuItem( _switch_colors_mi );
+        customizeJMenuItem( _overview_placment_mi );
+        customizeCheckBoxMenuItem( _show_node_boxes_cbmi, getOptions().isShowNodeBoxes() );
+        customizeCheckBoxMenuItem( _label_direction_cbmi,
+                                   getOptions().getNodeLabelDirection() == NODE_LABEL_DIRECTION.RADIAL );
+        customizeCheckBoxMenuItem( _screen_antialias_cbmi, getOptions().isAntialiasScreen() );
+        customizeCheckBoxMenuItem( _background_gradient_cbmi, getOptions().isBackgroundColorGradient() );
+        customizeCheckBoxMenuItem( _show_domain_labels, getOptions().isShowDomainLabels() );
+        customizeCheckBoxMenuItem( _abbreviate_scientific_names, getOptions().isAbbreviateScientificTaxonNames() );
+        customizeCheckBoxMenuItem( _color_labels_same_as_parent_branch, getOptions().isColorLabelsSameAsParentBranch() );
+        customizeCheckBoxMenuItem( _search_case_senstive_cbmi, getOptions().isSearchCaseSensitive() );
+        customizeCheckBoxMenuItem( _show_scale_cbmi, getOptions().isShowScale() );
+        customizeRadioButtonMenuItem( _non_lined_up_cladograms_rbmi,
+                                      getOptions().getCladogramType() == CLADOGRAM_TYPE.NON_LINED_UP );
+        customizeRadioButtonMenuItem( _uniform_cladograms_rbmi,
+                                      getOptions().getCladogramType() == CLADOGRAM_TYPE.TOTAL_NODE_SUM_DEP );
+        customizeRadioButtonMenuItem( _ext_node_dependent_cladogram_rbmi,
+                                      getOptions().getCladogramType() == CLADOGRAM_TYPE.EXT_NODE_SUM_DEP );
+        customizeCheckBoxMenuItem( _show_branch_length_values_cbmi, getOptions().isShowBranchLengthValues() );
+        customizeCheckBoxMenuItem( _show_overview_cbmi, getOptions().isShowOverview() );
+        customizeCheckBoxMenuItem( _search_whole_words_only_cbmi, getOptions().isMatchWholeTermsOnly() );
+        customizeCheckBoxMenuItem( _inverse_search_result_cbmi, getOptions().isInverseSearchResult() );
+        _jmenubar.add( _options_jmenu );
+    }
+
+    void buildToolsMenu() {
+        _tools_menu = MainFrame.createMenu( "Tools", getConfiguration() );
+        _tools_menu.add( _confcolor_item = new JMenuItem( "Colorize Branches Depending on Confidence" ) );
+        customizeJMenuItem( _confcolor_item );
+        _tools_menu.add( _taxcolor_item = new JMenuItem( "Taxonomy Colorize Branches" ) );
+        customizeJMenuItem( _taxcolor_item );
+        _tools_menu.add( _remove_branch_color_item = new JMenuItem( "Delete Branch Colors" ) );
+        _remove_branch_color_item.setToolTipText( "To delete branch color values from the current phylogeny." );
+        customizeJMenuItem( _remove_branch_color_item );
+        _tools_menu.addSeparator();
+        _tools_menu.add( _midpoint_root_item = new JMenuItem( "Midpoint-Root" ) );
+        customizeJMenuItem( _midpoint_root_item );
+        _tools_menu.addSeparator();
+        _tools_menu
+                .add( _infer_common_sn_names_item = new JMenuItem( "Infer Common Parts of Internal Scientific Names" ) );
+        customizeJMenuItem( _infer_common_sn_names_item );
+        _tools_menu.add( _collapse_species_specific_subtrees = new JMenuItem( "Collapse Species-Specific Subtrees" ) );
+        customizeJMenuItem( _collapse_species_specific_subtrees );
+        _jmenubar.add( _tools_menu );
+    }
+
+    void buildTypeMenu() {
+        _type_menu = MainFrame.createMenu( MainFrame.TYPE_MENU_HEADER, getConfiguration() );
+        _type_menu.add( _rectangular_type_cbmi = new JCheckBoxMenuItem( MainFrame.RECTANGULAR_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _euro_type_cbmi = new JCheckBoxMenuItem( MainFrame.EURO_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _rounded_type_cbmi = new JCheckBoxMenuItem( MainFrame.ROUNDED_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _curved_type_cbmi = new JCheckBoxMenuItem( MainFrame.CURVED_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _triangular_type_cbmi = new JCheckBoxMenuItem( MainFrame.TRIANGULAR_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _convex_type_cbmi = new JCheckBoxMenuItem( MainFrame.CONVEX_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _unrooted_type_cbmi = new JCheckBoxMenuItem( MainFrame.UNROOTED_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _circular_type_cbmi = new JCheckBoxMenuItem( MainFrame.CIRCULAR_TYPE_CBMI_LABEL ) );
+        customizeCheckBoxMenuItem( _rectangular_type_cbmi, false );
+        customizeCheckBoxMenuItem( _triangular_type_cbmi, false );
+        customizeCheckBoxMenuItem( _euro_type_cbmi, false );
+        customizeCheckBoxMenuItem( _rounded_type_cbmi, false );
+        customizeCheckBoxMenuItem( _curved_type_cbmi, false );
+        customizeCheckBoxMenuItem( _convex_type_cbmi, false );
+        customizeCheckBoxMenuItem( _unrooted_type_cbmi, false );
+        customizeCheckBoxMenuItem( _circular_type_cbmi, false );
+        _unrooted_type_cbmi.setToolTipText( MainFrame.USE_MOUSEWHEEL_SHIFT_TO_ROTATE );
+        _circular_type_cbmi.setToolTipText( MainFrame.USE_MOUSEWHEEL_SHIFT_TO_ROTATE );
+        initializeTypeMenu( getOptions() );
+        _jmenubar.add( _type_menu );
+    }
+
+    void buildViewMenu() {
+        _view_jmenu = MainFrame.createMenu( "View as Text", getConfiguration() );
+        _view_jmenu.add( _view_as_XML_item = new JMenuItem( "View as phyloXML" ) );
+        _view_jmenu.add( _view_as_NH_item = new JMenuItem( "View as Newick" ) );
+        _view_jmenu.add( _view_as_NHX_item = new JMenuItem( "View as NHX" ) );
+        _view_jmenu.add( _view_as_nexus_item = new JMenuItem( "View as Nexus" ) );
+        customizeJMenuItem( _view_as_NH_item );
+        customizeJMenuItem( _view_as_NHX_item );
+        customizeJMenuItem( _view_as_XML_item );
+        customizeJMenuItem( _view_as_nexus_item );
+        _jmenubar.add( _view_jmenu );
+    }
+
+    private void chooseFont() {
+        final FontChooser fc = new FontChooser();
+        fc.setFont( getMainPanel().getTreeFontSet().getLargeFont() );
+        fc.showDialog( this, "Select the Base Font" );
+        getMainPanel().getTreeFontSet().setBaseFont( fc.getFont() );
+    }
+
+    private void chooseMinimalConfidence() {
+        final String s = ( String ) JOptionPane
+                .showInputDialog( this,
+                                  "Please the minimum for confidence values to be displayed.\n" + "[current value: "
+                                          + getOptions().getMinConfidenceValue() + "]\n",
+                                  "Minimal Confidence Value",
+                                  JOptionPane.QUESTION_MESSAGE,
+                                  null,
+                                  null,
+                                  getOptions().getMinConfidenceValue() );
+        if ( !ForesterUtil.isEmpty( s ) ) {
+            boolean success = true;
+            double m = 0.0;
+            final String m_str = s.trim();
+            if ( !ForesterUtil.isEmpty( m_str ) ) {
+                try {
+                    m = Double.parseDouble( m_str );
+                }
+                catch ( final Exception ex ) {
+                    success = false;
+                }
+            }
+            else {
+                success = false;
+            }
+            if ( success && ( m >= 0.0 ) ) {
+                getOptions().setMinConfidenceValue( m );
+            }
+        }
+    }
+
+    void customizeCheckBoxMenuItem( final JCheckBoxMenuItem item, final boolean is_selected ) {
+        if ( item != null ) {
+            item.setFont( MainFrame.menu_font );
+            if ( !getConfiguration().isUseNativeUI() ) {
+                item.setBackground( getConfiguration().getGuiMenuBackgroundColor() );
+                item.setForeground( getConfiguration().getGuiMenuTextColor() );
+            }
+            item.setSelected( is_selected );
+            item.addActionListener( this );
+        }
+    }
+
+    void customizeJMenuItem( final JMenuItem jmi ) {
+        jmi.setFont( MainFrame.menu_font );
+        if ( !getConfiguration().isUseNativeUI() ) {
+            jmi.setBackground( getConfiguration().getGuiMenuBackgroundColor() );
+            jmi.setForeground( getConfiguration().getGuiMenuTextColor() );
+        }
+        jmi.addActionListener( this );
+    }
+
+    private void customizeRadioButtonMenuItem( final JRadioButtonMenuItem item, final boolean is_selected ) {
+        if ( item != null ) {
+            item.setFont( MainFrame.menu_font );
+            if ( !getConfiguration().isUseNativeUI() ) {
+                item.setBackground( getConfiguration().getGuiMenuBackgroundColor() );
+                item.setForeground( getConfiguration().getGuiMenuTextColor() );
+            }
+            item.setSelected( is_selected );
+            item.addActionListener( this );
+        }
+    }
+
+    @Override
+    public void destroy() {
+        Util.printAppletMessage( NAME, "going to be destroyed " );
+        removeTextFrame();
+        if ( getMainPanel() != null ) {
+            getMainPanel().terminate();
+        }
+    }
+
+    Configuration getConfiguration() {
+        return _configuration;
+    }
+
+    TreePanel getCurrentTreePanel() {
+        return getMainPanel().getCurrentTreePanel();
+    }
+
+    JCheckBoxMenuItem getlabelDirectionCbmi() {
+        return _label_direction_cbmi;
+    }
+
+    private MainPanel getMainPanel() {
+        return _main_panel;
+    }
+
+    public Options getOptions() {
+        return _options;
+    }
+
+    Options getOtions() {
+        return _options;
+    }
+
+    @Override
+    public void init() {
+        final String config_filename = getParameter( Constants.APPLET_PARAM_NAME_FOR_CONFIG_FILE_URL );
+        Util.printAppletMessage( NAME, "URL for configuration file is: " + config_filename );
+        final Configuration configuration = new Configuration( config_filename, true, true );
+        setConfiguration( configuration );
+        setOptions( Options.createInstance( configuration ) );
+        setupUI();
+        URL phys_url = null;
+        Phylogeny[] phys = null;
+        final String phys_url_string = getParameter( Constants.APPLET_PARAM_NAME_FOR_URL_OF_TREE_TO_LOAD );
+        Util.printAppletMessage( NAME, "URL for phylogenies is " + phys_url_string );
+        // Get URL to tree file
+        if ( phys_url_string != null ) {
+            try {
+                phys_url = new URL( phys_url_string );
+            }
+            catch ( final Exception e ) {
+                ForesterUtil.printErrorMessage( NAME, "error: " + e );
+                e.printStackTrace();
+                JOptionPane.showMessageDialog( this, NAME + ": Could not create URL from: \"" + phys_url_string
+                        + "\"\nException: " + e, "Failed to create URL", JOptionPane.ERROR_MESSAGE );
+            }
+        }
+        // Load the tree from URL
+        if ( phys_url != null ) {
+            try {
+                phys = Util.readPhylogeniesFromUrl( phys_url, getConfiguration().isValidatePhyloXmlAgainstSchema() );
+            }
+            catch ( final Exception e ) {
+                ForesterUtil.printErrorMessage( NAME, e.toString() );
+                e.printStackTrace();
+                JOptionPane.showMessageDialog( this,
+                                               NAME + ": Failed to read phylogenies: " + "\nException: " + e,
+                                               "Failed to read phylogenies",
+                                               JOptionPane.ERROR_MESSAGE );
+            }
+        }
+        if ( ( phys == null ) || ( phys.length < 1 ) ) {
+            ForesterUtil.printErrorMessage( NAME, "phylogenies from [" + phys_url + "] are null or empty" );
+            JOptionPane.showMessageDialog( this,
+                                           NAME + ": phylogenies from [" + phys_url + "] are null or empty",
+                                           "Failed to read phylogenies",
+                                           JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        else {
+            Util.printAppletMessage( NAME, "loaded " + phys.length + " phylogenies from: " + phys_url );
+        }
+        setVisible( false );
+        setMainPanel( new MainPanelApplets( getConfiguration(), this ) );
+        _jmenubar = new JMenuBar();
+        if ( !getConfiguration().isHideControlPanelAndMenubar() ) {
+            if ( !getConfiguration().isUseNativeUI() ) {
+                _jmenubar.setBackground( getConfiguration().getGuiMenuBackgroundColor() );
+            }
+            buildToolsMenu();
+            buildViewMenu();
+            buildFontSizeMenu();
+            buildOptionsMenu();
+            buildTypeMenu();
+            buildHelpMenu();
+            setJMenuBar( _jmenubar );
+        }
+        final Container contentpane = getContentPane();
+        contentpane.setLayout( new BorderLayout() );
+        contentpane.add( getMainPanel(), BorderLayout.CENTER );
+        addComponentListener( new ComponentAdapter() {
+
+            @Override
+            public void componentResized( final ComponentEvent e ) {
+                if ( getMainPanel().getCurrentTreePanel() != null ) {
+                    getMainPanel().getCurrentTreePanel().setParametersForPainting( getMainPanel().getCurrentTreePanel()
+                                                                                           .getWidth(),
+                                                                                   getMainPanel().getCurrentTreePanel()
+                                                                                           .getHeight(),
+                                                                                   false );
+                }
+            }
+        } );
+        if ( getConfiguration().isUseTabbedDisplay() ) {
+            Util.printAppletMessage( NAME, "using tabbed display" );
+            Util.addPhylogeniesToTabs( phys,
+                                       new File( phys_url.getFile() ).getName(),
+                                       phys_url.toString(),
+                                       getConfiguration(),
+                                       getMainPanel() );
+        }
+        else {
+            Util.printAppletMessage( NAME, "not using tabbed display" );
+            Util.addPhylogenyToPanel( phys, getConfiguration(), getMainPanel() );
+        }
+        validate();
+        setName( NAME );
+        getMainPanel().getControlPanel().showWholeAll();
+        getMainPanel().getControlPanel().showWhole();
+        System.gc();
+        Util.printAppletMessage( NAME, "successfully initialized" );
+        /* GUILHEM_BEG */
+        getCurrentTreePanel().getControlPanel().getSequenceRelationTypeBox().removeAllItems();
+        for( final SequenceRelation.SEQUENCE_RELATION_TYPE type : getMainPanel().getCurrentPhylogeny()
+                .getRelevantSequenceRelationTypes() ) {
+            getCurrentTreePanel().getControlPanel().getSequenceRelationTypeBox().addItem( type );
+        }
+        final String default_relation = getParameter( Constants.APPLET_PARAM_NAME_FOR_DEFAULT_SEQUENCE_RELATION_TYPE );
+        if ( default_relation != null ) {
+            getCurrentTreePanel().getControlPanel().getSequenceRelationTypeBox().setSelectedItem( default_relation );
+        }
+        final String default_sequence = getParameter( Constants.APPLET_PARAM_NAME_FOR_DEFAULT_QUERY_SEQUENCE );
+        if ( default_sequence != null ) {
+            getCurrentTreePanel().getControlPanel().getSequenceRelationBox().setSelectedItem( default_sequence );
+            /* GUILHEM_END */
+        }
+        setVisible( true );
+    }
+
+    void initializeTypeMenu( final Options options ) {
+        setTypeMenuToAllUnselected();
+        try {
+            switch ( options.getPhylogenyGraphicsType() ) {
+                case CONVEX:
+                    _convex_type_cbmi.setSelected( true );
+                    break;
+                case CURVED:
+                    _curved_type_cbmi.setSelected( true );
+                    break;
+                case EURO_STYLE:
+                    _euro_type_cbmi.setSelected( true );
+                    break;
+                case ROUNDED:
+                    _rounded_type_cbmi.setSelected( true );
+                    break;
+                case TRIANGULAR:
+                    _triangular_type_cbmi.setSelected( true );
+                    break;
+                case UNROOTED:
+                    _unrooted_type_cbmi.setSelected( true );
+                    break;
+                case CIRCULAR:
+                    _circular_type_cbmi.setSelected( true );
+                    break;
+                default:
+                    _rectangular_type_cbmi.setSelected( true );
+                    break;
+            }
+        }
+        catch ( final NullPointerException np ) {
+            // In all likelihood, this is caused by menu-less display.
+        }
+    }
+
+    private boolean isScreenAntialias() {
+        return true;
+    }
+
+    private void removeBranchColors() {
+        if ( getMainPanel().getCurrentPhylogeny() != null ) {
+            Util.removeBranchColors( getMainPanel().getCurrentPhylogeny() );
+        }
+    }
+
+    void removeTextFrame() {
+        if ( _textframe != null ) {
+            _textframe.close();
+            _textframe = null;
+        }
+    }
+
+    void setConfiguration( final Configuration configuration ) {
+        _configuration = configuration;
+    }
+
+    private void setMainPanel( final MainPanelApplets main_panel ) {
+        _main_panel = main_panel;
+    }
+
+    void setOptions( final Options options ) {
+        _options = options;
+    }
+
+    void setSelectedTypeInTypeMenu( final PHYLOGENY_GRAPHICS_TYPE type ) {
+        setTypeMenuToAllUnselected();
+        try {
+            switch ( type ) {
+                case CIRCULAR:
+                    _circular_type_cbmi.setSelected( true );
+                    break;
+                case CONVEX:
+                    _convex_type_cbmi.setSelected( true );
+                    break;
+                case CURVED:
+                    _curved_type_cbmi.setSelected( true );
+                    break;
+                case EURO_STYLE:
+                    _euro_type_cbmi.setSelected( true );
+                    break;
+                case ROUNDED:
+                    _rounded_type_cbmi.setSelected( true );
+                    break;
+                case RECTANGULAR:
+                    _rectangular_type_cbmi.setSelected( true );
+                    break;
+                case TRIANGULAR:
+                    _triangular_type_cbmi.setSelected( true );
+                    break;
+                case UNROOTED:
+                    _unrooted_type_cbmi.setSelected( true );
+                    break;
+                default:
+                    throw new IllegalArgumentException( "unknown type: " + type );
+            }
+        }
+        catch ( final NullPointerException np ) {
+            // In all likelihood, this is caused by menu-less display.
+        }
+    }
+
+    void setTypeMenuToAllUnselected() {
+        if ( _convex_type_cbmi != null ) {
+            _convex_type_cbmi.setSelected( false );
+        }
+        if ( _curved_type_cbmi != null ) {
+            _curved_type_cbmi.setSelected( false );
+        }
+        if ( _euro_type_cbmi != null ) {
+            _euro_type_cbmi.setSelected( false );
+        }
+        if ( _rounded_type_cbmi != null ) {
+            _rounded_type_cbmi.setSelected( false );
+        }
+        if ( _triangular_type_cbmi != null ) {
+            _triangular_type_cbmi.setSelected( false );
+        }
+        if ( _rectangular_type_cbmi != null ) {
+            _rectangular_type_cbmi.setSelected( false );
+        }
+        if ( _unrooted_type_cbmi != null ) {
+            _unrooted_type_cbmi.setSelected( false );
+        }
+        if ( _circular_type_cbmi != null ) {
+            _circular_type_cbmi.setSelected( false );
+        }
+    }
+
+    private void setupUI() {
+        try {
+            if ( getConfiguration().isUseNativeUI() ) {
+                UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
+            }
+            else {
+                UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
+            }
+        }
+        catch ( final UnsupportedLookAndFeelException e ) {
+            Util.dieWithSystemError( "UnsupportedLookAndFeelException: " + e.toString() );
+        }
+        catch ( final ClassNotFoundException e ) {
+            Util.dieWithSystemError( "ClassNotFoundException: " + e.toString() );
+        }
+        catch ( final InstantiationException e ) {
+            Util.dieWithSystemError( "InstantiationException: " + e.toString() );
+        }
+        catch ( final IllegalAccessException e ) {
+            Util.dieWithSystemError( "IllegalAccessException: " + e.toString() );
+        }
+        catch ( final Exception e ) {
+            Util.dieWithSystemError( e.toString() );
+        }
+    }
+
+    @Override
+    public void start() {
+        if ( getMainPanel() != null ) {
+            getMainPanel().validate();
+        }
+        requestFocus();
+        requestFocusInWindow();
+        requestFocus();
+        Util.printAppletMessage( NAME, "started" );
+    }
+
+    void switchColors() {
+        final TreeColorSet colorset = getMainPanel().getCurrentTreePanel().getTreeColorSet();
+        final ColorSchemeChooser csc = new ColorSchemeChooser( getMainPanel(), colorset );
+        csc.setVisible( true );
+        getMainPanel().setTreeColorSet( colorset );
+    }
+
+    void typeChanged( final Object o ) {
+        updateTypeCheckboxes( getOptions(), o );
+        updateOptions( getOptions() );
+        if ( getCurrentTreePanel() != null ) {
+            final PHYLOGENY_GRAPHICS_TYPE previous_type = getCurrentTreePanel().getPhylogenyGraphicsType();
+            final PHYLOGENY_GRAPHICS_TYPE new_type = getOptions().getPhylogenyGraphicsType();
+            if ( ( ( previous_type == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && ( new_type != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) )
+                    || ( ( previous_type == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) && ( new_type != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) )
+                    || ( ( previous_type != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && ( new_type == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) )
+                    || ( ( previous_type != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) && ( new_type == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) ) {
+                getCurrentTreePanel().getControlPanel().showWhole();
+            }
+            if ( getCurrentTreePanel().isPhyHasBranchLengths() && ( new_type != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
+                getCurrentTreePanel().getControlPanel().setDrawPhylogramEnabled( true );
+            }
+            else {
+                getCurrentTreePanel().getControlPanel().setDrawPhylogramEnabled( false );
+            }
+            getCurrentTreePanel().setPhylogenyGraphicsType( getOptions().getPhylogenyGraphicsType() );
+            MainFrame.updateScreenTextAntialias( getMainPanel().getTreePanels() );
+        }
+    }
+
+    void updateOptions( final Options options ) {
+        options.setAntialiasScreen( ( _screen_antialias_cbmi != null ) && _screen_antialias_cbmi.isSelected() );
+        options.setBackgroundColorGradient( ( _background_gradient_cbmi != null )
+                && _background_gradient_cbmi.isSelected() );
+        options.setShowDomainLabels( ( _show_domain_labels != null ) && _show_domain_labels.isSelected() );
+        options.setAbbreviateScientificTaxonNames( ( _abbreviate_scientific_names != null )
+                && _abbreviate_scientific_names.isSelected() );
+        options.setColorLabelsSameAsParentBranch( ( _color_labels_same_as_parent_branch != null )
+                && _color_labels_same_as_parent_branch.isSelected() );
+        options.setShowNodeBoxes( ( _show_node_boxes_cbmi != null ) && _show_node_boxes_cbmi.isSelected() );
+        if ( ( _non_lined_up_cladograms_rbmi != null ) && ( _non_lined_up_cladograms_rbmi.isSelected() ) ) {
+            options.setCladogramType( CLADOGRAM_TYPE.NON_LINED_UP );
+        }
+        else if ( ( _uniform_cladograms_rbmi != null ) && ( _uniform_cladograms_rbmi.isSelected() ) ) {
+            options.setCladogramType( CLADOGRAM_TYPE.TOTAL_NODE_SUM_DEP );
+        }
+        else if ( ( _ext_node_dependent_cladogram_rbmi != null ) && ( _ext_node_dependent_cladogram_rbmi.isSelected() ) ) {
+            options.setCladogramType( CLADOGRAM_TYPE.EXT_NODE_SUM_DEP );
+        }
+        options.setSearchCaseSensitive( ( _search_case_senstive_cbmi != null )
+                && _search_case_senstive_cbmi.isSelected() );
+        if ( ( _show_scale_cbmi != null ) && _show_scale_cbmi.isEnabled() ) {
+            options.setShowScale( _show_scale_cbmi.isSelected() );
+        }
+        if ( _label_direction_cbmi != null ) {
+            if ( _label_direction_cbmi.isSelected() ) {
+                options.setNodeLabelDirection( NODE_LABEL_DIRECTION.RADIAL );
+            }
+            else {
+                options.setNodeLabelDirection( NODE_LABEL_DIRECTION.HORIZONTAL );
+            }
+        }
+        options.setShowOverview( ( _show_overview_cbmi != null ) && _show_overview_cbmi.isSelected() );
+        if ( ( _show_branch_length_values_cbmi != null ) && _show_branch_length_values_cbmi.isEnabled() ) {
+            options.setShowBranchLengthValues( _show_branch_length_values_cbmi.isSelected() );
+        }
+        options.setMatchWholeTermsOnly( ( _search_whole_words_only_cbmi != null )
+                && _search_whole_words_only_cbmi.isSelected() );
+        options.setInverseSearchResult( ( _inverse_search_result_cbmi != null )
+                && _inverse_search_result_cbmi.isSelected() );
+        if ( ( _rectangular_type_cbmi != null ) && _rectangular_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
+        }
+        else if ( ( _triangular_type_cbmi != null ) && _triangular_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR );
+        }
+        else if ( ( _curved_type_cbmi != null ) && _curved_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CURVED );
+        }
+        else if ( ( _convex_type_cbmi != null ) && _convex_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CONVEX );
+        }
+        else if ( ( _euro_type_cbmi != null ) && _euro_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE );
+        }
+        else if ( ( _rounded_type_cbmi != null ) && _rounded_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.ROUNDED );
+        }
+        else if ( ( _unrooted_type_cbmi != null ) && _unrooted_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
+        }
+        else if ( ( _circular_type_cbmi != null ) && _circular_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CIRCULAR );
+        }
+    }
+
+    void updateTypeCheckboxes( final Options options, final Object o ) {
+        setTypeMenuToAllUnselected();
+        ( ( JCheckBoxMenuItem ) o ).setSelected( true );
+    }
+
+    void viewAsNexus() {
+        removeTextFrame();
+        if ( ( getMainPanel().getCurrentPhylogeny() == null ) || getMainPanel().getCurrentPhylogeny().isEmpty()
+                || ( getMainPanel().getCurrentPhylogeny().getNumberOfExternalNodes() > 10000 ) ) {
+            return;
+        }
+        _textframe = TextFrame.instantiate( getMainPanel().getCurrentPhylogeny().toNexus() );
+    }
+
+    void viewAsNH() {
+        removeTextFrame();
+        if ( ( getMainPanel().getCurrentPhylogeny() == null ) || getMainPanel().getCurrentPhylogeny().isEmpty()
+                || ( getMainPanel().getCurrentPhylogeny().getNumberOfExternalNodes() > 10000 ) ) {
+            return;
+        }
+        _textframe = TextFrame.instantiate( getMainPanel().getCurrentPhylogeny().toNewHampshire( false ) );
+    }
+
+    void viewAsNHX() {
+        removeTextFrame();
+        if ( ( getMainPanel().getCurrentPhylogeny() == null ) || getMainPanel().getCurrentPhylogeny().isEmpty()
+                || ( getMainPanel().getCurrentPhylogeny().getNumberOfExternalNodes() > 10000 ) ) {
+            return;
+        }
+        _textframe = TextFrame.instantiate( getMainPanel().getCurrentPhylogeny().toNewHampshireX() );
+    }
+
+    void viewAsXML() {
+        removeTextFrame();
+        if ( ( getMainPanel().getCurrentPhylogeny() == null ) || getMainPanel().getCurrentPhylogeny().isEmpty()
+                || ( getMainPanel().getCurrentPhylogeny().getNumberOfExternalNodes() > 10000 ) ) {
+            return;
+        }
+        _textframe = TextFrame.instantiate( getMainPanel().getCurrentPhylogeny().toPhyloXML( 0 ) );
+    }
+
+    static void setupScreenTextAntialias( final List<TreePanel> treepanels, final boolean antialias ) {
+        for( final TreePanel tree_panel : treepanels ) {
+            tree_panel.setTextAntialias();
+        }
+    }
+}
\ No newline at end of file
diff --git a/forester/java/src/org/forester/archaeopteryx/Blast.java b/forester/java/src/org/forester/archaeopteryx/Blast.java
new file mode 100644 (file)
index 0000000..68911e8
--- /dev/null
@@ -0,0 +1,144 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.forester.ws.wabi.RestUtil;
+
+public class Blast {
+
+    public Blast() {
+    }
+
+    void go( final String geneName ) {
+        // Retrieve accession number list which has specified gene name from searchByXMLPath of ARSA. Please click here for details of ARSA.
+        /*target: Sequence length is between 300bp and 1000bp.
+        Feature key is CDS.
+        Gene qualifire is same as specified gene name.*/
+        String queryPath = "/ENTRY/DDBJ/division=='HUM' AND (/ENTRY/DDBJ/length>=300 AND "
+                + "/ENTRY/DDBJ/length<=1000) ";
+        queryPath += "AND (/ENTRY/DDBJ/feature-table/feature{/f_key = 'CDS' AND ";
+        queryPath += "/f_quals/qualifier{/q_name = 'gene' AND /q_value=='" + geneName + "'}})";
+        String query = "service=ARSA&method=searchByXMLPath&queryPath=" + queryPath
+                + "&returnPath=/ENTRY/DDBJ/primary-accession&offset=1&count=100";
+        //Execute ARSA
+        String arsaResult = null;
+        try {
+            arsaResult = RestUtil.getResult( query );
+        }
+        catch ( final IOException e ) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        final String[] arsaResultLines = arsaResult.split( "\n" );
+        //Get hit count
+        final int arsaResultNum = Integer.parseInt( arsaResultLines[ 0 ].replaceAll( "hitscount       =", "" ).trim() );
+        //If there is no hit, print a message and exit
+        if ( arsaResultNum == 0 ) {
+            System.out.println( "There is no entry for gene:" + geneName );
+            return;
+        }
+        //Retrieve DNA sequence of top hit entry by using getFASTA_DDBJEntry of GetEntry.
+        //Retrieve DNA sequence of first fit.
+        final String repAccession = arsaResultLines[ 2 ];
+        query = "service=GetEntry&method=getFASTA_DDBJEntry&accession=" + repAccession;
+        String dnaSeq = null;
+        try {
+            dnaSeq = RestUtil.getResult( query );
+        }
+        catch ( final IOException e ) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        System.out.println( "Retrieved DNA sequence is: " + dnaSeq );
+        //Execute blastn by using searchParam of Blast with step2's sequence. Specified option is -e 0.0001 -m 8 -b 50 -v 50. It means "Extract top 50 hit which E-value is more than 0.0001.". The reference databases are specified as follows. ddbjpri(primates) ddbjrod(rodents) ddbjmam(mammals) ddbjvrt(vertebrates ) ddbjinv(invertebrates).
+        //Execute blastn with step3's sequence
+        query = "service=Blast&method=searchParam&program=blastn&database=ddbjpri ddbjrod ddbjmam ddbjvrt "
+                + "ddbjinv&query=" + dnaSeq + "&param=-m 8 -b 50 -v 50 -e 0.0001";
+        String blastResult = null;
+        try {
+            blastResult = RestUtil.getResult( query );
+        }
+        catch ( final IOException e ) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        // Extract both accession number and similarity score from BLAST result.
+        // This step does not use Web API and extract the part of result or edit the result. Please click here to see the details of each column in the BLAST tab delimited format which is generated by -m 8 option.
+        final String blastResultLines[] = blastResult.split( "\n" );
+        final Vector<String[]> parsedBlastResult = new Vector<String[]>();
+        for( final String blastResultLine : blastResultLines ) {
+            final String cols[] = blastResultLine.split( "\t" );
+            final String accession = cols[ 1 ].substring( 0, cols[ 1 ].indexOf( "|" ) );
+            final String[] result = { accession, cols[ 2 ] };
+            parsedBlastResult.add( result );
+        }
+        // Retrieve species name by using searchByXMLPath of ARSA. If the plural subjects whose species
+        // name are same are in the result, the highest similarity score is used.
+        //Retrieve species from accession number.
+        final Hashtable<String, String> organismAccession = new Hashtable<String, String>();
+        for( int i = 0; i < parsedBlastResult.size(); i++ ) {
+            final String[] parsed = parsedBlastResult.elementAt( i );
+            query = "service=ARSA&method=searchByXMLPath&queryPath=/ENTRY/DDBJ/primary-accession=='" + parsed[ 0 ]
+                    + "'&returnPath=/ENTRY/DDBJ/organism&offset=1&count=100";
+            String organism = null;
+            try {
+                organism = RestUtil.getResult( query );
+            }
+            catch ( final IOException e ) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+            final String[] organismLines = organism.split( "\n" );
+            organism = organismLines[ 2 ];
+            //If same organism name hits, use first hit.
+            if ( !organismAccession.containsKey( organism ) ) {
+                organismAccession.put( organism, parsed[ 0 ] + "\t" + parsed[ 1 ] );
+            }
+        }
+        // Print result.
+        // Print Result
+        System.out.println( "DDBJ entries: " + arsaResultNum );
+        System.out.println( "Representative accession: " + repAccession );
+        System.out.println( "Organism name\tDDBJ accession number\tSequence similarity" );
+        final String[] keys = new String[ organismAccession.size() ];
+        final Enumeration<String> enu = organismAccession.keys();
+        int count = 0;
+        while ( enu.hasMoreElements() ) {
+            keys[ count ] = enu.nextElement();
+            ++count;
+        }
+        Arrays.sort( keys );
+        for( final String key : keys ) {
+            System.out.println( key + "\t" + organismAccession.get( key ) );
+        }
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/ColorSchemeChooser.java b/forester/java/src/org/forester/archaeopteryx/ColorSchemeChooser.java
new file mode 100644 (file)
index 0000000..cc76278
--- /dev/null
@@ -0,0 +1,194 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// Copyright (C) 2000-2001 Washington University School of Medicine
+// and Howard Hughes Medical Institute
+// Copyright (C) 2003-2007 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Vector;
+
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+
+final class ColorSchemeChooser extends JDialog implements ActionListener {
+
+    private static final long  serialVersionUID = 6150960100859081126L;
+    private final TreeColorSet _colorset;
+    private final JComboBox    _selector;
+    private final JPanel       _color_panel;
+    private final JPanel       _color_labels[];
+    private final JButton      _ok_btn;
+    private final JButton      _cancel_btn;
+    private final MainPanel    _main_panel;
+    private final int          _prev_selected_scheme;
+    private int                _selected_scheme;
+
+    ColorSchemeChooser( final MainPanel parent, final TreeColorSet colorset ) {
+        setName( "Color Scheme Chooser" );
+        setModal( true );
+        _colorset = colorset;
+        _prev_selected_scheme = _colorset.getCurrentColorScheme();
+        _main_panel = parent;
+        setSize( 400, 350 );
+        final Container contentpane = getContentPane();
+        contentpane.setLayout( new BorderLayout( 5, 15 ) );
+        // The scheme selection panel
+        final JPanel select_panel = new JPanel();
+        final JLabel l = new JLabel( "Choose a color scheme:" );
+        select_panel.add( l );
+        final Vector<String> list = new Vector<String>();
+        for( final String element : TreeColorSet.SCHEME_NAMES ) {
+            list.add( element );
+        }
+        _selector = new JComboBox( list );
+        _selector.setMaximumRowCount( list.size() );
+        _selector.getModel().addListDataListener( new ListDataListener() {
+
+            public void contentsChanged( final ListDataEvent e ) {
+                final int selection = _selector.getSelectedIndex();
+                changeDialogColors( selection );
+            }
+
+            public void intervalAdded( final ListDataEvent e ) {
+                // Not needed.
+            }
+
+            public void intervalRemoved( final ListDataEvent e ) {
+                // Not needed.
+            }
+        } );
+        select_panel.add( _selector );
+        contentpane.add( select_panel, "North" );
+        // create color panel
+        final int num_colors = TreeColorSet.COLOR_FIELDS.length;
+        _color_panel = new JPanel( new GridLayout( num_colors, 2, 8, 0 ) );
+        final JLabel headings[] = new JLabel[ num_colors ];
+        _color_labels = new JPanel[ num_colors ];
+        for( int i = 0; i < num_colors; i++ ) {
+            headings[ i ] = new JLabel( TreeColorSet.COLOR_FIELDS[ i ] );
+            headings[ i ].setFont( new Font( Configuration.getDefaultFontFamilyName(), Font.PLAIN, 9 ) );
+            headings[ i ].setHorizontalAlignment( SwingConstants.RIGHT );
+            _color_panel.add( headings[ i ] );
+            _color_labels[ i ] = new JPanel();
+            _color_labels[ i ].setPreferredSize( new Dimension( 15, 40 ) );
+            _color_panel.add( _color_labels[ i ] );
+        }
+        contentpane.add( _color_panel, "Center" );
+        setColors( _colorset.getColorSchemes()[ 0 ] );
+        // create button panel
+        final JPanel btn_panel = new JPanel();
+        _ok_btn = new JButton( "OK" );
+        _ok_btn.addActionListener( new ActionListener() {
+
+            public void actionPerformed( final ActionEvent e ) {
+                ok();
+            }
+        } );
+        btn_panel.add( _ok_btn );
+        _cancel_btn = new JButton( "Cancel" );
+        _cancel_btn.addActionListener( new ActionListener() {
+
+            public void actionPerformed( final ActionEvent e ) {
+                cancel();
+            }
+        } );
+        btn_panel.add( _cancel_btn );
+        btn_panel.setPreferredSize( new Dimension( 400, 30 ) );
+        getContentPane().add( btn_panel, "South" );
+        setCurrentColor( colorset.getCurrentColorScheme() );
+    }
+
+    public void actionPerformed( final ActionEvent e ) {
+        // Not needed.
+    }
+
+    private void cancel() {
+        _colorset.setColorSchema( _prev_selected_scheme );
+        for( final TreePanel tree_panel : getMainPanel().getTreePanels() ) {
+            tree_panel.setBackground( _colorset.getBackgroundColor() );
+        }
+        redrawTreePanel();
+        setVisible( false );
+        dispose();
+    }
+
+    private void changeDialogColors( final int scheme_index ) {
+        _selected_scheme = scheme_index;
+        setColors( _colorset.getColorSchemes()[ scheme_index ] );
+        _colorset.setColorSchema( getSelectedScheme() );
+        for( final TreePanel tree_panel : getMainPanel().getTreePanels() ) {
+            tree_panel.setBackground( _colorset.getBackgroundColor() );
+        }
+        redrawTreePanel();
+    }
+
+    private MainPanel getMainPanel() {
+        return _main_panel;
+    }
+
+    private int getSelectedScheme() {
+        return _selected_scheme;
+    }
+
+    private void ok() {
+        // set the new color
+        _colorset.setColorSchema( getSelectedScheme() );
+        // close the window
+        setVisible( false );
+        dispose();
+    }
+
+    private void redrawTreePanel() {
+        if ( getMainPanel().getCurrentTreePanel() != null ) {
+            getMainPanel().getCurrentTreePanel().repaint();
+        }
+    }
+
+    private void setColors( final Color colors[] ) {
+        for( int i = 0; i < colors.length; i++ ) {
+            _color_labels[ i ].setBackground( colors[ i ] );
+        }
+    }
+
+    private void setCurrentColor( final int color_index ) {
+        setColors( _colorset.getColorSchemes()[ color_index ] );
+        _selector.setSelectedIndex( color_index );
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/Configuration.java b/forester/java/src/org/forester/archaeopteryx/Configuration.java
new file mode 100644 (file)
index 0000000..2333e77
--- /dev/null
@@ -0,0 +1,1345 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// Copyright (C) 2000-2001 Washington University School of Medicine
+// and Howard Hughes Medical Institute
+// Copyright (C) 2003-2007 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.Color;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+import org.forester.archaeopteryx.Options.CLADOGRAM_TYPE;
+import org.forester.archaeopteryx.Options.NODE_LABEL_DIRECTION;
+import org.forester.archaeopteryx.Options.OVERVIEW_PLACEMENT_TYPE;
+import org.forester.archaeopteryx.Options.PHYLOGENY_GRAPHICS_TYPE;
+import org.forester.util.ForesterUtil;
+
+public final class Configuration {
+
+    static final String                     VALIDATE_AGAINST_PHYLOXML_XSD_SCHEMA                   = "validate_against_phyloxml_xsd_schema";
+    private static final String             WEB_LINK_KEY                                           = "web_link";
+    private static final String             DISPLAY_COLOR_KEY                                      = "display_color";
+    private static final int                DEPRECATED                                             = -2;
+    private TRIPLET                         _native_ui                                             = TRIPLET.FALSE;
+    private boolean                         _use_tabbed_display                                    = false;
+    private boolean                         _hide_controls_and_menus                               = false;
+    private CLADOGRAM_TYPE                  _cladogram_type                                        = Constants.CLADOGRAM_TYPE_DEFAULT;
+    private SortedMap<String, WebLink>      _weblinks                                              = null;
+    private SortedMap<String, Color>        _display_colors                                        = null;
+    private boolean                         _antialias_screen                                      = true;
+    private PHYLOGENY_GRAPHICS_TYPE         _phylogeny_graphics_type                               = PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR;
+    private String                          _base_font_family_name                                 = "";
+    private int                             _base_font_size                                        = -1;
+    private int                             _graphics_export_x                                     = -1;
+    private int                             _graphics_export_y                                     = -1;
+    private short                           _ov_max_width                                          = 80;
+    private short                           _ov_max_height                                         = 80;
+    private OVERVIEW_PLACEMENT_TYPE         _ov_placement                                          = OVERVIEW_PLACEMENT_TYPE.UPPER_LEFT;
+    private double                          _min_confidence_value                                  = Options.MIN_CONFIDENCE_DEFAULT;
+    private float                           _print_line_width                                      = Constants.PDF_LINE_WIDTH_DEFAULT;
+    private boolean                         _show_scale                                            = false;
+    private boolean                         _show_branch_length_values                             = false;
+    private boolean                         _show_overview                                         = true;
+    private short                           _number_of_digits_after_comma_for_confidence_values    = Constants.NUMBER_OF_DIGITS_AFTER_COMMA_FOR_CONFIDENCE_VALUES_DEFAULT;
+    private short                           _number_of_digits_after_comma_for_branch_length_values = Constants.NUMBER_OF_DIGITS_AFTER_COMMA_FOR_BRANCH_LENGTH_VALUES_DEFAULT;
+    private boolean                         _editable                                              = true;
+    private boolean                         _nh_parsing_replace_underscores                        = false;
+    private boolean                         _nh_parsing_extract_pfam_taxonomy_codes                = false;
+    private boolean                         _internal_number_are_confidence_for_nh_parsing         = false;
+    private boolean                         _display_sequence_relations                            = false;
+    private boolean                         _validate_against_phyloxml_xsd_schema                  = Constants.VALIDATE_AGAINST_PHYLOXML_XSD_SCJEMA_DEFAULT;
+    private boolean                         _background_color_gradient                             = false;
+    private boolean                         _show_domain_labels                                    = true;
+    private boolean                         _abbreviate_scientific_names                           = false;
+    private boolean                         _color_labels_same_as_parent_branch                    = false;
+    private int                             _default_bootstrap_samples                             = -1;
+    final static int                        display_as_phylogram                                   = 0;
+    final static int                        show_node_names                                        = 1;
+    final static int                        show_tax_code                                          = 2;
+    final static int                        show_annotation                                        = 3;
+    final static int                        write_confidence_values                                = 4;
+    final static int                        write_events                                           = 5;
+    final static int                        color_according_to_species                             = 6;
+    final static int                        color_branches                                         = 7;
+    final static int                        width_branches                                         = 8;
+    final static int                        show_domain_architectures                              = 9;
+    final static int                        show_binary_characters                                 = 10;
+    final static int                        show_binary_character_counts                           = 11;
+    final static int                        show_gene_names                                        = 12;
+    final static int                        show_sequence_acc                                      = 13;
+    final static int                        display_internal_data                                  = 14;
+    final static int                        dynamically_hide_data                                  = 15;
+    final static int                        show_taxonomy_scientific_names                         = 16;
+    final static int                        show_taxonomy_common_names                             = 17;
+    final static int                        color_according_to_annotation                          = 18;
+    final static int                        show_property                                          = 19;
+    final static int                        show_gene_symbols                                      = 20;
+    final static int                        node_data_popup                                        = 21;
+    final static int                        show_relation_confidence                               = 22;
+    final static int                        show_vector_data                                       = 23;
+    final static int                        show_taxonomy_images                                   = 24;
+    // ------------------
+    // Click-to options
+    // ------------------
+    final static int                        display_node_data                                      = 0;
+    final static int                        collapse_uncollapse                                    = 1;
+    final static int                        reroot                                                 = 2;
+    final static int                        subtree                                                = 3;
+    final static int                        swap                                                   = 4;
+    final static int                        color_subtree                                          = 5;
+    final static int                        open_seq_web                                           = 6;
+    final static int                        open_tax_web                                           = 7;
+    final static int                        cut_subtree                                            = 8;
+    final static int                        copy_subtree                                           = 9;
+    final static int                        paste_subtree                                          = 10;
+    final static int                        delete_subtree_or_node                                 = 11;
+    final static int                        add_new_node                                           = 12;
+    final static int                        edit_node_data                                         = 13;
+    final static int                        blast                                                  = 14;
+    // ---------------------------
+    // Display options for trees
+    // ---------------------------
+    // ---------------------------------
+    // Pertaining to the config itself
+    // ---------------------------------
+    // Full path to config (may be URL)
+    String                                  config_filename;
+    String                                  default_config_filename                                = Constants.DEFAULT_CONFIGURATION_FILE_NAME;
+    final static String                     display_options[][]                                    = {
+            { "Phylogram", "display", "?" }, { "Node Name", "display", "yes" }, { "Taxonomy Code", "display", "yes" },
+            { "Annotation", "nodisplay", "no" }, { "Confidence Value", "display", "?" }, { "Event", "display", "?" },
+            { "Taxonomy Colorize", "display", "yes" }, { "Colorize Branches", "display", "no" },
+            { "Use Branch-Width", "nodisplay", "no" }, { "Domains", "nodisplay", "no" },
+            { "Binary Characters", "nodisplay", "no" }, { "Binary Char Counts", "nodisplay", "no" },
+            { "Prot/Gene Name", "display", "no" }, { "Prot/Gene Acc", "display", "no" },
+            { "Show Internal Data", "display", "yes" }, { "Dyna Hide", "display", "yes" },
+            { "Taxonomy Scientific", "display", "yes" }, { "Taxonomy Common", "display", "no" },
+            { "Annotation Colorize", "nodisplay", "no" }, { "Property", "nodisplay", "no" },
+            { "Prot/Gene Symbol", "display", "no" }, { "Rollover", "display", "yes" },
+            { "Relation Confidence", "display", "no" }, { "Vector Data", "display", "no" },
+            { "Taxonomy Images", "display", "no" }                                                };
+    final static String                     clickto_options[][]                                    = {
+            { "Display Node Data", "display" }, { "Collapse/Uncollapse", "display" }, { "Root/Reroot", "display" },
+            { "Sub/Super Tree", "display" }, { "Swap Descendants", "display" }, { "Colorize Subtree", "display" },
+            { "Open Sequence Web", "nodisplay" }, { "Open Taxonomy Web", "nodisplay" }, { "Cut Subtree", "display" },
+            { "Copy Subtree", "display" }, { "Paste Subtree", "display" }, { "Delete Subtree/Node", "display" },
+            { "Add New Node", "display" }, { "Edit Node Data", "display" }, { "Blast", "display" } };
+    // This option is selected in the dropdown
+    int                                     default_clickto                                        = Configuration.display_node_data;
+    // --------------
+    // Color set
+    // --------------
+    TreeColorSet                            tree_color_set;
+    // -------
+    // Fonts
+    // -------
+    TreeFontSet                             tree_font_set;
+    // ----------------
+    // Species colors
+    // ----------------
+    private static Hashtable<String, Color> _species_colors;
+    // ----------------
+    // Domain colors
+    // ----------------
+    private static Hashtable<String, Color> _domain_colors;
+    // ----------------
+    // Function colors
+    // ----------------
+    private static Hashtable<String, Color> _annotation_colors;
+    boolean                                 verbose                                                = Constants.VERBOSE_DEFAULT;
+    private NODE_LABEL_DIRECTION            _node_label_direction                                  = NODE_LABEL_DIRECTION.HORIZONTAL;
+    private TRIPLET                         _use_native_ui;
+    private Color                           _gui_background_color                                  = Constants.GUI_BACKGROUND_DEFAULT;
+    private Color                           _gui_checkbox_text_color                               = Constants.CHECKBOX_TEXT_COLOR_DEFAULT;
+    private Color                           _gui_checkbox_and_button_active_color                  = Constants.CHECKBOX_AND_BUTTON_ACTIVE_COLOR_DEFAULT;
+    private Color                           _gui_button_text_color                                 = Constants.BUTTON_TEXT_COLOR_DEFAULT;
+    private Color                           _gui_button_background_color                           = Constants.BUTTON_BACKGROUND_COLOR_DEFAULT;
+    private Color                           _gui_menu_background_color                             = Constants.MENU_BACKGROUND_COLOR_DEFAULT;
+    private Color                           _gui_menu_text_color                                   = Constants.MENU_TEXT_COLOR_DEFAULT;
+    private Color                           _gui_button_border_color                               = Constants.BUTTON_BORDER_COLOR_DEFAULT;
+    private Color                           _domain_structure_font_color                           = Constants.DOMAIN_STRUCTURE_FONT_COLOR_DEFAULT;
+    private Color                           _domain_structure_base_color                           = Constants.DOMAIN_STRUCTURE_BASE_COLOR_DEFAULT;
+    private static String                   DEFAULT_FONT_FAMILY                                    = "";
+    static {
+        for( final String font_name : Constants.DEFAULT_FONT_CHOICES ) {
+            if ( Arrays.binarySearch( Util.getAvailableFontFamiliesSorted(), font_name ) >= 0 ) {
+                DEFAULT_FONT_FAMILY = font_name;
+                break;
+            }
+        }
+        if ( ForesterUtil.isEmpty( DEFAULT_FONT_FAMILY ) ) {
+            DEFAULT_FONT_FAMILY = Constants.DEFAULT_FONT_CHOICES[ Constants.DEFAULT_FONT_CHOICES.length - 1 ];
+        }
+    }
+
+    Configuration( final String cf, final boolean is_url, final boolean is_applet ) {
+        if ( ForesterUtil.isEmpty( cf ) ) {
+            config_filename = default_config_filename;
+        }
+        else {
+            config_filename = cf;
+        }
+        setWebLinks( new TreeMap<String, WebLink>() );
+        setDisplayColors( new TreeMap<String, Color>() );
+        config_filename = config_filename.trim();
+        URL u = null;
+        if ( is_url ) {
+            // If URL, open accordingly
+            try {
+                u = new URL( config_filename );
+                try {
+                    final InputStreamReader isr = new InputStreamReader( u.openStream() );
+                    final BufferedReader bf = new BufferedReader( isr );
+                    readConfig( bf );
+                    bf.close();
+                    ForesterUtil.programMessage( Constants.PRG_NAME, "successfully read from configuration url ["
+                            + config_filename + "]" );
+                }
+                catch ( final Exception e ) {
+                    ForesterUtil.printWarningMessage( Constants.PRG_NAME, "failed to read configuration from ["
+                            + config_filename + "]: " + e.getLocalizedMessage() );
+                }
+            }
+            catch ( final Exception e ) {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME, "cannot find or open configuration url ["
+                        + config_filename + "]" );
+            }
+        }
+        else {
+            // Otherwise, open as a file
+            File f = new File( config_filename );
+            if ( !f.exists() ) {
+                f = new File( config_filename + ".txt" );
+            }
+            if ( f.exists() && f.canRead() ) {
+                try {
+                    final BufferedReader bf = new BufferedReader( new FileReader( f ) );
+                    readConfig( bf );
+                    bf.close();
+                }
+                catch ( final Exception e ) {
+                    ForesterUtil.printWarningMessage( Constants.PRG_NAME, "failed to read configuration from ["
+                            + config_filename + "]: " + e );
+                }
+            }
+            else {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME, "cannot find or open configuration file ["
+                        + config_filename + "]" );
+            }
+        }
+    }
+
+    private void createWebLink( final String url_str, final String desc, final String source_identifier ) {
+        WebLink weblink = null;
+        boolean ex = false;
+        try {
+            weblink = new WebLink( new URL( url_str.trim() ), desc.trim(), source_identifier.trim() );
+        }
+        catch ( final MalformedURLException e ) {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME, "could not create URL from [" + url_str + "]" );
+            ex = true;
+        }
+        if ( !ex && ( weblink != null ) ) {
+            getWebLinks().put( weblink.getSourceIdentifier().toLowerCase(), weblink );
+        }
+    }
+
+    Color getGuiBackgroundColor() {
+        return _gui_background_color;
+    }
+
+    Color getGuiCheckboxTextColor() {
+        return _gui_checkbox_text_color;
+    }
+
+    Color getGuiCheckboxAndButtonActiveColor() {
+        return _gui_checkbox_and_button_active_color;
+    }
+
+    Color getGuiButtonTextColor() {
+        return _gui_button_text_color;
+    }
+
+    Color getGuiButtonBackgroundColor() {
+        return _gui_button_background_color;
+    }
+
+    Color getGuiMenuBackgroundColor() {
+        return _gui_menu_background_color;
+    }
+
+    Color getGuiMenuTextColor() {
+        return _gui_menu_text_color;
+    }
+
+    Color getGuiButtonBorderColor() {
+        return _gui_button_border_color;
+    }
+
+    boolean displaySequenceRelations() {
+        return _display_sequence_relations;
+    }
+
+    boolean doCheckOption( final int which ) {
+        return ( display_options[ which ][ 2 ].equalsIgnoreCase( "yes" ) )
+                || ( display_options[ which ][ 2 ].equalsIgnoreCase( "true" ) );
+    }
+
+    boolean doDisplayClickToOption( final int which ) {
+        return clickto_options[ which ][ 1 ].equalsIgnoreCase( "display" );
+    }
+
+    boolean doDisplayOption( final int which ) {
+        return display_options[ which ][ 1 ].equalsIgnoreCase( "display" );
+    }
+
+    /**
+     * Will attempt to use the phylogeny to determine whether to check
+     * this or not (e.g. phylogram)
+     * 
+     */
+    boolean doGuessCheckOption( final int which ) {
+        return display_options[ which ][ 2 ].equals( "?" );
+    }
+
+    Map<String, Color> getAnnotationColors() {
+        if ( _annotation_colors == null ) {
+            _annotation_colors = new Hashtable<String, Color>();
+        }
+        return _annotation_colors;
+    }
+
+    public String getBaseFontFamilyName() {
+        return _base_font_family_name;
+    }
+
+    int getBaseFontSize() {
+        return _base_font_size;
+    }
+
+    CLADOGRAM_TYPE getCladogramType() {
+        return _cladogram_type;
+    }
+
+    private int getClickToIndex( final String name ) {
+        int index = -1;
+        if ( name.equals( "edit_info" ) ) {
+            index = Configuration.display_node_data;
+            ForesterUtil
+                    .printWarningMessage( Constants.PRG_NAME,
+                                          "configuration key [edit_info] is deprecated, use [display node data] instead" );
+        }
+        else if ( name.equals( "display_node_data" ) ) {
+            index = Configuration.display_node_data;
+        }
+        else if ( name.equals( "collapse_uncollapse" ) ) {
+            index = Configuration.collapse_uncollapse;
+        }
+        else if ( name.equals( "reroot" ) ) {
+            index = Configuration.reroot;
+        }
+        else if ( name.equals( "subtree" ) ) {
+            index = Configuration.subtree;
+        }
+        else if ( name.equals( "swap" ) ) {
+            index = Configuration.swap;
+        }
+        else if ( name.equals( "display_sequences" ) ) {
+            ForesterUtil
+                    .printWarningMessage( Constants.PRG_NAME, "configuration key [display_sequences] is deprecated" );
+            return DEPRECATED;
+        }
+        else if ( name.equals( "open_seq_web" ) ) {
+            index = Configuration.open_seq_web;
+        }
+        else if ( name.equals( "open_tax_web" ) ) {
+            index = Configuration.open_tax_web;
+        }
+        else if ( name.equals( "cut_subtree" ) ) {
+            index = Configuration.cut_subtree;
+        }
+        else if ( name.equals( "copy_subtree" ) ) {
+            index = Configuration.copy_subtree;
+        }
+        else if ( name.equals( "paste_subtree" ) ) {
+            index = Configuration.paste_subtree;
+        }
+        else if ( name.equals( "delete" ) ) {
+            index = Configuration.delete_subtree_or_node;
+        }
+        else if ( name.equals( "add_new_node" ) ) {
+            index = Configuration.add_new_node;
+        }
+        else if ( name.equals( "edit_node_data" ) ) {
+            index = Configuration.edit_node_data;
+        }
+        else if ( name.equals( "display_node_popup" ) ) {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME,
+                                              "configuration key [display_node_popup] is deprecated" );
+            return DEPRECATED;
+        }
+        else if ( name.equals( "custom_option" ) ) {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME, "configuration key [custom_option] is deprecated" );
+            return DEPRECATED;
+        }
+        else if ( name.equals( "color_subtree" ) ) {
+            index = Configuration.color_subtree;
+        }
+        else if ( name.equals( "go_to_swiss_prot" ) ) {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME, "configuration key [go_to_swiss_prot] is deprecated" );
+            return DEPRECATED;
+        }
+        return index;
+    }
+
+    int getClickToOptionsCount() {
+        return clickto_options.length;
+    }
+
+    String getClickToTitle( final int which ) {
+        return clickto_options[ which ][ 0 ];
+    }
+
+    int getDefaultDisplayClicktoOption() {
+        return default_clickto;
+    }
+
+    SortedMap<String, Color> getDisplayColors() {
+        return _display_colors;
+    }
+
+    String getDisplayTitle( final int which ) {
+        return display_options[ which ][ 0 ];
+    }
+
+    Map<String, Color> getDomainColors() {
+        if ( _domain_colors == null ) {
+            _domain_colors = new Hashtable<String, Color>();
+        }
+        return _domain_colors;
+    }
+
+    int getGraphicsExportX() {
+        return _graphics_export_x;
+    }
+
+    int getGraphicsExportY() {
+        return _graphics_export_y;
+    }
+
+    int getDefaultBootstrapSamples() {
+        return _default_bootstrap_samples;
+    }
+
+    double getMinConfidenceValue() {
+        return _min_confidence_value;
+    }
+
+    NODE_LABEL_DIRECTION getNodeLabelDirection() {
+        return _node_label_direction;
+    }
+
+    short getNumberOfDigitsAfterCommaForBranchLengthValues() {
+        return _number_of_digits_after_comma_for_branch_length_values;
+    }
+
+    short getNumberOfDigitsAfterCommaForConfidenceValues() {
+        return _number_of_digits_after_comma_for_confidence_values;
+    }
+
+    short getOvMaxHeight() {
+        return _ov_max_height;
+    }
+
+    short getOvMaxWidth() {
+        return _ov_max_width;
+    }
+
+    OVERVIEW_PLACEMENT_TYPE getOvPlacement() {
+        return _ov_placement;
+    }
+
+    PHYLOGENY_GRAPHICS_TYPE getPhylogenyGraphicsType() {
+        return _phylogeny_graphics_type;
+    }
+
+    float getPrintLineWidth() {
+        return _print_line_width;
+    }
+
+    Hashtable<String, Color> getSpeciesColors() {
+        if ( _species_colors == null ) {
+            _species_colors = new Hashtable<String, Color>();
+        }
+        return _species_colors;
+    }
+
+    TreeColorSet getTreeColorSet() {
+        return null;
+    }
+
+    TreeFontSet getTreeFontSet() {
+        return null;
+    }
+
+    WebLink getWebLink( final String source ) {
+        return getWebLinks().get( source );
+    }
+
+    Map<String, WebLink> getWebLinks() {
+        return _weblinks;
+    }
+
+    boolean isAntialiasScreen() {
+        return _antialias_screen;
+    }
+
+    public boolean isBackgroundColorGradient() {
+        return _background_color_gradient;
+    }
+
+    /**
+     * Convenience method.
+     * 
+     * @return true if value in configuration file was 'yes'
+     */
+    boolean isDrawAsPhylogram() {
+        return doCheckOption( display_as_phylogram );
+    }
+
+    boolean isEditable() {
+        return _editable;
+    }
+
+    boolean isExtractPfamTaxonomyCodesInNhParsing() {
+        return _nh_parsing_extract_pfam_taxonomy_codes;
+    }
+
+    boolean isHasWebLink( final String source ) {
+        return getWebLinks().containsKey( source );
+    }
+
+    /**
+     * Only used by ArchaeoptryxE.
+     *
+     */
+    boolean isHideControlPanelAndMenubar() {
+        return _hide_controls_and_menus;
+    }
+
+    boolean isInternalNumberAreConfidenceForNhParsing() {
+        return _internal_number_are_confidence_for_nh_parsing;
+    }
+
+    boolean isReplaceUnderscoresInNhParsing() {
+        return _nh_parsing_replace_underscores;
+    }
+
+    boolean isShowBranchLengthValues() {
+        return _show_branch_length_values;
+    }
+
+    boolean isShowOverview() {
+        return _show_overview;
+    }
+
+    boolean isShowScale() {
+        return _show_scale;
+    }
+
+    final boolean isUseNativeUI() {
+        if ( ( _use_native_ui == null ) || ( _use_native_ui == TRIPLET.UNKNOWN ) ) {
+            if ( ( _native_ui == TRIPLET.UNKNOWN ) && Util.isMac() && Util.isJava15() ) {
+                _use_native_ui = TRIPLET.TRUE;
+            }
+            else if ( _native_ui == TRIPLET.TRUE ) {
+                _use_native_ui = TRIPLET.TRUE;
+            }
+            else {
+                _use_native_ui = TRIPLET.FALSE;
+            }
+        }
+        return _use_native_ui == TRIPLET.TRUE;
+    }
+
+    /**
+     * Only used by ArchaeoptryxE.
+     *
+     */
+    boolean isUseTabbedDisplay() {
+        return _use_tabbed_display;
+    }
+
+    boolean isValidatePhyloXmlAgainstSchema() {
+        return _validate_against_phyloxml_xsd_schema;
+    }
+
+    private boolean parseBoolean( final String str ) {
+        final String my_str = str.trim().toLowerCase();
+        if ( my_str.equals( "yes" ) || my_str.equals( "true" ) ) {
+            return true;
+        }
+        else if ( my_str.equals( "no" ) || my_str.equals( "false" ) ) {
+            return false;
+        }
+        else {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME, "could not parse boolean value from [" + str + "]" );
+            return false;
+        }
+    }
+
+    private double parseDouble( final String str ) {
+        double d = 0.0;
+        try {
+            d = Double.parseDouble( str );
+        }
+        catch ( final Exception e ) {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME, "could not parse double from [" + str + "]" );
+            d = 0.0;
+        }
+        return d;
+    }
+
+    private float parseFloat( final String str ) {
+        float f = 0.0f;
+        try {
+            f = Float.parseFloat( str );
+        }
+        catch ( final Exception e ) {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME, "could not parse float from [" + str + "]" );
+            f = 0.0f;
+        }
+        return f;
+    }
+
+    private int parseInt( final String str ) {
+        int i = -1;
+        try {
+            i = Integer.parseInt( str );
+        }
+        catch ( final Exception e ) {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME, "could not parse integer from [" + str + "]" );
+            i = -1;
+        }
+        return i;
+    }
+
+    private short parseShort( final String str ) {
+        short i = -1;
+        try {
+            i = Short.parseShort( str );
+        }
+        catch ( final Exception e ) {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME, "could not parse short from [" + str + "]" );
+            i = -1;
+        }
+        return i;
+    }
+
+    private void processFontFamily( final StringTokenizer st ) {
+        setBaseFontFamilyName( "" );
+        final String font_str = ( ( String ) st.nextElement() ).trim();
+        final String[] fonts = font_str.split( ",+" );
+        for( String font : fonts ) {
+            font = font.replace( '_', ' ' ).trim();
+            if ( Arrays.binarySearch( Util.getAvailableFontFamiliesSorted(), font ) >= 0 ) {
+                setBaseFontFamilyName( font );
+                break;
+            }
+        }
+    }
+
+    /**
+     * read each line of config file, process non-comment lines
+     * @throws IOException 
+     */
+    private void readConfig( final BufferedReader conf_in ) throws IOException {
+        String line;
+        do {
+            line = conf_in.readLine();
+            if ( line != null ) {
+                line = line.trim();
+                // skip comments and blank lines
+                if ( !line.startsWith( "#" ) && ( !ForesterUtil.isEmpty( line ) ) ) {
+                    // convert runs of spaces to tabs
+                    line = line.replaceAll( "\\s+", "\t" );
+                    final StringTokenizer st = new StringTokenizer( line, "\t" );
+                    setKeyValue( st );
+                }
+            }
+        } while ( line != null );
+    }
+
+    private void setAntialiasScreen( final boolean antialias_screen ) {
+        _antialias_screen = antialias_screen;
+    }
+
+    public void setBackgroundColorGradient( final boolean background_color_gradient ) {
+        _background_color_gradient = background_color_gradient;
+    }
+
+    private void setBaseFontFamilyName( final String base_font_family_name ) {
+        _base_font_family_name = base_font_family_name;
+    }
+
+    private void setBaseFontSize( final int base_font_size ) {
+        _base_font_size = base_font_size;
+    }
+
+    private void setShowDomainLabels( final boolean show_domain_labels ) {
+        _show_domain_labels = show_domain_labels;
+    }
+
+    private void setAbbreviateScientificTaxonNames( final boolean abbreviate_scientific_names ) {
+        _abbreviate_scientific_names = abbreviate_scientific_names;
+    }
+
+    private void setColorLabelsSameAsParentBranch( final boolean color_labels_same_as_parent_branch ) {
+        _color_labels_same_as_parent_branch = color_labels_same_as_parent_branch;
+    }
+
+    private void setCladogramType( final CLADOGRAM_TYPE cladogram_type ) {
+        _cladogram_type = cladogram_type;
+    }
+
+    void setDisplayColors( final SortedMap<String, Color> display_colors ) {
+        _display_colors = display_colors;
+    }
+
+    private void setDisplaySequenceRelations( final boolean display_sequence_relations ) {
+        _display_sequence_relations = display_sequence_relations;
+    }
+
+    private void setEditable( final boolean editable ) {
+        _editable = editable;
+    }
+
+    private void setExtractPfamTaxonomyCodesInNhParsing( final boolean nh_parsing_extract_pfam_taxonomy_codes ) {
+        _nh_parsing_extract_pfam_taxonomy_codes = nh_parsing_extract_pfam_taxonomy_codes;
+    }
+
+    private void setGraphicsExportX( final int graphics_export_x ) {
+        _graphics_export_x = graphics_export_x;
+    }
+
+    private void setGraphicsExportY( final int graphics_export_y ) {
+        _graphics_export_y = graphics_export_y;
+    }
+
+    private void setDefaultBootstrapSamples( final int default_bootstrap_samples ) {
+        _default_bootstrap_samples = default_bootstrap_samples;
+    }
+
+    private void setInternalNumberAreConfidenceForNhParsing( final boolean internal_number_are_confidence_for_nh_parsing ) {
+        _internal_number_are_confidence_for_nh_parsing = internal_number_are_confidence_for_nh_parsing;
+    }
+
+    /**
+     * Set a key-value(s) tuple
+     */
+    private void setKeyValue( final StringTokenizer st ) {
+        String key = ( String ) st.nextElement();
+        key = key.replace( ':', ' ' );
+        key = key.trim();
+        key = key.toLowerCase();
+        // Handle single value settings first:
+        if ( key.equals( "default_click_to" ) ) {
+            final String clickto_name = ( String ) st.nextElement();
+            default_clickto = getClickToIndex( clickto_name );
+            if ( default_clickto == -1 ) {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME, "invalid value [" + clickto_name
+                        + "] for [default_click_to]" );
+                default_clickto = 0;
+            }
+            else if ( default_clickto == DEPRECATED ) {
+                // Deprecated.
+            }
+        }
+        else if ( key.equals( "native_ui" ) ) {
+            final String my_str = ( ( String ) st.nextElement() ).trim().toLowerCase();
+            if ( my_str.equals( "yes" ) || my_str.equals( "true" ) ) {
+                _native_ui = TRIPLET.TRUE;
+            }
+            else if ( my_str.equals( "no" ) || my_str.equals( "false" ) ) {
+                _native_ui = TRIPLET.FALSE;
+            }
+            else if ( my_str.equals( "?" ) ) {
+                _native_ui = TRIPLET.UNKNOWN;
+            }
+            else {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME, "could not parse yes/no/? value from [" + my_str
+                        + "]" );
+                _native_ui = TRIPLET.FALSE;
+            }
+        }
+        else if ( key.equals( VALIDATE_AGAINST_PHYLOXML_XSD_SCHEMA ) ) {
+            setValidatePhyloXmlAgainstSchema( parseBoolean( ( String ) st.nextElement() ) );
+        }
+        else if ( key.equals( "antialias_screen" ) ) {
+            setAntialiasScreen( parseBoolean( ( String ) st.nextElement() ) );
+        }
+        else if ( key.equals( "phylogeny_graphics_type" ) ) {
+            final String type_str = ( ( String ) st.nextElement() ).trim();
+            if ( type_str.equalsIgnoreCase( PHYLOGENY_GRAPHICS_TYPE.CONVEX.toString() ) ) {
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CONVEX );
+            }
+            else if ( type_str.equalsIgnoreCase( PHYLOGENY_GRAPHICS_TYPE.CURVED.toString() ) ) {
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CURVED );
+            }
+            else if ( type_str.equalsIgnoreCase( PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE.toString() ) ) {
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE );
+            }
+            else if ( type_str.equalsIgnoreCase( PHYLOGENY_GRAPHICS_TYPE.ROUNDED.toString() ) ) {
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.ROUNDED );
+            }
+            else if ( type_str.equalsIgnoreCase( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR.toString() ) ) {
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
+            }
+            else if ( type_str.equalsIgnoreCase( PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR.toString() ) ) {
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR );
+            }
+            else if ( type_str.equalsIgnoreCase( PHYLOGENY_GRAPHICS_TYPE.UNROOTED.toString() ) ) {
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
+            }
+            else if ( type_str.equalsIgnoreCase( PHYLOGENY_GRAPHICS_TYPE.CIRCULAR.toString() ) ) {
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CIRCULAR );
+            }
+            else {
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME, "unknown value [" + type_str
+                        + "] for [phylogeny_graphics_type]" );
+            }
+        }
+        else if ( key.equals( "min_confidence_value" ) ) {
+            final String mcv_str = ( ( String ) st.nextElement() ).trim();
+            final double d = parseDouble( mcv_str );
+            setMinConfidenceValue( d );
+        }
+        else if ( key.equals( "font_family" ) ) {
+            processFontFamily( st );
+        }
+        else if ( key.equals( "font_size" ) ) {
+            final String size_str = ( ( String ) st.nextElement() ).trim();
+            final int i = parseInt( size_str );
+            setBaseFontSize( i );
+        }
+        else if ( key.equals( "graphics_export_x" ) ) {
+            final String str = ( ( String ) st.nextElement() ).trim();
+            final int i = parseInt( str );
+            setGraphicsExportX( i );
+        }
+        else if ( key.equals( "graphics_export_y" ) ) {
+            final String str = ( ( String ) st.nextElement() ).trim();
+            final int i = parseInt( str );
+            setGraphicsExportY( i );
+        }
+        else if ( key.equals( "pdf_export_line_width" ) ) {
+            final String str = ( ( String ) st.nextElement() ).trim();
+            final float f = parseFloat( str );
+            if ( f > 0 ) {
+                setPrintLineWidth( f );
+            }
+            else {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME,
+                                                  "value for [pdf_export_line_width] cannot be zero or negative" );
+            }
+        }
+        else if ( key.equals( "default_number_of_bootstrap_resamples" ) ) {
+            final String str = ( ( String ) st.nextElement() ).trim();
+            final int i = parseInt( str );
+            if ( i >= 0 ) {
+                setDefaultBootstrapSamples( i );
+            }
+            else {
+                ForesterUtil
+                        .printWarningMessage( Constants.PRG_NAME,
+                                              "value for [default_number_of_bootstrap_resamples] cannot be negative" );
+            }
+        }
+        else if ( key.equals( "show_scale" ) ) {
+            setShowScale( parseBoolean( ( String ) st.nextElement() ) );
+        }
+        else if ( key.equals( "show_overview" ) ) {
+            setShowOverview( parseBoolean( ( String ) st.nextElement() ) );
+        }
+        else if ( key.equals( "show_branch_length_values" ) ) {
+            setShowBranchLengthValues( parseBoolean( ( String ) st.nextElement() ) );
+        }
+        else if ( key.equals( "background_gradient" ) ) {
+            setBackgroundColorGradient( parseBoolean( ( String ) st.nextElement() ) );
+        }
+        else if ( key.equals( "color_labels_same_as_branch_length_values" ) ) {
+            setColorLabelsSameAsParentBranch( parseBoolean( ( String ) st.nextElement() ) );
+        }
+        else if ( key.equals( "show_domain_labels" ) ) {
+            setShowDomainLabels( parseBoolean( ( String ) st.nextElement() ) );
+        }
+        else if ( key.equals( "abbreviate_scientific_names" ) ) {
+            setAbbreviateScientificTaxonNames( parseBoolean( ( String ) st.nextElement() ) );
+        }
+        else if ( key.equals( "cladogram_type" ) ) {
+            final String type_str = ( ( String ) st.nextElement() ).trim();
+            if ( type_str.equalsIgnoreCase( Options.CLADOGRAM_TYPE.NON_LINED_UP.toString() ) ) {
+                setCladogramType( Options.CLADOGRAM_TYPE.NON_LINED_UP );
+            }
+            else if ( type_str.equalsIgnoreCase( Options.CLADOGRAM_TYPE.EXT_NODE_SUM_DEP.toString() ) ) {
+                setCladogramType( Options.CLADOGRAM_TYPE.EXT_NODE_SUM_DEP );
+            }
+            else if ( type_str.equalsIgnoreCase( Options.CLADOGRAM_TYPE.TOTAL_NODE_SUM_DEP.toString() ) ) {
+                setCladogramType( Options.CLADOGRAM_TYPE.TOTAL_NODE_SUM_DEP );
+            }
+            else {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME, "unknown value [" + type_str
+                        + "] for [cladogram_type]" );
+            }
+        }
+        else if ( key.equals( "non_lined_up_cladogram" ) ) {
+            ForesterUtil
+                    .printWarningMessage( Constants.PRG_NAME,
+                                          "configuration key [non_lined_up_cladogram] is deprecated, use [cladogram_type] instead" );
+        }
+        else if ( key.equals( "hide_controls_and_menus" ) ) {
+            _hide_controls_and_menus = parseBoolean( ( String ) st.nextElement() );
+        }
+        else if ( key.equals( "use_tabbed_display" ) ) {
+            _use_tabbed_display = parseBoolean( ( String ) st.nextElement() );
+        }
+        else if ( key.equals( "overview_width" ) ) {
+            final short i = parseShort( ( ( String ) st.nextElement() ).trim() );
+            setOvMaxWidth( i );
+        }
+        else if ( key.equals( "overview_height" ) ) {
+            final short i = parseShort( ( ( String ) st.nextElement() ).trim() );
+            setOvMaxHeight( i );
+        }
+        else if ( key.equals( "overview_placement_type" ) ) {
+            final String type_str = ( ( String ) st.nextElement() ).trim();
+            if ( type_str.equalsIgnoreCase( OVERVIEW_PLACEMENT_TYPE.UPPER_LEFT.toTag() ) ) {
+                setOvPlacement( OVERVIEW_PLACEMENT_TYPE.UPPER_LEFT );
+            }
+            else if ( type_str.equalsIgnoreCase( OVERVIEW_PLACEMENT_TYPE.UPPER_RIGHT.toTag() ) ) {
+                setOvPlacement( OVERVIEW_PLACEMENT_TYPE.UPPER_RIGHT );
+            }
+            else if ( type_str.equalsIgnoreCase( OVERVIEW_PLACEMENT_TYPE.LOWER_LEFT.toTag() ) ) {
+                setOvPlacement( OVERVIEW_PLACEMENT_TYPE.LOWER_LEFT );
+            }
+            else if ( type_str.equalsIgnoreCase( OVERVIEW_PLACEMENT_TYPE.LOWER_RIGHT.toTag() ) ) {
+                setOvPlacement( OVERVIEW_PLACEMENT_TYPE.LOWER_RIGHT );
+            }
+            else {
+                setOvPlacement( OVERVIEW_PLACEMENT_TYPE.UPPER_LEFT );
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME, "unknown value [" + type_str
+                        + "] for [overview_placement_type]" );
+            }
+        }
+        else if ( key.equals( "node_label_direction" ) ) {
+            final String type_str = ( ( String ) st.nextElement() ).trim();
+            if ( type_str.equalsIgnoreCase( NODE_LABEL_DIRECTION.HORIZONTAL.toString() ) ) {
+                setNodeLabelDirection( NODE_LABEL_DIRECTION.HORIZONTAL );
+            }
+            else if ( type_str.equalsIgnoreCase( NODE_LABEL_DIRECTION.RADIAL.toString() ) ) {
+                setNodeLabelDirection( NODE_LABEL_DIRECTION.RADIAL );
+            }
+            else {
+                setNodeLabelDirection( NODE_LABEL_DIRECTION.HORIZONTAL );
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME, "unknown value [" + type_str
+                        + "] for [node_label_direction]" );
+            }
+        }
+        else if ( key.equals( "branch_length_value_digits" ) ) {
+            final short i = parseShort( ( ( String ) st.nextElement() ).trim() );
+            if ( i >= 0 ) {
+                setNumberOfDigitsAfterCommaForBranchLengthValue( i );
+            }
+            else {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME, "illegal value [" + i
+                        + "] for [branch_length_value_digits]" );
+            }
+        }
+        else if ( key.equals( "confidence_value_digits" ) ) {
+            final short i = parseShort( ( ( String ) st.nextElement() ).trim() );
+            if ( i >= 0 ) {
+                setNumberOfDigitsAfterCommaForConfidenceValues( i );
+            }
+            else {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME, "illegal value [" + i
+                        + "] for [confidence_value_digits]" );
+            }
+        }
+        else if ( key.equals( "allow_editing" ) ) {
+            setEditable( parseBoolean( ( String ) st.nextElement() ) );
+        }
+        else if ( key.equals( "display_sequence_relations" ) ) {
+            setDisplaySequenceRelations( parseBoolean( ( String ) st.nextElement() ) );
+        }
+        else if ( key.equals( "replace_underscores_in_nh_parsing" ) ) {
+            final boolean r = parseBoolean( ( String ) st.nextElement() );
+            if ( r && isExtractPfamTaxonomyCodesInNhParsing() ) {
+                ForesterUtil
+                        .printWarningMessage( Constants.PRG_NAME,
+                                              "attempt to extract taxonomies and replace underscores at the same time" );
+            }
+            else {
+                setReplaceUnderscoresInNhParsing( r );
+            }
+        }
+        else if ( key.equals( "extract_taxonomy_codes_in_nh_parsing" ) ) {
+            final boolean e = parseBoolean( ( String ) st.nextElement() );
+            if ( e && isReplaceUnderscoresInNhParsing() ) {
+                ForesterUtil
+                        .printWarningMessage( Constants.PRG_NAME,
+                                              "attempt to extract taxonomies and replace underscores at the same time" );
+            }
+            else {
+                setExtractPfamTaxonomyCodesInNhParsing( e );
+            }
+        }
+        else if ( key.equals( "internal_labels_are_confidence_values" ) ) {
+            setInternalNumberAreConfidenceForNhParsing( parseBoolean( ( String ) st.nextElement() ) );
+        }
+        else if ( key.equals( "gui_background_color" ) ) {
+            _gui_background_color = Color.decode( ( String ) st.nextElement() );
+        }
+        else if ( key.equals( "gui_checkbox_text_color" ) ) {
+            _gui_checkbox_text_color = Color.decode( ( String ) st.nextElement() );
+        }
+        else if ( key.equals( "gui_checkbox_and_button_active_color" ) ) {
+            _gui_checkbox_and_button_active_color = Color.decode( ( String ) st.nextElement() );
+        }
+        else if ( key.equals( "gui_button_text_color" ) ) {
+            _gui_button_text_color = Color.decode( ( String ) st.nextElement() );
+        }
+        else if ( key.equals( "gui_button_background_color" ) ) {
+            _gui_button_background_color = Color.decode( ( String ) st.nextElement() );
+        }
+        else if ( key.equals( "gui_menu_background_color" ) ) {
+            _gui_menu_background_color = Color.decode( ( String ) st.nextElement() );
+        }
+        else if ( key.equals( "gui_menu_text_color" ) ) {
+            _gui_menu_text_color = Color.decode( ( String ) st.nextElement() );
+        }
+        else if ( key.equals( "gui_button_border_color" ) ) {
+            _gui_button_border_color = Color.decode( ( String ) st.nextElement() );
+        }
+        else if ( key.equals( "domain_structure_font_color" ) ) {
+            _domain_structure_font_color = Color.decode( ( String ) st.nextElement() );
+        }
+        else if ( key.equals( "domain_structure_base_color" ) ) {
+            _domain_structure_base_color = Color.decode( ( String ) st.nextElement() );
+        }
+        else if ( st.countTokens() >= 2 ) { // counts the tokens that are not
+            // yet retrieved!
+            int key_index = -1;
+            if ( key.equals( "use_real_br_lengths" ) || key.equals( "phylogram" ) ) {
+                key_index = Configuration.display_as_phylogram;
+                if ( key.equals( "use_real_br_lengths" ) ) {
+                    ForesterUtil
+                            .printWarningMessage( Constants.PRG_NAME,
+                                                  "configuration key [use_real_br_lengths] is deprecated, use [phylogram] instead" );
+                }
+            }
+            else if ( key.equals( "rollover" ) ) {
+                key_index = Configuration.node_data_popup;
+            }
+            else if ( key.equals( "color_according_to_species" ) ) {
+                key_index = Configuration.color_according_to_species;
+            }
+            else if ( key.equals( "show_node_names" ) ) {
+                key_index = Configuration.show_node_names;
+            }
+            else if ( key.equals( "show_taxonomy" ) || key.equals( "show_taxonomy_code" ) ) {
+                key_index = Configuration.show_tax_code;
+                if ( key.equals( "show_taxonomy" ) ) {
+                    ForesterUtil
+                            .printWarningMessage( Constants.PRG_NAME,
+                                                  "configuration key [show_taxonomy] is deprecated, use [show_taxonomy_code] instead" );
+                }
+            }
+            else if ( key.equals( "write_br_length_values" ) ) {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME,
+                                                  "configuration key [write_br_length_values] is deprecated" );
+                key_index = DEPRECATED;
+            }
+            else if ( key.equals( "write_bootstrap_values" ) || key.equals( "write_confidence_values" ) ) {
+                key_index = Configuration.write_confidence_values;
+                if ( key.equals( "write_bootstrap_values" ) ) {
+                    ForesterUtil
+                            .printWarningMessage( Constants.PRG_NAME,
+                                                  "configuration key [write_bootstrap_values] is deprecated, use [write_confidence_values] instead" );
+                }
+            }
+            else if ( key.equals( "write_events" ) || key.equals( "write_dup_spec" ) ) {
+                key_index = Configuration.write_events;
+                if ( key.equals( "write_dup_spec" ) ) {
+                    ForesterUtil
+                            .printWarningMessage( Constants.PRG_NAME,
+                                                  "configuration key [write_dup_spec] is deprecated, use [write_events] instead" );
+                }
+            }
+            else if ( key.equals( "color_branches" ) ) {
+                key_index = Configuration.color_branches;
+            }
+            else if ( key.equals( "width_branches" ) ) {
+                key_index = Configuration.width_branches;
+            }
+            else if ( key.equals( "color_orthologous" ) ) {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME,
+                                                  "configuration key [color_orthologous] is deprecated" );
+            }
+            else if ( key.equals( "color_subtree_neighbors" ) ) {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME,
+                                                  "configuration key [color_subtree_neighbors] is deprecated" );
+            }
+            else if ( key.equals( "color_super_orthologous" ) ) {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME,
+                                                  "configuration key [color_super_orthologous] is deprecated" );
+            }
+            else if ( key.equals( "mark_nodes_with_box" ) ) {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME,
+                                                  "configuration key [mark_nodes_with_box] is deprecated" );
+                key_index = DEPRECATED;
+            }
+            else if ( key.equals( "show_domain_architectures" ) ) {
+                key_index = Configuration.show_domain_architectures;
+            }
+            else if ( key.equals( "show_annotations" ) ) {
+                key_index = Configuration.show_annotation;
+            }
+            else if ( key.equals( "show_binary_characters" ) ) {
+                key_index = Configuration.show_binary_characters;
+            }
+            else if ( key.equals( "show_binary_character_counts" ) ) {
+                key_index = Configuration.show_binary_character_counts;
+            }
+            else if ( key.equals( "show_gene_names" ) ) {
+                key_index = Configuration.show_gene_names;
+            }
+            else if ( key.equals( "show_gene_symbols" ) ) {
+                key_index = Configuration.show_gene_symbols;
+            }
+            else if ( key.equals( "show_sequence_acc" ) ) {
+                key_index = Configuration.show_sequence_acc;
+            }
+            else if ( key.equals( "show_node_ids" ) ) {
+                ForesterUtil
+                        .printWarningMessage( Constants.PRG_NAME, "configuration key [show_node_ids] is deprecated" );
+                key_index = DEPRECATED;
+            }
+            else if ( key.equals( "display_internal_data" ) ) {
+                key_index = Configuration.display_internal_data;
+            }
+            else if ( key.equals( "dynamically_hide_data" ) ) {
+                key_index = Configuration.dynamically_hide_data;
+            }
+            else if ( key.equals( "show_taxonomy_names" ) ) {
+                ForesterUtil.printWarningMessage( Constants.PRG_NAME,
+                                                  "configuration key [show_taxonomy_names] is deprecated" );
+                key_index = DEPRECATED;
+            }
+            else if ( key.equals( "show_taxonomy_scientific_names" ) ) {
+                key_index = Configuration.show_taxonomy_scientific_names;
+            }
+            else if ( key.equals( "show_taxonomy_common_names" ) ) {
+                key_index = Configuration.show_taxonomy_common_names;
+            }
+            else if ( key.equals( "show_taxonomy_images" ) ) {
+                key_index = Configuration.show_taxonomy_images;
+            }
+            else if ( key.equals( "color_according_to_annotation" ) ) {
+                key_index = Configuration.color_according_to_annotation;
+            }
+            else if ( key.equals( "show_property" ) ) {
+                key_index = Configuration.show_property;
+            }
+            else if ( key.equals( "show_vector_data" ) ) {
+                key_index = Configuration.show_vector_data;
+            }
+            else if ( key.equals( "show_relation_confidence" ) ) {
+                key_index = Configuration.show_relation_confidence;
+            }
+            // If we've found the key, set the values
+            if ( key_index >= 0 ) {
+                display_options[ key_index ][ 1 ] = ( String ) st.nextElement();
+                display_options[ key_index ][ 2 ] = ( String ) st.nextElement();
+                // otherwise, keep looking
+            }
+            else {
+                if ( key_index == DEPRECATED ) {
+                    // Deprecated.
+                }
+                else if ( key.equals( "click_to" ) ) {
+                    final String click_to_name = ( String ) st.nextElement();
+                    key_index = getClickToIndex( click_to_name );
+                    if ( key_index >= 0 ) {
+                        clickto_options[ key_index ][ 1 ] = ( String ) st.nextElement();
+                    }
+                    else if ( key_index == DEPRECATED ) {
+                        // Deprecated.
+                    }
+                    else {
+                        ForesterUtil.printWarningMessage( Constants.PRG_NAME, "unknown click-to option: "
+                                + click_to_name );
+                    }
+                }
+                else if ( key.equals( "species_color" ) ) {
+                    getSpeciesColors().put( ( String ) st.nextElement(), Color.decode( ( String ) st.nextElement() ) );
+                }
+                else if ( key.equals( "domain_color" ) ) {
+                    getDomainColors().put( ( String ) st.nextElement(), Color.decode( ( String ) st.nextElement() ) );
+                }
+                else if ( key.equals( "annotation_color" ) ) {
+                    getAnnotationColors()
+                            .put( ( String ) st.nextElement(), Color.decode( ( String ) st.nextElement() ) );
+                }
+                else if ( key.equals( "function_color" ) ) {
+                    ForesterUtil.printWarningMessage( Constants.PRG_NAME,
+                                                      "configuration key [function_color] is deprecated" );
+                }
+                else if ( key.equals( DISPLAY_COLOR_KEY ) ) {
+                    getDisplayColors().put( ( String ) st.nextElement(), Color.decode( ( String ) st.nextElement() ) );
+                }
+                else if ( key.equals( WEB_LINK_KEY ) ) {
+                    if ( st.countTokens() == 3 ) {
+                        createWebLink( ( String ) st.nextElement(), ( String ) st.nextElement(), ( String ) st
+                                .nextElement() );
+                    }
+                    else {
+                        ForesterUtil.printWarningMessage( Constants.PRG_NAME,
+                                                          "illegal format in configuration file for key [" + key + "]" );
+                    }
+                }
+                else {
+                    ForesterUtil.printWarningMessage( Constants.PRG_NAME, "unknown configuration key [" + key
+                            + "] in: " + config_filename );
+                }
+            }
+        }
+        else {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME, "unknown configuration key [" + key + "] in: "
+                    + config_filename );
+        }
+    }
+
+    private void setMinConfidenceValue( final double min_confidence_value ) {
+        _min_confidence_value = min_confidence_value;
+    }
+
+    void setNodeLabelDirection( final NODE_LABEL_DIRECTION node_label_direction ) {
+        _node_label_direction = node_label_direction;
+    }
+
+    private void setNumberOfDigitsAfterCommaForBranchLengthValue( final short _number_of_digits_after_comma_for_branch_length_values ) {
+        this._number_of_digits_after_comma_for_branch_length_values = _number_of_digits_after_comma_for_branch_length_values;
+    }
+
+    private void setNumberOfDigitsAfterCommaForConfidenceValues( final short _number_of_digits_after_comma_for_confidence_values ) {
+        this._number_of_digits_after_comma_for_confidence_values = _number_of_digits_after_comma_for_confidence_values;
+    }
+
+    private void setOvMaxHeight( final short ov_max_height ) {
+        _ov_max_height = ov_max_height;
+    }
+
+    private void setOvMaxWidth( final short ov_max_width ) {
+        _ov_max_width = ov_max_width;
+    }
+
+    private void setOvPlacement( final OVERVIEW_PLACEMENT_TYPE ov_placement ) {
+        _ov_placement = ov_placement;
+    }
+
+    void setPhylogenyGraphicsType( final PHYLOGENY_GRAPHICS_TYPE phylogeny_graphics_type ) {
+        _phylogeny_graphics_type = phylogeny_graphics_type;
+    }
+
+    private void setPrintLineWidth( final float print_line_width ) {
+        _print_line_width = print_line_width;
+    }
+
+    private void setReplaceUnderscoresInNhParsing( final boolean nh_parsing_replace_underscores ) {
+        _nh_parsing_replace_underscores = nh_parsing_replace_underscores;
+    }
+
+    private void setShowBranchLengthValues( final boolean show_branch_length_values ) {
+        _show_branch_length_values = show_branch_length_values;
+    }
+
+    private void setShowOverview( final boolean show_overview ) {
+        _show_overview = show_overview;
+    }
+
+    private void setShowScale( final boolean show_scale ) {
+        _show_scale = show_scale;
+    }
+
+    private void setValidatePhyloXmlAgainstSchema( final boolean validate_against_phyloxml_xsd_schema ) {
+        _validate_against_phyloxml_xsd_schema = validate_against_phyloxml_xsd_schema;
+    }
+
+    void setWebLinks( final SortedMap<String, WebLink> weblinks ) {
+        _weblinks = weblinks;
+    }
+
+    static String getDefaultFontFamilyName() {
+        return DEFAULT_FONT_FAMILY;
+    }
+
+    static enum TRIPLET {
+        TRUE, FALSE, UNKNOWN
+    }
+
+    public Color getDomainStructureFontColor() {
+        return _domain_structure_font_color;
+    }
+
+    public Color getDomainStructureBaseColor() {
+        return _domain_structure_base_color;
+    }
+
+    public boolean isColorLabelsSameAsParentBranch() {
+        return _color_labels_same_as_parent_branch;
+    }
+
+    public boolean isShowDomainLabels() {
+        return _show_domain_labels;
+    }
+
+    public boolean isAbbreviateScientificTaxonNames() {
+        return _abbreviate_scientific_names;
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/Constants.java b/forester/java/src/org/forester/archaeopteryx/Constants.java
new file mode 100644 (file)
index 0000000..94dfc5d
--- /dev/null
@@ -0,0 +1,109 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// Copyright (C) 2000-2001 Washington University School of Medicine
+// and Howard Hughes Medical Institute
+// Copyright (C) 2003-2007 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.Color;
+import java.awt.Dimension;
+
+import org.forester.archaeopteryx.Options.CLADOGRAM_TYPE;
+import org.forester.util.ForesterConstants;
+
+public final class Constants {
+
+    final static boolean        __ALLOW_PHYLOGENETIC_INFERENCE                                = true;
+    final static boolean        __RELEASE                                                     = false;                                                    // TODO remove me
+    final static boolean        __SNAPSHOT_RELEASE                                            = false;                                                    // TODO remove me
+    final static String         PRG_NAME                                                      = "Archaeopteryx";
+    final static String         VERSION                                                       = "0.960 beta A48";
+    final static String         PRG_DATE                                                      = "2011.01.28";
+    final static String         DEFAULT_CONFIGURATION_FILE_NAME                               = "_aptx_configuration_file";
+    final static String[]       DEFAULT_FONT_CHOICES                                          = { "Verdana", "Tahoma",
+            "Arial", "Helvetica", "Dialog", "Lucida Sans", "SansSerif", "Sans-serif", "Sans" };
+    final static boolean        VERBOSE_DEFAULT                                               = false;
+    final static int            DOMAIN_STRUCTURE_DEFAULT_WIDTH                                = 200;
+    final static String         AUTHOR_EMAIL                                                  = "phylosoft@gmail.com";
+    final static int            DOMAIN_STRUCTURE_E_VALUE_THR_DEFAULT_EXP                      = 0;
+    final static float          BUTTON_ZOOM_IN_FACTOR                                         = 1.25f;
+    final static float          BUTTON_ZOOM_OUT_FACTOR                                        = 1 / Constants.BUTTON_ZOOM_IN_FACTOR;
+    final static float          BUTTON_ZOOM_IN_X_CORRECTION_FACTOR                            = 1.2f;
+    final static float          BUTTON_ZOOM_OUT_X_CORRECTION_FACTOR                           = 1 / Constants.BUTTON_ZOOM_IN_X_CORRECTION_FACTOR;
+    final static float          WHEEL_ZOOM_IN_FACTOR                                          = 1.08f;
+    final static float          WHEEL_ZOOM_OUT_FACTOR                                         = 1 / Constants.WHEEL_ZOOM_IN_FACTOR;
+    final static float          WHEEL_ZOOM_IN_X_CORRECTION_FACTOR                             = 1.085f;
+    final static float          WHEEL_ZOOM_OUT_X_CORRECTION_FACTOR                            = 1 / Constants.WHEEL_ZOOM_IN_X_CORRECTION_FACTOR;
+    static final boolean        SPECIAL_CUSTOM                                                = false;                                                    //TODO remove me
+    static final int            EXT_NODE_INFO_LENGTH_MAX                                      = 300;
+    static final Dimension      NODE_PANEL_SPLIT_MINIMUM_SIZE                                 = new Dimension( 100, 50 );
+    static final Dimension      NODE_PANEL_SIZE                                               = new Dimension( 500, 600 );
+    static final Dimension      NODE_FRAME_SIZE                                               = new Dimension( 520, 640 );
+    static final String         APPLET_PARAM_NAME_FOR_URL_OF_TREE_TO_LOAD                     = "url_of_tree_to_load";
+    static final String         APPLET_PARAM_NAME_FOR_CONFIG_FILE_URL                         = "config_file";
+    static final String         APPLET_PARAM_NAME_FOR_DEFAULT_QUERY_SEQUENCE                  = "homology_type_analysis_query_sequence";
+    static final String         APPLET_PARAM_NAME_FOR_DEFAULT_SEQUENCE_RELATION_TYPE          = "homology_type_analysis_initial_relation_type";
+    static final int            MAX_TREES_TO_LOAD                                             = 100;
+    static final int            US_LETTER_SIZE_X                                              = 612;
+    static final int            US_LETTER_SIZE_Y                                              = 792;
+    static final int            A4_SIZE_X                                                     = 595;
+    static final int            A4_SIZE_Y                                                     = 845;
+    final static float          PDF_LINE_WIDTH_DEFAULT                                        = 0.5f;
+    final static String         APTX_WEB_SITE                                                 = "http://www.phylosoft.org/archaeopteryx/";
+    final static String         PHYLOXML_WEB_SITE                                             = ForesterConstants.PHYLO_XML_LOCATION;
+    final static String         PHYLOXML_REFERENCE_URL                                        = "http://www.biomedcentral.com/1471-2105/10/356/";
+    final static String         APTX_REFERENCE_URL                                            = "http://www.biomedcentral.com/bmcbioinformatics/";
+    final static String         APTX_REFERENCE                                                = "Zmasek...";                                              //TODO
+    final static String         PHYLOXML_REFERENCE                                            = ForesterConstants.PHYLO_XML_REFERENCE;
+    final static String         PHYLOXML_REFERENCE_SHORT                                      = "Han MV and Zmasek CM (2009), BMC Bioinformatics, 10:356";
+    final static short          NUMBER_OF_DIGITS_AFTER_COMMA_FOR_BRANCH_LENGTH_VALUES_DEFAULT = 2;
+    final static short          NUMBER_OF_DIGITS_AFTER_COMMA_FOR_CONFIDENCE_VALUES_DEFAULT    = 1;
+    public static final boolean NH_PARSING_IGNORE_QUOTES_DEFAULT                              = false;
+    static final CLADOGRAM_TYPE CLADOGRAM_TYPE_DEFAULT                                        = CLADOGRAM_TYPE.EXT_NODE_SUM_DEP;
+    final static boolean        VALIDATE_AGAINST_PHYLOXML_XSD_SCJEMA_DEFAULT                  = true;
+    final static String         BACKUP_FILE_SUFFIX                                            = ".BAK";
+    final static double         MIN_NOT_COLLAPSE_DEFAULT                                      = 50;
+    final static Color          GUI_BACKGROUND_DEFAULT                                        = new Color( 32, 32, 32 );
+    final static Color          CHECKBOX_TEXT_COLOR_DEFAULT                                   = new Color( 220,
+                                                                                                           220,
+                                                                                                           220 );
+    final static Color          CHECKBOX_AND_BUTTON_ACTIVE_COLOR_DEFAULT                      = new Color( 255, 0, 0 );
+    final static Color          BUTTON_TEXT_COLOR_DEFAULT                                     = new Color( 255,
+                                                                                                           255,
+                                                                                                           255 );
+    final static Color          BUTTON_BACKGROUND_COLOR_DEFAULT                               = new Color( 64, 64, 64 );
+    final static Color          MENU_BACKGROUND_COLOR_DEFAULT                                 = new Color( 0, 0, 0 );
+    final static Color          MENU_TEXT_COLOR_DEFAULT                                       = new Color( 255,
+                                                                                                           255,
+                                                                                                           255 );
+    final static Color          BUTTON_BORDER_COLOR_DEFAULT                                   = new Color( 0, 0, 0 );
+    final static Color          TAB_LABEL_FOREGROUND_COLOR_SELECTED                           = new Color( 0, 0, 0 );
+    final static Color          DOMAIN_STRUCTURE_BASE_COLOR_DEFAULT                           = new Color( 32, 32, 32 );
+    final static Color          DOMAIN_STRUCTURE_FONT_COLOR_DEFAULT                           = new Color( 144,
+                                                                                                           144,
+                                                                                                           144 );
+    final static String         NCBI_ALL_DATABASE_SEARCH                                      = "http://www.ncbi.nlm.nih.gov/gquery/?term=";
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/ControlPanel.java b/forester/java/src/org/forester/archaeopteryx/ControlPanel.java
new file mode 100644 (file)
index 0000000..d3b56e2
--- /dev/null
@@ -0,0 +1,1905 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.BorderFactory;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollBar;
+import javax.swing.JTextField;
+import javax.swing.ListCellRenderer;
+
+import org.forester.archaeopteryx.Options.CLADOGRAM_TYPE;
+import org.forester.archaeopteryx.Options.PHYLOGENY_GRAPHICS_TYPE;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.phylogeny.PhylogenyMethods;
+import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.Sequence;
+import org.forester.phylogeny.data.SequenceRelation;
+import org.forester.util.ForesterUtil;
+
+final class ControlPanel extends JPanel implements ActionListener {
+
+    private static final String  RETURN_TO_SUPER_TREE_TEXT = "Back to Super Tree";
+    final static Font            jcb_font                  = new Font( Configuration.getDefaultFontFamilyName(),
+                                                                       Font.PLAIN,
+                                                                       9 );
+    final static Font            js_font                   = new Font( Configuration.getDefaultFontFamilyName(),
+                                                                       Font.PLAIN,
+                                                                       9 );
+    final static Font            jcb_bold_font             = new Font( Configuration.getDefaultFontFamilyName(),
+                                                                       Font.BOLD,
+                                                                       9 );
+    private static final long    serialVersionUID          = -8463483932821545633L;
+    private final MainPanel      _mainpanel;
+    // The settings from the conf file
+    private final Configuration  _configuration;
+    // Tree checkboxes
+    private JCheckBox            _display_internal_data;
+    private JCheckBox            _show_node_names;
+    private JCheckBox            _show_taxo_code;
+    private JCheckBox            _write_confidence;
+    private JCheckBox            _show_events;
+    private JCheckBox            _color_acc_species;
+    private JCheckBox            _color_branches_cb;
+    private JCheckBox            _width_branches;
+    private JCheckBox            _show_domain_architectures;
+    private JCheckBox            _show_annotation;
+    private JCheckBox            _show_binary_characters;
+    private JCheckBox            _show_binary_character_counts;
+    private JCheckBox            _show_gene_names;
+    private JCheckBox            _show_gene_symbols;
+    private JCheckBox            _show_sequence_acc;
+    private JCheckBox            _node_desc_popup_cb;
+    private JCheckBox            _dynamically_hide_data;
+    private JCheckBox            _show_taxo_scientific_names;
+    private JCheckBox            _show_taxo_common_names;
+    private JCheckBox            _show_taxo_images_cb;
+    private JCheckBox            _color_according_to_annotation;
+    private JCheckBox            _display_as_phylogram_cb;
+    private JCheckBox            _seq_relation_confidence_switch;
+    private JComboBox            _show_sequence_relations;
+    private JComboBox            _sequence_relation_type_box;
+    private JCheckBox            _show_vector_data_cb;
+    private JLabel               _click_to_label;
+    private JLabel               _zoom_label;
+    private JLabel               _domain_display_label;
+    private JComboBox            _click_to_combobox;
+    private Map<Integer, String> _all_click_to_names;
+    private List<String>         _click_to_names;
+    // Indices for the click-to options in the combo box
+    private int                  _show_data_item;
+    private int                  _collapse_cb_item;
+    private int                  _reroot_cb_item;
+    private int                  _swap_cb_item;
+    private int                  _subtree_cb_item;
+    private int                  _color_subtree_cb_item;
+    private int                  _open_seq_web_item;
+    private int                  _open_tax_web_item;
+    private int                  _cut_subtree_item;
+    private int                  _copy_subtree_item;
+    private int                  _delete_node_or_subtree_item;
+    private int                  _paste_subtree_item;
+    private int                  _add_new_node_item;
+    private int                  _edit_node_data_item;
+    private int                  _blast_item;
+    // zooming and quick tree manipulation buttons:
+    private JButton              _zoom_in_x;
+    private JButton              _zoom_in_y;
+    private JButton              _zoom_out_x;
+    private JButton              _zoom_out_y;
+    private JButton              _show_whole;
+    private JButton              _order;
+    private JButton              _uncollapse_all;
+    private JButton              _zoom_in_domain_structure;
+    private JButton              _zoom_out_domain_structure;
+    private JButton              _decr_domain_structure_evalue_thr;
+    private JButton              _incr_domain_structure_evalue_thr;
+    private JButton              _return_to_super_tree;
+    private JTextField           _domain_structure_evalue_thr_tf;
+    private JTextField           _search_tf;
+    private boolean              _order_of_appearance;
+    private boolean              _color_branches;
+    private NodeClickAction      _action_when_node_clicked;
+    private List<Boolean>        _draw_phylogram;
+    private Map<String, Color>   _annotation_colors;
+    private Map<String, Color>   _species_colors;
+    private JButton              _search_reset_button;
+    private JLabel               _search_found_label;
+    private Sequence             _selected_query_seq;
+
+    ControlPanel( final MainPanel ap, final Configuration configuration ) {
+        init();
+        _mainpanel = ap;
+        _configuration = configuration;
+        if ( !_configuration.isUseNativeUI() ) {
+            setBackground( getConfiguration().getGuiBackgroundColor() );
+            setBorder( BorderFactory.createRaisedBevelBorder() );
+        }
+        setLayout( new GridLayout( 0, 1, 2, 2 ) );
+        _order_of_appearance = true;
+        setupControls();
+    }
+
+    /**
+     * Handle an action.
+     */
+    public void actionPerformed( final ActionEvent e ) {
+        try {
+            final TreePanel tp = getMainPanel().getCurrentTreePanel();
+            if ( tp == null ) {
+                return;
+            }
+            if ( e.getSource() == _click_to_combobox ) {
+                setClickToAction( _click_to_combobox.getSelectedIndex() );
+                getCurrentTreePanel().repaint();
+            }
+            else if ( e.getSource() == _show_binary_characters ) {
+                if ( ( _show_binary_character_counts != null ) && _show_binary_characters.isSelected() ) {
+                    _show_binary_character_counts.setSelected( false );
+                }
+                displayedPhylogenyMightHaveChanged( true );
+            }
+            else if ( e.getSource() == _show_binary_character_counts ) {
+                if ( ( _show_binary_characters != null ) && _show_binary_character_counts.isSelected() ) {
+                    _show_binary_characters.setSelected( false );
+                }
+                displayedPhylogenyMightHaveChanged( true );
+            }
+            else if ( e.getSource() == _color_according_to_annotation ) {
+                if ( ( _show_annotation != null ) && _color_according_to_annotation.isSelected() ) {
+                    _show_annotation.setSelected( true );
+                }
+                displayedPhylogenyMightHaveChanged( false );
+            }
+            else if ( e.getSource() == _show_annotation ) {
+                if ( ( _color_according_to_annotation != null ) && !_show_annotation.isSelected() ) {
+                    _color_according_to_annotation.setSelected( false );
+                }
+                displayedPhylogenyMightHaveChanged( false );
+            }
+            else if ( ( tp != null ) && ( tp.getPhylogeny() != null ) ) {
+                if ( e.getSource() == getDisplayAsPhylogramCb() ) {
+                    setDrawPhylogram( getDisplayAsPhylogramCb().isSelected() );
+                    showWhole();
+                }
+                // Zoom buttons
+                else if ( e.getSource() == _zoom_in_x ) {
+                    zoomInX( Constants.BUTTON_ZOOM_IN_FACTOR, Constants.BUTTON_ZOOM_IN_X_CORRECTION_FACTOR );
+                    displayedPhylogenyMightHaveChanged( false );
+                }
+                else if ( e.getSource() == _zoom_in_y ) {
+                    zoomInY( Constants.BUTTON_ZOOM_IN_FACTOR );
+                    displayedPhylogenyMightHaveChanged( false );
+                }
+                else if ( e.getSource() == _zoom_out_x ) {
+                    zoomOutX( Constants.BUTTON_ZOOM_OUT_FACTOR, Constants.BUTTON_ZOOM_OUT_X_CORRECTION_FACTOR );
+                    displayedPhylogenyMightHaveChanged( false );
+                }
+                else if ( e.getSource() == _zoom_out_y ) {
+                    zoomOutY( Constants.BUTTON_ZOOM_OUT_FACTOR );
+                    displayedPhylogenyMightHaveChanged( false );
+                }
+                else if ( e.getSource() == _show_whole ) {
+                    showWhole();
+                }
+                else if ( e.getSource() == _return_to_super_tree ) {
+                    _mainpanel.getCurrentTreePanel().superTree();
+                    showWhole();
+                }
+                else if ( e.getSource() == _order ) {
+                    tp.getPhylogeny().orderAppearance( _order_of_appearance );
+                    _order_of_appearance = !_order_of_appearance;
+                    displayedPhylogenyMightHaveChanged( false );
+                }
+                else if ( e.getSource() == _uncollapse_all ) {
+                    uncollapseAll( tp );
+                    displayedPhylogenyMightHaveChanged( false );
+                }
+                else if ( e.getSource() == _zoom_in_domain_structure ) {
+                    _mainpanel.getCurrentTreePanel().zoomInDomainStructure();
+                    displayedPhylogenyMightHaveChanged( true );
+                }
+                else if ( e.getSource() == _zoom_out_domain_structure ) {
+                    _mainpanel.getCurrentTreePanel().zoomOutDomainStructure();
+                    displayedPhylogenyMightHaveChanged( true );
+                }
+                else if ( e.getSource() == _decr_domain_structure_evalue_thr ) {
+                    _mainpanel.getCurrentTreePanel().decreaseDomainStructureEvalueThreshold();
+                    displayedPhylogenyMightHaveChanged( true );
+                }
+                else if ( e.getSource() == _incr_domain_structure_evalue_thr ) {
+                    _mainpanel.getCurrentTreePanel().increaseDomainStructureEvalueThreshold();
+                    displayedPhylogenyMightHaveChanged( true );
+                }
+                else if ( e.getSource() == _search_tf ) {
+                    search();
+                    displayedPhylogenyMightHaveChanged( true );
+                }
+                else {
+                    displayedPhylogenyMightHaveChanged( true );
+                }
+            }
+            tp.requestFocus();
+            tp.requestFocusInWindow();
+            tp.requestFocus();
+        }
+        catch ( final Exception ex ) {
+            Util.unexpectedException( ex );
+        }
+        catch ( final Error err ) {
+            Util.unexpectedError( err );
+        }
+    }
+
+    void activateButtonToReturnToSuperTree( int index ) {
+        --index;
+        if ( index > 0 ) {
+            _return_to_super_tree.setText( RETURN_TO_SUPER_TREE_TEXT + " " + index );
+        }
+        else {
+            _return_to_super_tree.setText( RETURN_TO_SUPER_TREE_TEXT );
+        }
+        _return_to_super_tree.setForeground( getConfiguration().getGuiCheckboxAndButtonActiveColor() );
+        _return_to_super_tree.setEnabled( true );
+    }
+
+    /**
+     * Add zoom and quick edit buttons. (Last modified 8/9/04)
+     */
+    void addButtons() {
+        final JLabel spacer = new JLabel( "" );
+        spacer.setOpaque( false );
+        add( spacer );
+        final JPanel x_panel = new JPanel( new GridLayout( 1, 1, 0, 0 ) );
+        final JPanel y_panel = new JPanel( new GridLayout( 1, 3, 0, 0 ) );
+        final JPanel z_panel = new JPanel( new GridLayout( 1, 1, 0, 0 ) );
+        if ( !getConfiguration().isUseNativeUI() ) {
+            x_panel.setBackground( getBackground() );
+            y_panel.setBackground( getBackground() );
+            z_panel.setBackground( getBackground() );
+        }
+        add( _zoom_label = new JLabel( "Zoom:" ) );
+        customizeLabel( _zoom_label, getConfiguration() );
+        add( x_panel );
+        add( y_panel );
+        add( z_panel );
+        if ( getConfiguration().isUseNativeUI() ) {
+            _zoom_in_x = new JButton( "+" );
+            _zoom_out_x = new JButton( "-" );
+        }
+        else {
+            _zoom_in_x = new JButton( "X+" );
+            _zoom_out_x = new JButton( "X-" );
+        }
+        _zoom_in_y = new JButton( "Y+" );
+        _zoom_out_y = new JButton( "Y-" );
+        _show_whole = new JButton( "F" );
+        _show_whole.setToolTipText( "To fit the complete phylogeny to the current display size [Backspace]" );
+        _zoom_in_x.setToolTipText( "To zoom in horizontally [Shift+Right]" );
+        _zoom_in_y.setToolTipText( "To zoom in vertically [Shift+Up]" );
+        _zoom_out_x.setToolTipText( "To zoom out horizontally [Shift+Left]" );
+        _zoom_out_y.setToolTipText( "To zoom out vertically [Shift+Down]" );
+        if ( getConfiguration().isUseNativeUI() && Util.isMac() ) {
+            _zoom_out_x.setPreferredSize( new Dimension( 55, 10 ) );
+            _zoom_in_x.setPreferredSize( new Dimension( 55, 10 ) );
+        }
+        else {
+            _zoom_out_x.setPreferredSize( new Dimension( 10, 10 ) );
+            _zoom_in_x.setPreferredSize( new Dimension( 10, 10 ) );
+        }
+        _zoom_out_y.setPreferredSize( new Dimension( 10, 10 ) );
+        _zoom_in_y.setPreferredSize( new Dimension( 10, 10 ) );
+        _show_whole.setPreferredSize( new Dimension( 10, 10 ) );
+        _return_to_super_tree = new JButton( RETURN_TO_SUPER_TREE_TEXT );
+        _return_to_super_tree.setEnabled( false );
+        _order = new JButton( "Order Subtrees" );
+        _uncollapse_all = new JButton( "Uncollapse All" );
+        addJButton( _zoom_in_y, x_panel );
+        addJButton( _zoom_out_x, y_panel );
+        addJButton( _show_whole, y_panel );
+        addJButton( _zoom_in_x, y_panel );
+        addJButton( _zoom_out_y, z_panel );
+        if ( getConfiguration().doDisplayOption( Configuration.show_domain_architectures ) ) {
+            setUpControlsForDomainStrucures();
+        }
+        final JLabel spacer2 = new JLabel( "" );
+        add( spacer2 );
+        addJButton( _return_to_super_tree, this );
+        addJButton( _order, this );
+        addJButton( _uncollapse_all, this );
+        final JLabel spacer3 = new JLabel( "" );
+        add( spacer3 );
+        setVisibilityOfDomainStrucureControls();
+    }
+
+    void addCheckbox( final int which, final String title ) {
+        final JPanel ch_panel = new JPanel( new BorderLayout( 0, 0 ) );
+        switch ( which ) {
+            case Configuration.display_as_phylogram:
+                _display_as_phylogram_cb = new JCheckBox( title );
+                getDisplayAsPhylogramCb().setToolTipText( "To switch between phylogram and cladogram display" );
+                addJCheckBox( getDisplayAsPhylogramCb(), ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.display_internal_data:
+                _display_internal_data = new JCheckBox( title );
+                _display_internal_data.setToolTipText( "To allow or disallow display of internal labels" );
+                addJCheckBox( _display_internal_data, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.color_according_to_species:
+                _color_acc_species = new JCheckBox( title );
+                _color_acc_species
+                        .setToolTipText( "To colorize taxonomy and sequence labels as a function of taxonomy" );
+                addJCheckBox( _color_acc_species, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.color_according_to_annotation:
+                _color_according_to_annotation = new JCheckBox( title );
+                _color_according_to_annotation
+                        .setToolTipText( "To colorize sequence annotation labels as a function of sequence annotation" );
+                addJCheckBox( _color_according_to_annotation, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_node_names:
+                _show_node_names = new JCheckBox( title );
+                addJCheckBox( _show_node_names, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_tax_code:
+                _show_taxo_code = new JCheckBox( title );
+                addJCheckBox( _show_taxo_code, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_taxonomy_scientific_names:
+                _show_taxo_scientific_names = new JCheckBox( title );
+                addJCheckBox( _show_taxo_scientific_names, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_taxonomy_common_names:
+                _show_taxo_common_names = new JCheckBox( title );
+                addJCheckBox( _show_taxo_common_names, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_taxonomy_images:
+                _show_taxo_images_cb = new JCheckBox( title );
+                addJCheckBox( _show_taxo_images_cb, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_binary_characters:
+                _show_binary_characters = new JCheckBox( title );
+                addJCheckBox( _show_binary_characters, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_annotation:
+                _show_annotation = new JCheckBox( title );
+                addJCheckBox( _show_annotation, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_binary_character_counts:
+                _show_binary_character_counts = new JCheckBox( title );
+                addJCheckBox( _show_binary_character_counts, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.write_confidence_values:
+                _write_confidence = new JCheckBox( title );
+                addJCheckBox( getWriteConfidenceCb(), ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.write_events:
+                _show_events = new JCheckBox( title );
+                addJCheckBox( getShowEventsCb(), ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.color_branches:
+                _color_branches_cb = new JCheckBox( title );
+                getColorBranchesCb().setToolTipText( "To use branch color values, if present" );
+                addJCheckBox( getColorBranchesCb(), ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.width_branches:
+                _width_branches = new JCheckBox( title );
+                _width_branches.setToolTipText( "To use branch width values, if present" );
+                addJCheckBox( _width_branches, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_domain_architectures:
+                _show_domain_architectures = new JCheckBox( title );
+                addJCheckBox( _show_domain_architectures, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_gene_names:
+                _show_gene_names = new JCheckBox( title );
+                addJCheckBox( _show_gene_names, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_gene_symbols:
+                _show_gene_symbols = new JCheckBox( title );
+                addJCheckBox( _show_gene_symbols, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_sequence_acc:
+                _show_sequence_acc = new JCheckBox( title );
+                addJCheckBox( _show_sequence_acc, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.dynamically_hide_data:
+                _dynamically_hide_data = new JCheckBox( title );
+                getDynamicallyHideData().setToolTipText( "To hide labels depending on likely visibility" );
+                addJCheckBox( getDynamicallyHideData(), ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.node_data_popup:
+                _node_desc_popup_cb = new JCheckBox( title );
+                getNodeDescPopupCb().setToolTipText( "To enable mouse rollover display of basic node data" );
+                addJCheckBox( getNodeDescPopupCb(), ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_relation_confidence:
+                _seq_relation_confidence_switch = new JCheckBox( title );
+                addJCheckBox( _seq_relation_confidence_switch, ch_panel );
+                add( ch_panel );
+                break;
+            case Configuration.show_vector_data:
+                _show_vector_data_cb = new JCheckBox( title );
+                addJCheckBox( _show_vector_data_cb, ch_panel );
+                add( ch_panel );
+                break;
+            default:
+                throw new RuntimeException( "unknown checkbox: " + which );
+        }
+    }// addCheckbox
+
+    private void addClickToOption( final int which, final String title ) {
+        _click_to_combobox.addItem( title );
+        _click_to_names.add( title );
+        _all_click_to_names.put( new Integer( which ), title );
+        if ( !_configuration.isUseNativeUI() ) {
+            _click_to_combobox.setBackground( getConfiguration().getGuiButtonBackgroundColor() );
+            _click_to_combobox.setForeground( getConfiguration().getGuiButtonTextColor() );
+        }
+    }
+
+    void addJButton( final JButton jb, final JPanel p ) {
+        jb.setFocusPainted( false );
+        jb.setFont( ControlPanel.jcb_font );
+        if ( !_configuration.isUseNativeUI() ) {
+            jb.setBorder( BorderFactory.createLineBorder( getConfiguration().getGuiButtonBorderColor() ) );
+            jb.setBackground( getConfiguration().getGuiButtonBackgroundColor() );
+            jb.setForeground( getConfiguration().getGuiButtonTextColor() );
+        }
+        p.add( jb );
+        jb.addActionListener( this );
+    }
+
+    void addJCheckBox( final JCheckBox jcb, final JPanel p ) {
+        jcb.setFocusPainted( false );
+        jcb.setFont( ControlPanel.jcb_font );
+        if ( !_configuration.isUseNativeUI() ) {
+            jcb.setBackground( getConfiguration().getGuiBackgroundColor() );
+            jcb.setForeground( getConfiguration().getGuiCheckboxTextColor() );
+        }
+        p.add( jcb, "Center" );
+        jcb.addActionListener( this );
+    }
+
+    void addJTextField( final JTextField tf, final JPanel p ) {
+        if ( !_configuration.isUseNativeUI() ) {
+            tf.setForeground( getConfiguration().getGuiBackgroundColor() );
+            tf.setFont( ControlPanel.jcb_font );
+        }
+        p.add( tf );
+        tf.addActionListener( this );
+    }
+
+    /* GUILHEM_BEG */
+    private void addSequenceRelationBlock() {
+        final JLabel spacer = new JLabel( "" );
+        spacer.setSize( 1, 1 );
+        add( spacer );
+        final JLabel mainLabel = new JLabel( "Sequence relations to display" );
+        final JLabel typeLabel = customizeLabel( new JLabel( "(type) " ), getConfiguration() );
+        typeLabel.setFont( ControlPanel.js_font.deriveFont( 7 ) );
+        getSequenceRelationTypeBox().setFocusable( false );
+        _sequence_relation_type_box.setFont( ControlPanel.js_font );
+        if ( !_configuration.isUseNativeUI() ) {
+            _sequence_relation_type_box.setBackground( getConfiguration().getGuiButtonBackgroundColor() );
+            _sequence_relation_type_box.setForeground( getConfiguration().getGuiButtonTextColor() );
+        }
+        _sequence_relation_type_box.setRenderer( new ListCellRenderer() {
+
+            @Override
+            public Component getListCellRendererComponent( final JList list,
+                                                           final Object value,
+                                                           final int index,
+                                                           final boolean isSelected,
+                                                           final boolean cellHasFocus ) {
+                final Component component = new DefaultListCellRenderer().getListCellRendererComponent( list,
+                                                                                                        value,
+                                                                                                        index,
+                                                                                                        isSelected,
+                                                                                                        cellHasFocus );
+                if ( ( value != null ) && ( value instanceof SequenceRelation.SEQUENCE_RELATION_TYPE ) ) {
+                    ( ( DefaultListCellRenderer ) component ).setText( SequenceRelation
+                            .getPrintableNameByType( ( SequenceRelation.SEQUENCE_RELATION_TYPE ) value ) );
+                }
+                return component;
+            }
+        } );
+        final GridBagLayout gbl = new GridBagLayout();
+        _sequence_relation_type_box.setMinimumSize( new Dimension( 115, 17 ) );
+        _sequence_relation_type_box.setPreferredSize( new Dimension( 115, 20 ) );
+        final JPanel horizGrid = new JPanel( gbl );
+        horizGrid.setBackground( getBackground() );
+        horizGrid.add( typeLabel );
+        horizGrid.add( _sequence_relation_type_box );
+        add( customizeLabel( mainLabel, getConfiguration() ) );
+        add( horizGrid );
+        add( getSequenceRelationBox() );
+        if ( _configuration.doDisplayOption( Configuration.show_relation_confidence ) ) {
+            addCheckbox( Configuration.show_relation_confidence, _configuration
+                    .getDisplayTitle( Configuration.show_relation_confidence ) );
+            setCheckbox( Configuration.show_relation_confidence, _configuration
+                    .doCheckOption( Configuration.show_relation_confidence ) );
+        }
+    }// addSequenceRelationBlock
+
+    void deactivateButtonToReturnToSuperTree() {
+        _return_to_super_tree.setText( RETURN_TO_SUPER_TREE_TEXT );
+        _return_to_super_tree.setForeground( getConfiguration().getGuiButtonTextColor() );
+        _return_to_super_tree.setEnabled( false );
+    }
+
+    void displayedPhylogenyMightHaveChanged( final boolean recalc_longest_ext_node_info ) {
+        if ( ( _mainpanel != null ) && ( _mainpanel.getCurrentPhylogeny() != null ) ) {
+            if ( getOptions().isShowOverview() ) {
+                _mainpanel.getCurrentTreePanel().updateOvSizes();
+            }
+            _mainpanel.getCurrentTreePanel().recalculateMaxDistanceToRoot();
+            setVisibilityOfDomainStrucureControls();
+            updateDomainStructureEvaluethresholdDisplay();
+            _mainpanel.getCurrentTreePanel().calculateScaleDistance();
+            _mainpanel.getCurrentTreePanel().calcMaxDepth();
+            _mainpanel.adjustJScrollPane();
+            if ( recalc_longest_ext_node_info ) {
+                _mainpanel.getCurrentTreePanel().initNodeData();
+                _mainpanel.getCurrentTreePanel().calculateLongestExtNodeInfo();
+            }
+            _mainpanel.getCurrentTreePanel().repaint();
+            // _mainpanel.getCurrentTreePanel().setUpUrtFactors();
+        }
+    }
+
+    void endClickToOptions() {
+        _click_to_combobox.addActionListener( this );
+    }
+
+    /**
+     * Indicates what action should be execute when a node is clicked
+     * 
+     * @return the click-on action
+     */
+    NodeClickAction getActionWhenNodeClicked() {
+        return _action_when_node_clicked;
+    }
+
+    Map<Integer, String> getAllClickToItems() {
+        return _all_click_to_names;
+    }
+
+    Map<String, Color> getAnnotationColors() {
+        return _annotation_colors;
+    }
+
+    public JCheckBox getColorBranchesCb() {
+        return _color_branches_cb;
+    }
+
+    Configuration getConfiguration() {
+        return _configuration;
+    }
+
+    TreePanel getCurrentTreePanel() {
+        return getMainPanel().getCurrentTreePanel();
+    }
+
+    public JCheckBox getDisplayAsPhylogramCb() {
+        return _display_as_phylogram_cb;
+    }
+
+    public JCheckBox getDynamicallyHideData() {
+        return _dynamically_hide_data;
+    }
+
+    /* GUILHEM_END */
+    private List<Boolean> getIsDrawPhylogramList() {
+        return _draw_phylogram;
+    }
+
+    MainPanel getMainPanel() {
+        return _mainpanel;
+    }
+
+    public JCheckBox getNodeDescPopupCb() {
+        return _node_desc_popup_cb;
+    }
+
+    Options getOptions() {
+        return getMainPanel().getOptions();
+    }
+
+    private JLabel getSearchFoundCountsLabel() {
+        return _search_found_label;
+    }
+
+    private JButton getSearchResetButton() {
+        return _search_reset_button;
+    }
+
+    JTextField getSearchTextField() {
+        return _search_tf;
+    }
+
+    public Sequence getSelectedQuerySequence() {
+        return _selected_query_seq;
+    }
+
+    public JComboBox getSequenceRelationBox() {
+        if ( _show_sequence_relations == null ) {
+            _show_sequence_relations = new JComboBox();
+            _show_sequence_relations.setFocusable( false );
+            _show_sequence_relations.setMaximumRowCount( 20 );
+            _show_sequence_relations.setFont( ControlPanel.js_font );
+            if ( !_configuration.isUseNativeUI() ) {
+                _show_sequence_relations.setBackground( getConfiguration().getGuiButtonBackgroundColor() );
+                _show_sequence_relations.setForeground( getConfiguration().getGuiButtonTextColor() );
+            }
+            _show_sequence_relations.addItem( "-----" );
+            _show_sequence_relations.setToolTipText( "To display orthology information for selected query" );
+        }
+        return _show_sequence_relations;
+    }
+
+    /* GUILHEM_BEG */
+    public JComboBox getSequenceRelationTypeBox() {
+        if ( _sequence_relation_type_box == null ) {
+            _sequence_relation_type_box = new JComboBox();
+            for( final SequenceRelation.SEQUENCE_RELATION_TYPE type : SequenceRelation.SEQUENCE_RELATION_TYPE.values() ) {
+                _sequence_relation_type_box.addItem( type );
+            }
+            _sequence_relation_type_box.addActionListener( new ActionListener() {
+
+                @Override
+                public void actionPerformed( final ActionEvent e ) {
+                    if ( _mainpanel.getCurrentPhylogeny() != null ) {
+                        setSequenceRelationQueries( getMainPanel().getCurrentPhylogeny().getSequenceRelationQueries() );
+                    }
+                }
+            } );
+        }
+        return _sequence_relation_type_box;
+    }
+
+    public JCheckBox getShowEventsCb() {
+        return _show_events;
+    }
+
+    List<String> getSingleClickToNames() {
+        return _click_to_names;
+    }
+
+    Map<String, Color> getSpeciesColors() {
+        return _species_colors;
+    }
+
+    public JCheckBox getWriteConfidenceCb() {
+        return _write_confidence;
+    }
+
+    private void init() {
+        _draw_phylogram = new ArrayList<Boolean>();
+        setSpeciesColors( new HashMap<String, Color>() );
+        setAnnotationColors( new HashMap<String, Color>() );
+    }
+
+    boolean isAntialiasScreenText() {
+        return true;
+    }
+
+    boolean isColorAccordingToAnnotation() {
+        return ( ( _color_according_to_annotation != null ) && _color_according_to_annotation.isSelected() );
+    }
+
+    boolean isColorAccordingToTaxonomy() {
+        return ( ( _color_acc_species != null ) && _color_acc_species.isSelected() );
+    }
+
+    boolean isColorBranches() {
+        return ( ( ( getColorBranchesCb() != null ) && getColorBranchesCb().isSelected() ) || ( ( getColorBranchesCb() == null ) && _color_branches ) );
+    }
+
+    boolean isDrawPhylogram() {
+        return isDrawPhylogram( getMainPanel().getCurrentTabIndex() );
+    }
+
+    private boolean isDrawPhylogram( final int index ) {
+        return getIsDrawPhylogramList().get( index );
+    }
+
+    boolean isDynamicallyHideData() {
+        return ( ( getDynamicallyHideData() != null ) && getDynamicallyHideData().isSelected() );
+    }
+
+    boolean isEvents() {
+        return ( ( getShowEventsCb() != null ) && getShowEventsCb().isSelected() );
+    }
+
+    boolean isNodeDescPopup() {
+        return ( ( getNodeDescPopupCb() != null ) && getNodeDescPopupCb().isSelected() );
+    }
+
+    boolean isShowAnnotation() {
+        return ( ( _show_annotation != null ) && _show_annotation.isSelected() );
+    }
+
+    boolean isShowBinaryCharacterCounts() {
+        return ( ( _show_binary_character_counts != null ) && _show_binary_character_counts.isSelected() );
+    }
+
+    boolean isShowBinaryCharacters() {
+        return ( ( _show_binary_characters != null ) && _show_binary_characters.isSelected() );
+    }
+
+    boolean isShowBootstrapValues() {
+        return ( ( getWriteConfidenceCb() != null ) && getWriteConfidenceCb().isSelected() );
+    }
+
+    boolean isShowDomainArchitectures() {
+        return ( ( _show_domain_architectures != null ) && _show_domain_architectures.isSelected() );
+    }
+
+    boolean isShowGeneNames() {
+        return ( ( _show_gene_names != null ) && _show_gene_names.isSelected() );
+    }
+
+    public boolean isShowVectorData() {
+        return ( ( _show_vector_data_cb != null ) && _show_vector_data_cb.isSelected() );
+    }
+
+    boolean isShowGeneSymbols() {
+        return ( ( _show_gene_symbols != null ) && _show_gene_symbols.isSelected() );
+    }
+
+    boolean isShowInternalData() {
+        return ( ( _display_internal_data == null ) || _display_internal_data.isSelected() );
+    }
+
+    boolean isShowNodeNames() {
+        return ( ( _show_node_names != null ) && _show_node_names.isSelected() );
+    }
+
+    boolean isShowProperty() {
+        return ( ( _show_annotation != null ) && _show_annotation.isSelected() );
+    }
+
+    boolean isShowSequenceAcc() {
+        return ( ( _show_sequence_acc != null ) && _show_sequence_acc.isSelected() );
+    }
+
+    boolean isShowSequenceRelationConfidence() {
+        return ( ( _seq_relation_confidence_switch != null ) && ( _seq_relation_confidence_switch.isSelected() ) );
+    }
+
+    boolean isShowSequenceRelations() {
+        return ( ( _show_sequence_relations != null ) && ( _show_sequence_relations.getSelectedIndex() > 0 ) );
+    }
+
+    boolean isShowTaxonomyCode() {
+        return ( ( _show_taxo_code != null ) && _show_taxo_code.isSelected() );
+    }
+
+    public boolean isShowTaxonomyImages() {
+        return ( ( _show_taxo_images_cb != null ) && _show_taxo_images_cb.isSelected() );
+    }
+
+    boolean isShowTaxonomyCommonNames() {
+        return ( ( _show_taxo_common_names != null ) && _show_taxo_common_names.isSelected() );
+    }
+
+    boolean isShowTaxonomyScientificNames() {
+        return ( ( _show_taxo_scientific_names != null ) && _show_taxo_scientific_names.isSelected() );
+    }
+
+    boolean isWidthBranches() {
+        return ( ( _width_branches != null ) && _width_branches.isSelected() );
+    }
+
+    void phylogenyAdded( final Configuration configuration ) {
+        getIsDrawPhylogramList().add( configuration.isDrawAsPhylogram() );
+    }
+
+    void phylogenyRemoved( final int index ) {
+        getIsDrawPhylogramList().remove( index );
+    }
+
+    void search() {
+        final MainPanel main_panel = getMainPanel();
+        final Phylogeny tree = main_panel.getCurrentPhylogeny();
+        if ( ( tree == null ) || tree.isEmpty() ) {
+            return;
+        }
+        String query = getSearchTextField().getText();
+        if ( query != null ) {
+            query = query.trim();
+        }
+        else {
+            getSearchFoundCountsLabel().setVisible( false );
+            getSearchResetButton().setEnabled( false );
+            getSearchResetButton().setVisible( false );
+            searchReset();
+        }
+        if ( !ForesterUtil.isEmpty( query ) ) {
+            search( main_panel, tree, query );
+        }
+        else {
+            getSearchFoundCountsLabel().setVisible( false );
+            getSearchResetButton().setEnabled( false );
+            getSearchResetButton().setVisible( false );
+            searchReset();
+        }
+    }
+
+    private void search( final MainPanel main_panel, final Phylogeny tree, final String query_str ) {
+        getSearchFoundCountsLabel().setVisible( true );
+        getSearchResetButton().setEnabled( true );
+        getSearchResetButton().setVisible( true );
+        String[] queries = null;
+        List<PhylogenyNode> nodes = null;
+        if ( query_str.indexOf( ',' ) >= 0 ) {
+            queries = query_str.split( ",+" );
+        }
+        else {
+            queries = new String[ 1 ];
+            queries[ 0 ] = query_str.trim();
+        }
+        if ( ( queries != null ) && ( queries.length > 0 ) ) {
+            nodes = new ArrayList<PhylogenyNode>();
+            for( String query : queries ) {
+                if ( ForesterUtil.isEmpty( query ) ) {
+                    continue;
+                }
+                query = query.trim();
+                if ( query.indexOf( '+' ) >= 0 ) {
+                    nodes.addAll( PhylogenyMethods.searchDataLogicalAnd( query.split( "\\++" ), tree, getOptions()
+                            .isSearchCaseSensitive(), !getOptions().isMatchWholeTermsOnly() ) );
+                }
+                else {
+                    nodes.addAll( PhylogenyMethods.searchData( query,
+                                                               tree,
+                                                               getOptions().isSearchCaseSensitive(),
+                                                               !getOptions().isMatchWholeTermsOnly() ) );
+                }
+            }
+            if ( getOptions().isInverseSearchResult() ) {
+                final List<PhylogenyNode> all = PhylogenyMethods.obtainAllNodesAsList( tree );
+                all.removeAll( nodes );
+                nodes = all;
+            }
+        }
+        if ( ( nodes != null ) && ( nodes.size() > 0 ) ) {
+            main_panel.getCurrentTreePanel().setFoundNodes( new HashSet<Integer>() );
+            for( final PhylogenyNode node : nodes ) {
+                main_panel.getCurrentTreePanel().getFoundNodes().add( node.getId() );
+            }
+            setSearchFoundCountsOnLabel( nodes.size() );
+        }
+        else {
+            setSearchFoundCountsOnLabel( 0 );
+            searchReset();
+        }
+    }
+
+    private void searchReset() {
+        if ( getMainPanel().getCurrentTreePanel() != null ) {
+            getMainPanel().getCurrentTreePanel().setFoundNodes( null );
+        }
+    }
+
+    void setActionWhenNodeClicked( final NodeClickAction action ) {
+        _action_when_node_clicked = action;
+    }
+
+    void setAnnotationColors( final Map<String, Color> annotation_colors ) {
+        _annotation_colors = annotation_colors;
+    }
+
+    void setCheckbox( final int which, final boolean state ) {
+        switch ( which ) {
+            case Configuration.display_as_phylogram:
+                if ( getDisplayAsPhylogramCb() != null ) {
+                    getDisplayAsPhylogramCb().setSelected( state );
+                }
+                break;
+            case Configuration.display_internal_data:
+                if ( _display_internal_data != null ) {
+                    _display_internal_data.setSelected( state );
+                }
+                break;
+            case Configuration.color_according_to_species:
+                if ( _color_acc_species != null ) {
+                    _color_acc_species.setSelected( state );
+                }
+                break;
+            case Configuration.color_according_to_annotation:
+                if ( _color_according_to_annotation != null ) {
+                    _color_according_to_annotation.setSelected( state );
+                }
+                break;
+            case Configuration.show_node_names:
+                if ( _show_node_names != null ) {
+                    _show_node_names.setSelected( state );
+                }
+                break;
+            case Configuration.show_tax_code:
+                if ( _show_taxo_code != null ) {
+                    _show_taxo_code.setSelected( state );
+                }
+                break;
+            case Configuration.show_taxonomy_scientific_names:
+                if ( _show_taxo_scientific_names != null ) {
+                    _show_taxo_scientific_names.setSelected( state );
+                }
+                break;
+            case Configuration.show_taxonomy_common_names:
+                if ( _show_taxo_common_names != null ) {
+                    _show_taxo_common_names.setSelected( state );
+                }
+                break;
+            case Configuration.show_taxonomy_images:
+                if ( _show_taxo_images_cb != null ) {
+                    _show_taxo_images_cb.setSelected( state );
+                }
+                break;
+            case Configuration.show_annotation:
+                if ( _show_annotation != null ) {
+                    _show_annotation.setSelected( state );
+                }
+                break;
+            case Configuration.show_binary_characters:
+                if ( _show_binary_characters != null ) {
+                    _show_binary_characters.setSelected( state );
+                }
+                break;
+            case Configuration.show_binary_character_counts:
+                if ( _show_binary_character_counts != null ) {
+                    _show_binary_character_counts.setSelected( state );
+                }
+                break;
+            case Configuration.write_confidence_values:
+                if ( getWriteConfidenceCb() != null ) {
+                    getWriteConfidenceCb().setSelected( state );
+                }
+                break;
+            case Configuration.write_events:
+                if ( getShowEventsCb() != null ) {
+                    getShowEventsCb().setSelected( state );
+                }
+                break;
+            case Configuration.color_branches:
+                if ( getColorBranchesCb() != null ) {
+                    getColorBranchesCb().setSelected( state );
+                }
+                break;
+            case Configuration.width_branches:
+                if ( _width_branches != null ) {
+                    _width_branches.setSelected( state );
+                }
+                break;
+            case Configuration.show_domain_architectures:
+                if ( _show_domain_architectures != null ) {
+                    _show_domain_architectures.setSelected( state );
+                }
+                break;
+            case Configuration.show_gene_names:
+                if ( _show_gene_names != null ) {
+                    _show_gene_names.setSelected( state );
+                }
+                break;
+            case Configuration.show_gene_symbols:
+                if ( _show_gene_symbols != null ) {
+                    _show_gene_symbols.setSelected( state );
+                }
+                break;
+            case Configuration.show_vector_data:
+                if ( _show_vector_data_cb != null ) {
+                    _show_vector_data_cb.setSelected( state );
+                }
+                break;
+            case Configuration.show_sequence_acc:
+                if ( _show_sequence_acc != null ) {
+                    _show_sequence_acc.setSelected( state );
+                }
+                break;
+            case Configuration.dynamically_hide_data:
+                if ( getDynamicallyHideData() != null ) {
+                    getDynamicallyHideData().setSelected( state );
+                }
+                break;
+            case Configuration.node_data_popup:
+                if ( getNodeDescPopupCb() != null ) {
+                    getNodeDescPopupCb().setSelected( state );
+                }
+                break;
+            /* GUILHEM_BEG */
+            case Configuration.show_relation_confidence:
+                if ( _seq_relation_confidence_switch != null ) {
+                    _seq_relation_confidence_switch.setSelected( state );
+                }
+                break;
+            /* GUILHEM_END */
+            default:
+                throw new AssertionError( "unknown checkbox: " + which );
+        }
+    }
+
+    /**
+     * Set this checkbox state. Not all checkboxes have been instantiated
+     * depending on the config.
+     */
+    void setCheckbox( final JCheckBox cb, final boolean state ) {
+        if ( cb != null ) {
+            cb.setSelected( state );
+        }
+    }
+
+    void setClickToAction( final int action ) {
+        // Set click-to action
+        if ( action == _show_data_item ) {
+            setActionWhenNodeClicked( NodeClickAction.SHOW_DATA );
+        }
+        else if ( action == _collapse_cb_item ) {
+            setActionWhenNodeClicked( NodeClickAction.COLLAPSE );
+        }
+        else if ( action == _reroot_cb_item ) {
+            setActionWhenNodeClicked( NodeClickAction.REROOT );
+        }
+        else if ( action == _subtree_cb_item ) {
+            setActionWhenNodeClicked( NodeClickAction.SUBTREE );
+        }
+        else if ( action == _swap_cb_item ) {
+            setActionWhenNodeClicked( NodeClickAction.SWAP );
+        }
+        else if ( action == _color_subtree_cb_item ) {
+            setActionWhenNodeClicked( NodeClickAction.COLOR_SUBTREE );
+        }
+        else if ( action == _open_seq_web_item ) {
+            setActionWhenNodeClicked( NodeClickAction.OPEN_SEQ_WEB );
+        }
+        else if ( action == _blast_item ) {
+            if ( !Constants.__RELEASE && !Constants.__SNAPSHOT_RELEASE ) {
+                setActionWhenNodeClicked( NodeClickAction.BLAST );
+            }
+        }
+        else if ( action == _open_tax_web_item ) {
+            setActionWhenNodeClicked( NodeClickAction.OPEN_TAX_WEB );
+        }
+        else if ( action == _cut_subtree_item ) {
+            setActionWhenNodeClicked( NodeClickAction.CUT_SUBTREE );
+        }
+        else if ( action == _copy_subtree_item ) {
+            setActionWhenNodeClicked( NodeClickAction.COPY_SUBTREE );
+        }
+        else if ( action == _delete_node_or_subtree_item ) {
+            setActionWhenNodeClicked( NodeClickAction.DELETE_NODE_OR_SUBTREE );
+        }
+        else if ( action == _paste_subtree_item ) {
+            setActionWhenNodeClicked( NodeClickAction.PASTE_SUBTREE );
+        }
+        else if ( action == _add_new_node_item ) {
+            setActionWhenNodeClicked( NodeClickAction.ADD_NEW_NODE );
+        }
+        else if ( action == _edit_node_data_item ) {
+            setActionWhenNodeClicked( NodeClickAction.EDIT_NODE_DATA );
+        }
+        else {
+            throw new RuntimeException( "unknown action: " + action );
+        }
+        // make sure drop down is displaying the correct action
+        // in case this was called from outside the class
+        _click_to_combobox.setSelectedIndex( action );
+    }
+
+    void setColorBranches( final boolean color_branches ) {
+        _color_branches = color_branches;
+    }
+
+    void setDrawPhylogram( final boolean b ) {
+        getDisplayAsPhylogramCb().setSelected( b );
+        setDrawPhylogram( getMainPanel().getCurrentTabIndex(), b );
+    }
+
+    private void setDrawPhylogram( final int index, final boolean b ) {
+        getIsDrawPhylogramList().set( index, b );
+    }
+
+    void setDrawPhylogramEnabled( final boolean b ) {
+        getDisplayAsPhylogramCb().setEnabled( b );
+    }
+
+    void setDynamicHidingIsOn( final boolean is_on ) {
+        //  if ( !_configuration.isUseNativeUI() ) {
+        if ( is_on ) {
+            getDynamicallyHideData().setForeground( getConfiguration().getGuiCheckboxAndButtonActiveColor() );
+        }
+        else {
+            if ( !_configuration.isUseNativeUI() ) {
+                getDynamicallyHideData().setForeground( getConfiguration().getGuiButtonTextColor() );
+            }
+            else {
+                getDynamicallyHideData().setForeground( Color.BLACK );
+            }
+        }
+        // }
+    }
+
+    private void setSearchFoundCountsOnLabel( final int counts ) {
+        getSearchFoundCountsLabel().setText( "Found: " + counts );
+    }
+
+    public void setSequenceRelationQueries( final Collection<Sequence> sequenceRelationQueries ) {
+        final JComboBox box = getSequenceRelationBox();
+        while ( box.getItemCount() > 1 ) {
+            box.removeItemAt( 1 );
+        }
+        final HashMap<String, Sequence> sequencesByName = new HashMap<String, Sequence>();
+        final SequenceRelation.SEQUENCE_RELATION_TYPE relationType = ( SequenceRelation.SEQUENCE_RELATION_TYPE ) _sequence_relation_type_box
+                .getSelectedItem();
+        if ( relationType == null ) {
+            return;
+        }
+        final ArrayList<String> sequenceNamesToAdd = new ArrayList<String>();
+        for( final Sequence seq : sequenceRelationQueries ) {
+            if ( seq.hasSequenceRelations() ) {
+                boolean fFoundForCurrentType = false;
+                for( final SequenceRelation sq : seq.getSequenceRelations() ) {
+                    if ( sq.getType().equals( relationType ) ) {
+                        fFoundForCurrentType = true;
+                        break;
+                    }
+                }
+                if ( fFoundForCurrentType ) {
+                    sequenceNamesToAdd.add( seq.getName() );
+                    sequencesByName.put( seq.getName(), seq );
+                }
+            }
+        }
+        // sort sequences by name before adding them to the combo
+        final String[] sequenceNameArray = sequenceNamesToAdd.toArray( new String[ sequenceNamesToAdd.size() ] );
+        Arrays.sort( sequenceNameArray, String.CASE_INSENSITIVE_ORDER );
+        for( final String seqName : sequenceNameArray ) {
+            box.addItem( seqName );
+        }
+        for( final ItemListener oldItemListener : box.getItemListeners() ) {
+            box.removeItemListener( oldItemListener );
+        }
+        box.addItemListener( new ItemListener() {
+
+            @Override
+            public void itemStateChanged( final ItemEvent e ) {
+                _selected_query_seq = sequencesByName.get( e.getItem() );
+                _mainpanel.getCurrentTreePanel().repaint();
+            }
+        } );
+    }
+
+    void setShowEvents( final boolean show_events ) {
+        if ( getShowEventsCb() == null ) {
+            _show_events = new JCheckBox( "" );
+        }
+        getShowEventsCb().setSelected( show_events );
+    }
+
+    void setSpeciesColors( final Map<String, Color> species_colors ) {
+        _species_colors = species_colors;
+    }
+
+    private void setupClickToOptions() {
+        final int default_option = _configuration.getDefaultDisplayClicktoOption();
+        int selected_index = 0;
+        int cb_index = 0;
+        if ( _configuration.doDisplayClickToOption( Configuration.display_node_data ) ) {
+            _show_data_item = cb_index;
+            addClickToOption( Configuration.display_node_data, _configuration
+                    .getClickToTitle( Configuration.display_node_data ) );
+            if ( default_option == Configuration.display_node_data ) {
+                selected_index = cb_index;
+            }
+            cb_index++;
+        }
+        if ( _configuration.doDisplayClickToOption( Configuration.collapse_uncollapse ) ) {
+            _collapse_cb_item = cb_index;
+            addClickToOption( Configuration.collapse_uncollapse, _configuration
+                    .getClickToTitle( Configuration.collapse_uncollapse ) );
+            if ( default_option == Configuration.collapse_uncollapse ) {
+                selected_index = cb_index;
+            }
+            cb_index++;
+        }
+        if ( _configuration.doDisplayClickToOption( Configuration.reroot ) ) {
+            _reroot_cb_item = cb_index;
+            addClickToOption( Configuration.reroot, _configuration.getClickToTitle( Configuration.reroot ) );
+            if ( default_option == Configuration.reroot ) {
+                selected_index = cb_index;
+            }
+            cb_index++;
+        }
+        if ( _configuration.doDisplayClickToOption( Configuration.subtree ) ) {
+            _subtree_cb_item = cb_index;
+            addClickToOption( Configuration.subtree, _configuration.getClickToTitle( Configuration.subtree ) );
+            if ( default_option == Configuration.subtree ) {
+                selected_index = cb_index;
+            }
+            cb_index++;
+        }
+        if ( _configuration.doDisplayClickToOption( Configuration.swap ) ) {
+            _swap_cb_item = cb_index;
+            addClickToOption( Configuration.swap, _configuration.getClickToTitle( Configuration.swap ) );
+            if ( default_option == Configuration.swap ) {
+                selected_index = cb_index;
+            }
+            cb_index++;
+        }
+        if ( _configuration.doDisplayClickToOption( Configuration.color_subtree ) ) {
+            _color_subtree_cb_item = cb_index;
+            addClickToOption( Configuration.color_subtree, _configuration.getClickToTitle( Configuration.color_subtree ) );
+            if ( default_option == Configuration.color_subtree ) {
+                selected_index = cb_index;
+            }
+            cb_index++;
+        }
+        if ( _configuration.doDisplayClickToOption( Configuration.open_seq_web ) ) {
+            _open_seq_web_item = cb_index;
+            addClickToOption( Configuration.open_seq_web, _configuration.getClickToTitle( Configuration.open_seq_web ) );
+            if ( default_option == Configuration.open_seq_web ) {
+                selected_index = cb_index;
+            }
+            cb_index++;
+        }
+        if ( _configuration.doDisplayClickToOption( Configuration.open_tax_web ) ) {
+            _open_tax_web_item = cb_index;
+            addClickToOption( Configuration.open_tax_web, _configuration.getClickToTitle( Configuration.open_tax_web ) );
+            if ( default_option == Configuration.open_tax_web ) {
+                selected_index = cb_index;
+            }
+            cb_index++;
+        }
+        if ( getOptions().isEditable() ) {
+            if ( _configuration.doDisplayClickToOption( Configuration.cut_subtree ) ) {
+                _cut_subtree_item = cb_index;
+                addClickToOption( Configuration.cut_subtree, _configuration.getClickToTitle( Configuration.cut_subtree ) );
+                if ( default_option == Configuration.cut_subtree ) {
+                    selected_index = cb_index;
+                }
+                cb_index++;
+            }
+            if ( _configuration.doDisplayClickToOption( Configuration.copy_subtree ) ) {
+                _copy_subtree_item = cb_index;
+                addClickToOption( Configuration.copy_subtree, _configuration
+                        .getClickToTitle( Configuration.copy_subtree ) );
+                if ( default_option == Configuration.copy_subtree ) {
+                    selected_index = cb_index;
+                }
+                cb_index++;
+            }
+            if ( _configuration.doDisplayClickToOption( Configuration.paste_subtree ) ) {
+                _paste_subtree_item = cb_index;
+                addClickToOption( Configuration.paste_subtree, _configuration
+                        .getClickToTitle( Configuration.paste_subtree ) );
+                if ( default_option == Configuration.paste_subtree ) {
+                    selected_index = cb_index;
+                }
+                cb_index++;
+            }
+            if ( _configuration.doDisplayClickToOption( Configuration.delete_subtree_or_node ) ) {
+                _delete_node_or_subtree_item = cb_index;
+                addClickToOption( Configuration.delete_subtree_or_node, _configuration
+                        .getClickToTitle( Configuration.delete_subtree_or_node ) );
+                if ( default_option == Configuration.delete_subtree_or_node ) {
+                    selected_index = cb_index;
+                }
+                cb_index++;
+            }
+            if ( _configuration.doDisplayClickToOption( Configuration.add_new_node ) ) {
+                _add_new_node_item = cb_index;
+                addClickToOption( Configuration.add_new_node, _configuration
+                        .getClickToTitle( Configuration.add_new_node ) );
+                if ( default_option == Configuration.add_new_node ) {
+                    selected_index = cb_index;
+                }
+                cb_index++;
+            }
+            if ( _configuration.doDisplayClickToOption( Configuration.edit_node_data ) ) {
+                _edit_node_data_item = cb_index;
+                addClickToOption( Configuration.edit_node_data, _configuration
+                        .getClickToTitle( Configuration.edit_node_data ) );
+                if ( default_option == Configuration.edit_node_data ) {
+                    selected_index = cb_index;
+                }
+                cb_index++;
+            }
+            if ( !Constants.__RELEASE && !Constants.__SNAPSHOT_RELEASE ) {
+                if ( _configuration.doDisplayClickToOption( Configuration.blast ) ) {
+                    _blast_item = cb_index;
+                    addClickToOption( Configuration.blast, _configuration.getClickToTitle( Configuration.blast ) );
+                    if ( default_option == Configuration.blast ) {
+                        selected_index = cb_index;
+                    }
+                    cb_index++;
+                }
+            }
+        }
+        // Set default selection and its action
+        _click_to_combobox.setSelectedIndex( selected_index );
+        setClickToAction( selected_index );
+    }
+
+    /* GUILHEM_END */
+    /*
+     * Set up the controls from the config settings. 11/26/05
+     */
+    void setupControls() {
+        // The tree display options:
+        setupDisplayCheckboxes();
+        /* GUILHEM_BEG */
+        // The sequence relation query selection combo-box
+        if ( _configuration.displaySequenceRelations() ) {
+            addSequenceRelationBlock();
+        }
+        /* GUILHEM_END */
+        // Click-to options
+        startClickToOptions();
+        setupClickToOptions();
+        endClickToOptions();
+        // Zoom and quick edit buttons
+        addButtons();
+        setupSearchTools();
+    }
+
+    void setUpControlsForDomainStrucures() {
+        _domain_display_label = new JLabel( "Domain Display:" );
+        add( customizeLabel( _domain_display_label, getConfiguration() ) );
+        add( _domain_display_label );
+        _zoom_in_domain_structure = new JButton( "d+" );
+        _zoom_out_domain_structure = new JButton( "d-" );
+        _decr_domain_structure_evalue_thr = new JButton( "-" );
+        _incr_domain_structure_evalue_thr = new JButton( "+" );
+        _zoom_in_domain_structure.setPreferredSize( new Dimension( 10, 10 ) );
+        _zoom_out_domain_structure.setPreferredSize( new Dimension( 10, 10 ) );
+        _decr_domain_structure_evalue_thr.setPreferredSize( new Dimension( 10, 10 ) );
+        _incr_domain_structure_evalue_thr.setPreferredSize( new Dimension( 10, 10 ) );
+        _incr_domain_structure_evalue_thr.setToolTipText( "Increase the E-value threshold by a factor of 10" );
+        _decr_domain_structure_evalue_thr.setToolTipText( "Decrease the E-value threshold by a factor of 10" );
+        _domain_structure_evalue_thr_tf = new JTextField( 3 );
+        _domain_structure_evalue_thr_tf.setEditable( false );
+        if ( !getConfiguration().isUseNativeUI() ) {
+            _domain_structure_evalue_thr_tf.setForeground( getConfiguration().getGuiMenuBackgroundColor() );
+            _domain_structure_evalue_thr_tf.setBackground( getConfiguration().getGuiCheckboxTextColor() );
+            _domain_structure_evalue_thr_tf.setBorder( null );
+        }
+        final JPanel d1_panel = new JPanel( new GridLayout( 1, 2, 0, 0 ) );
+        final JPanel d2_panel = new JPanel( new GridLayout( 1, 3, 0, 0 ) );
+        if ( !_configuration.isUseNativeUI() ) {
+            d1_panel.setBackground( getBackground() );
+            d2_panel.setBackground( getBackground() );
+        }
+        add( d1_panel );
+        add( d2_panel );
+        addJButton( _zoom_out_domain_structure, d1_panel );
+        addJButton( _zoom_in_domain_structure, d1_panel );
+        addJButton( _decr_domain_structure_evalue_thr, d2_panel );
+        addJTextField( _domain_structure_evalue_thr_tf, d2_panel );
+        addJButton( _incr_domain_structure_evalue_thr, d2_panel );
+    }
+
+    private void setupDisplayCheckboxes() {
+        if ( _configuration.doDisplayOption( Configuration.display_as_phylogram ) ) {
+            addCheckbox( Configuration.display_as_phylogram, _configuration
+                    .getDisplayTitle( Configuration.display_as_phylogram ) );
+            setCheckbox( Configuration.display_as_phylogram, _configuration
+                    .doCheckOption( Configuration.display_as_phylogram ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.dynamically_hide_data ) ) {
+            addCheckbox( Configuration.dynamically_hide_data, _configuration
+                    .getDisplayTitle( Configuration.dynamically_hide_data ) );
+            setCheckbox( Configuration.dynamically_hide_data, _configuration
+                    .doCheckOption( Configuration.dynamically_hide_data ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.node_data_popup ) ) {
+            addCheckbox( Configuration.node_data_popup, _configuration.getDisplayTitle( Configuration.node_data_popup ) );
+            setCheckbox( Configuration.node_data_popup, _configuration.doCheckOption( Configuration.node_data_popup ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.display_internal_data ) ) {
+            addCheckbox( Configuration.display_internal_data, _configuration
+                    .getDisplayTitle( Configuration.display_internal_data ) );
+            setCheckbox( Configuration.display_internal_data, _configuration
+                    .doCheckOption( Configuration.display_internal_data ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.color_according_to_species ) ) {
+            addCheckbox( Configuration.color_according_to_species, _configuration
+                    .getDisplayTitle( Configuration.color_according_to_species ) );
+            setCheckbox( Configuration.color_according_to_species, _configuration
+                    .doCheckOption( Configuration.color_according_to_species ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.color_according_to_annotation ) ) {
+            addCheckbox( Configuration.color_according_to_annotation, _configuration
+                    .getDisplayTitle( Configuration.color_according_to_annotation ) );
+            setCheckbox( Configuration.color_according_to_annotation, _configuration
+                    .doCheckOption( Configuration.color_according_to_annotation ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.color_branches ) ) {
+            addCheckbox( Configuration.color_branches, _configuration.getDisplayTitle( Configuration.color_branches ) );
+            setCheckbox( Configuration.color_branches, _configuration.doCheckOption( Configuration.color_branches ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.width_branches ) ) {
+            addCheckbox( Configuration.width_branches, _configuration.getDisplayTitle( Configuration.width_branches ) );
+            setCheckbox( Configuration.width_branches, _configuration.doCheckOption( Configuration.width_branches ) );
+        }
+        final JLabel label = new JLabel( "Display Data:" );
+        label.setFont( ControlPanel.jcb_bold_font );
+        if ( !getConfiguration().isUseNativeUI() ) {
+            label.setForeground( getConfiguration().getGuiCheckboxTextColor() );
+        }
+        add( label );
+        if ( _configuration.doDisplayOption( Configuration.show_node_names ) ) {
+            addCheckbox( Configuration.show_node_names, _configuration.getDisplayTitle( Configuration.show_node_names ) );
+            setCheckbox( Configuration.show_node_names, _configuration.doCheckOption( Configuration.show_node_names ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.show_tax_code ) ) {
+            addCheckbox( Configuration.show_tax_code, _configuration.getDisplayTitle( Configuration.show_tax_code ) );
+            setCheckbox( Configuration.show_tax_code, _configuration.doCheckOption( Configuration.show_tax_code ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.show_taxonomy_scientific_names ) ) {
+            addCheckbox( Configuration.show_taxonomy_scientific_names, _configuration
+                    .getDisplayTitle( Configuration.show_taxonomy_scientific_names ) );
+            setCheckbox( Configuration.show_taxonomy_scientific_names, _configuration
+                    .doCheckOption( Configuration.show_taxonomy_scientific_names ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.show_taxonomy_common_names ) ) {
+            addCheckbox( Configuration.show_taxonomy_common_names, _configuration
+                    .getDisplayTitle( Configuration.show_taxonomy_common_names ) );
+            setCheckbox( Configuration.show_taxonomy_common_names, _configuration
+                    .doCheckOption( Configuration.show_taxonomy_common_names ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.show_taxonomy_images ) ) {
+            addCheckbox( Configuration.show_taxonomy_images, _configuration
+                    .getDisplayTitle( Configuration.show_taxonomy_images ) );
+            setCheckbox( Configuration.show_taxonomy_images, _configuration
+                    .doCheckOption( Configuration.show_taxonomy_images ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.show_gene_symbols ) ) {
+            addCheckbox( Configuration.show_gene_symbols, _configuration
+                    .getDisplayTitle( Configuration.show_gene_symbols ) );
+            setCheckbox( Configuration.show_gene_symbols, _configuration
+                    .doCheckOption( Configuration.show_gene_symbols ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.show_gene_names ) ) {
+            addCheckbox( Configuration.show_gene_names, _configuration.getDisplayTitle( Configuration.show_gene_names ) );
+            setCheckbox( Configuration.show_gene_names, _configuration.doCheckOption( Configuration.show_gene_names ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.show_sequence_acc ) ) {
+            addCheckbox( Configuration.show_sequence_acc, _configuration
+                    .getDisplayTitle( Configuration.show_sequence_acc ) );
+            setCheckbox( Configuration.show_sequence_acc, _configuration
+                    .doCheckOption( Configuration.show_sequence_acc ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.show_annotation ) ) {
+            addCheckbox( Configuration.show_annotation, _configuration.getDisplayTitle( Configuration.show_annotation ) );
+            setCheckbox( Configuration.show_annotation, _configuration.doCheckOption( Configuration.show_annotation ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.show_binary_characters ) ) {
+            addCheckbox( Configuration.show_binary_characters, _configuration
+                    .getDisplayTitle( Configuration.show_binary_characters ) );
+            setCheckbox( Configuration.show_binary_characters, _configuration
+                    .doCheckOption( Configuration.show_binary_characters ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.show_binary_character_counts ) ) {
+            addCheckbox( Configuration.show_binary_character_counts, _configuration
+                    .getDisplayTitle( Configuration.show_binary_character_counts ) );
+            setCheckbox( Configuration.show_binary_character_counts, _configuration
+                    .doCheckOption( Configuration.show_binary_character_counts ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.show_domain_architectures ) ) {
+            addCheckbox( Configuration.show_domain_architectures, _configuration
+                    .getDisplayTitle( Configuration.show_domain_architectures ) );
+            setCheckbox( Configuration.show_domain_architectures, _configuration
+                    .doCheckOption( Configuration.show_domain_architectures ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.write_confidence_values ) ) {
+            addCheckbox( Configuration.write_confidence_values, _configuration
+                    .getDisplayTitle( Configuration.write_confidence_values ) );
+            setCheckbox( Configuration.write_confidence_values, _configuration
+                    .doCheckOption( Configuration.write_confidence_values ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.write_events ) ) {
+            addCheckbox( Configuration.write_events, _configuration.getDisplayTitle( Configuration.write_events ) );
+            setCheckbox( Configuration.write_events, _configuration.doCheckOption( Configuration.write_events ) );
+        }
+        if ( _configuration.doDisplayOption( Configuration.show_vector_data ) ) {
+            addCheckbox( Configuration.show_vector_data, _configuration
+                    .getDisplayTitle( Configuration.show_vector_data ) );
+            setCheckbox( Configuration.show_vector_data, _configuration.doCheckOption( Configuration.show_vector_data ) );
+        }
+    }
+
+    void setupSearchTools() {
+        final String tip = "Enter text to search for. Use ',' for multiple searches (logical OR) and '+' for logical AND.";
+        final JLabel search_label = new JLabel( "Search:" );
+        search_label.setFont( ControlPanel.jcb_bold_font );
+        if ( !getConfiguration().isUseNativeUI() ) {
+            search_label.setForeground( getConfiguration().getGuiCheckboxTextColor() );
+        }
+        add( search_label );
+        search_label.setToolTipText( tip );
+        _search_found_label = new JLabel();
+        getSearchFoundCountsLabel().setVisible( false );
+        _search_found_label.setFont( ControlPanel.jcb_bold_font );
+        if ( !getConfiguration().isUseNativeUI() ) {
+            _search_found_label.setForeground( getConfiguration().getGuiCheckboxTextColor() );
+        }
+        _search_tf = new JTextField( 3 );
+        _search_tf.setToolTipText( tip );
+        _search_tf.setEditable( true );
+        if ( !getConfiguration().isUseNativeUI() ) {
+            _search_tf.setForeground( getConfiguration().getGuiMenuBackgroundColor() );
+            _search_tf.setBackground( getConfiguration().getGuiCheckboxTextColor() );
+            _search_tf.setBorder( null );
+        }
+        _search_reset_button = new JButton();
+        getSearchResetButton().setText( "Reset" );
+        getSearchResetButton().setEnabled( false );
+        getSearchResetButton().setVisible( false );
+        final JPanel s_panel_1 = new JPanel( new BorderLayout() );
+        final JPanel s_panel_2 = new JPanel( new GridLayout( 1, 2, 0, 0 ) );
+        s_panel_1.setBackground( getBackground() );
+        add( s_panel_1 );
+        s_panel_2.setBackground( getBackground() );
+        add( s_panel_2 );
+        final KeyAdapter key_adapter = new KeyAdapter() {
+
+            @Override
+            public void keyReleased( final KeyEvent key_event ) {
+                search();
+                displayedPhylogenyMightHaveChanged( true );
+            }
+        };
+        final ActionListener action_listener = new ActionListener() {
+
+            @Override
+            public void actionPerformed( final ActionEvent e ) {
+                searchReset();
+                setSearchFoundCountsOnLabel( 0 );
+                getSearchFoundCountsLabel().setVisible( false );
+                getSearchTextField().setText( "" );
+                getSearchResetButton().setEnabled( false );
+                getSearchResetButton().setVisible( false );
+                displayedPhylogenyMightHaveChanged( true );
+            }
+        };
+        _search_reset_button.addActionListener( action_listener );
+        _search_tf.addKeyListener( key_adapter );
+        addJTextField( _search_tf, s_panel_1 );
+        s_panel_2.add( _search_found_label );
+        addJButton( _search_reset_button, s_panel_2 );
+    }
+
+    private void setVisibilityOfDomainStrucureControls() {
+        if ( _zoom_in_domain_structure != null ) {
+            if ( isShowDomainArchitectures() ) {
+                _domain_display_label.setVisible( true );
+                _zoom_in_domain_structure.setVisible( true );
+                _zoom_out_domain_structure.setVisible( true );
+                _decr_domain_structure_evalue_thr.setVisible( true );
+                _incr_domain_structure_evalue_thr.setVisible( true );
+                _domain_structure_evalue_thr_tf.setVisible( true );
+            }
+            else {
+                _domain_display_label.setVisible( false );
+                _zoom_in_domain_structure.setVisible( false );
+                _zoom_out_domain_structure.setVisible( false );
+                _decr_domain_structure_evalue_thr.setVisible( false );
+                _incr_domain_structure_evalue_thr.setVisible( false );
+                _domain_structure_evalue_thr_tf.setVisible( false );
+            }
+        }
+    }
+
+    /**
+     * Fit entire tree into window.
+     */
+    void showWhole() {
+        if ( _mainpanel.getCurrentScrollPane() == null ) {
+            return;
+        }
+        displayedPhylogenyMightHaveChanged( false );
+        _mainpanel.getCurrentTreePanel().updateOvSettings();
+        _mainpanel.getCurrentTreePanel().validate();
+        _mainpanel.validate();
+        _mainpanel.getCurrentTreePanel().setParametersForPainting( _mainpanel.getSizeOfViewport().width,
+                                                                   _mainpanel.getSizeOfViewport().height,
+                                                                   true );
+        _mainpanel.getCurrentTreePanel().resetPreferredSize();
+        _mainpanel.adjustJScrollPane();
+        _mainpanel.getCurrentTreePanel().repaint();
+        _mainpanel.getCurrentTreePanel().validate();
+        _mainpanel.validate();
+        _mainpanel.getCurrentTreePanel().setParametersForPainting( _mainpanel.getSizeOfViewport().width,
+                                                                   _mainpanel.getSizeOfViewport().height,
+                                                                   true );
+        _mainpanel.getCurrentTreePanel().resetPreferredSize();
+        _mainpanel.adjustJScrollPane();
+        _mainpanel.getCurrentTreePanel().repaint();
+        _mainpanel.getCurrentTreePanel().updateOvSizes();
+    }
+
+    void showWholeAll() {
+        for( final TreePanel tree_panel : _mainpanel.getTreePanels() ) {
+            if ( tree_panel != null ) {
+                tree_panel.validate();
+                tree_panel.setParametersForPainting( _mainpanel.getSizeOfViewport().width, _mainpanel
+                        .getSizeOfViewport().height, true );
+                tree_panel.resetPreferredSize();
+                tree_panel.repaint();
+            }
+        }
+    }
+
+    // Create header for click-to combo box.
+    void startClickToOptions() {
+        final JLabel spacer = new JLabel( "" );
+        spacer.setFont( ControlPanel.jcb_font );
+        add( spacer );
+        _click_to_label = new JLabel( "Click on Node to:" );
+        add( customizeLabel( _click_to_label, getConfiguration() ) );
+        _click_to_combobox = new JComboBox();
+        _click_to_combobox.setFocusable( false );
+        _click_to_combobox.setMaximumRowCount( 14 );
+        _click_to_combobox.setFont( ControlPanel.js_font );
+        if ( !_configuration.isUseNativeUI() ) {
+            _click_to_combobox.setBackground( getConfiguration().getGuiBackgroundColor() );
+        }
+        // don't add listener until all items are set (or each one will trigger
+        // an event)
+        // click_to_list.addActionListener(this);
+        add( _click_to_combobox );
+        // Correlates option names to titles
+        _all_click_to_names = new HashMap<Integer, String>();
+        _click_to_names = new ArrayList<String>();
+    }
+
+    void tabChanged() {
+        if ( getMainPanel().getTabbedPane().getTabCount() > 0 ) {
+            if ( getCurrentTreePanel().isPhyHasBranchLengths()
+                    && ( getCurrentTreePanel().getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
+                setDrawPhylogramEnabled( true );
+                setDrawPhylogram( isDrawPhylogram() );
+            }
+            else {
+                setDrawPhylogramEnabled( false );
+                setDrawPhylogram( false );
+            }
+            if ( getMainPanel().getMainFrame() == null ) {
+                // Must be "E" applet version.
+                final ArchaeopteryxE e = ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet();
+                e.setSelectedTypeInTypeMenu( e.getCurrentTreePanel().getPhylogenyGraphicsType() );
+            }
+            else {
+                getMainPanel().getMainFrame().setSelectedTypeInTypeMenu( getMainPanel().getCurrentTreePanel()
+                        .getPhylogenyGraphicsType() );
+            }
+            getMainPanel().getCurrentTreePanel().updateSubSuperTreeButton();
+            getMainPanel().getControlPanel().search();
+            getSequenceRelationTypeBox().removeAllItems();
+            for( final SequenceRelation.SEQUENCE_RELATION_TYPE type : getMainPanel().getCurrentPhylogeny()
+                    .getRelevantSequenceRelationTypes() ) {
+                _sequence_relation_type_box.addItem( type );
+            }
+            //setSequenceRelationQueries( getMainPanel().getCurrentPhylogeny().getSequenceRelationQueries() );
+            // according to GUILHEM the line above can be removed.
+        }
+    }
+
+    /**
+     * Uncollapse all nodes.
+     */
+    void uncollapseAll( final TreePanel tp ) {
+        final Phylogeny t = tp.getPhylogeny();
+        if ( ( t != null ) && !t.isEmpty() ) {
+            t.setAllNodesToNotCollapse();
+            t.recalculateNumberOfExternalDescendants( false );
+            showWhole();
+        }
+    }
+
+    void updateDomainStructureEvaluethresholdDisplay() {
+        if ( _domain_structure_evalue_thr_tf != null ) {
+            _domain_structure_evalue_thr_tf.setText( "10^"
+                    + getMainPanel().getCurrentTreePanel().getDomainStructureEvalueThreshold() );
+        }
+    }
+
+    void zoomInX( final float factor, final float x_correction_factor ) {
+        final JScrollBar sb = getMainPanel().getCurrentScrollPane().getHorizontalScrollBar();
+        final TreePanel treepanel = getMainPanel().getCurrentTreePanel();
+        treepanel.multiplyUrtFactor( 1f );
+        if ( ( treepanel.getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR )
+                || ( treepanel.getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
+                || isDrawPhylogram( getMainPanel().getCurrentTabIndex() )
+                || ( getOptions().getCladogramType() == CLADOGRAM_TYPE.NON_LINED_UP ) ) {
+            final double x = ( sb.getMaximum() - sb.getMinimum() ) / ( sb.getValue() + ( sb.getVisibleAmount() / 2.0 ) );
+            treepanel.setXdistance( ( treepanel.getXdistance() * factor ) );
+            treepanel.setXcorrectionFactor( ( treepanel.getXcorrectionFactor() * x_correction_factor ) );
+            getMainPanel().adjustJScrollPane();
+            treepanel.resetPreferredSize();
+            getMainPanel().getCurrentScrollPane().getViewport().validate();
+            sb.setValue( ForesterUtil.roundToInt( ( ( sb.getMaximum() - sb.getMinimum() ) / x )
+                    - ( sb.getVisibleAmount() / 2.0 ) ) );
+        }
+        else {
+            final int x = sb.getMaximum() - sb.getMinimum() - sb.getVisibleAmount() - sb.getValue();
+            treepanel.setXdistance( ( treepanel.getXdistance() * factor ) );
+            treepanel.setXcorrectionFactor( ( treepanel.getXcorrectionFactor() * x_correction_factor ) );
+            getMainPanel().adjustJScrollPane();
+            treepanel.resetPreferredSize();
+            getMainPanel().getCurrentScrollPane().getViewport().validate();
+            sb.setValue( sb.getMaximum() - sb.getMinimum() - x - sb.getVisibleAmount() );
+        }
+        treepanel.resetPreferredSize();
+        treepanel.updateOvSizes();
+    }
+
+    void zoomInY( final float factor ) {
+        final JScrollBar sb = getMainPanel().getCurrentScrollPane().getVerticalScrollBar();
+        final TreePanel treepanel = getMainPanel().getCurrentTreePanel();
+        treepanel.multiplyUrtFactor( 1.1f );
+        final double x = ( sb.getMaximum() - sb.getMinimum() ) / ( sb.getValue() + ( sb.getVisibleAmount() / 2.0 ) );
+        treepanel.setYdistance( ( treepanel.getYdistance() * factor ) );
+        getMainPanel().adjustJScrollPane();
+        treepanel.resetPreferredSize();
+        getMainPanel().getCurrentScrollPane().getViewport().validate();
+        sb.setValue( ForesterUtil.roundToInt( ( ( sb.getMaximum() - sb.getMinimum() ) / x )
+                - ( sb.getVisibleAmount() / 2.0 ) ) );
+        treepanel.resetPreferredSize();
+        treepanel.updateOvSizes();
+    }
+
+    void zoomOutX( final float factor, final float x_correction_factor ) {
+        final TreePanel treepanel = getMainPanel().getCurrentTreePanel();
+        treepanel.multiplyUrtFactor( 1f );
+        if ( ( treepanel.getXdistance() * factor ) > 0.0 ) {
+            final JScrollBar sb = getMainPanel().getCurrentScrollPane().getHorizontalScrollBar();
+            if ( ( treepanel.getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR )
+                    || ( treepanel.getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
+                    || isDrawPhylogram( getMainPanel().getCurrentTabIndex() )
+                    || ( getOptions().getCladogramType() == CLADOGRAM_TYPE.NON_LINED_UP ) ) {
+                getMainPanel().adjustJScrollPane();
+                treepanel.resetPreferredSize();
+                getMainPanel().getCurrentScrollPane().getViewport().validate();
+                final double x = ( sb.getMaximum() - sb.getMinimum() )
+                        / ( sb.getValue() + ( sb.getVisibleAmount() / 2.0 ) );
+                treepanel.setXdistance( ( treepanel.getXdistance() * factor ) );
+                treepanel.setXcorrectionFactor( ( treepanel.getXcorrectionFactor() * x_correction_factor ) );
+                getMainPanel().adjustJScrollPane();
+                treepanel.resetPreferredSize();
+                getMainPanel().getCurrentScrollPane().getViewport().validate();
+                sb.setValue( ForesterUtil.roundToInt( ( ( sb.getMaximum() - sb.getMinimum() ) / x )
+                        - ( sb.getVisibleAmount() / 2.0 ) ) );
+            }
+            else {
+                final int x = sb.getMaximum() - sb.getMinimum() - sb.getVisibleAmount() - sb.getValue();
+                treepanel.setXdistance( treepanel.getXdistance() * factor );
+                treepanel.setXcorrectionFactor( treepanel.getXcorrectionFactor() * x_correction_factor );
+                if ( x > 0 ) {
+                    getMainPanel().adjustJScrollPane();
+                    treepanel.resetPreferredSize();
+                    getMainPanel().getCurrentScrollPane().getViewport().validate();
+                    sb.setValue( sb.getMaximum() - sb.getMinimum() - x - sb.getVisibleAmount() );
+                }
+            }
+            treepanel.resetPreferredSize();
+            treepanel.updateOvSizes();
+        }
+    }
+
+    void zoomOutY( final float factor ) {
+        final TreePanel treepanel = getMainPanel().getCurrentTreePanel();
+        treepanel.multiplyUrtFactor( 0.9f );
+        if ( ( treepanel.getYdistance() * factor ) > 0.0 ) {
+            final JScrollBar sb = getMainPanel().getCurrentScrollPane().getVerticalScrollBar();
+            final double x = ( sb.getMaximum() - sb.getMinimum() ) / ( sb.getValue() + ( sb.getVisibleAmount() / 2.0 ) );
+            treepanel.setYdistance( ( treepanel.getYdistance() * factor ) );
+            getMainPanel().adjustJScrollPane();
+            treepanel.resetPreferredSize();
+            getMainPanel().getCurrentScrollPane().getViewport().validate();
+            sb.setValue( ForesterUtil.roundToInt( ( ( sb.getMaximum() - sb.getMinimum() ) / x )
+                    - ( sb.getVisibleAmount() / 2.0 ) ) );
+            treepanel.resetPreferredSize();
+            treepanel.updateOvSizes();
+        }
+    }
+
+    static JLabel customizeLabel( final JLabel label, final Configuration configuration ) {
+        label.setFont( ControlPanel.jcb_bold_font );
+        if ( !configuration.isUseNativeUI() ) {
+            label.setForeground( configuration.getGuiCheckboxTextColor() );
+            label.setBackground( configuration.getGuiBackgroundColor() );
+        }
+        return label;
+    }
+
+    enum NodeClickAction {
+        SHOW_DATA,
+        COLLAPSE,
+        REROOT,
+        SUBTREE,
+        SWAP,
+        COLOR_SUBTREE,
+        OPEN_TAX_WEB,
+        OPEN_SEQ_WEB,
+        CUT_SUBTREE,
+        COPY_SUBTREE,
+        DELETE_NODE_OR_SUBTREE,
+        PASTE_SUBTREE,
+        ADD_NEW_NODE,
+        EDIT_NODE_DATA,
+        BLAST;
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/FontChooser.java b/forester/java/src/org/forester/archaeopteryx/FontChooser.java
new file mode 100644 (file)
index 0000000..d319fa1
--- /dev/null
@@ -0,0 +1,297 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// The FontChooser class is in the Public Domain, the code may be used
+// for any purpose. It is provided as is with no warranty.
+//
+// The FontChooser class is based on the JFontChooser class written
+// by: James Bardsley (torasin@torasin.com)
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+public class FontChooser extends JDialog implements ActionListener, ListSelectionListener {
+
+    private static final String   BOLD_ITALIC       = "Bold Italic";
+    private static final String   ITALIC            = "Italic";
+    private static final String   BOLD              = "Bold";
+    private static final String   REGULAR           = "Regular";
+    private static final String   DEFAULT_FONT_NAME = "Sans";
+    public static final long      serialVersionUID  = 62256323L;
+    private static final String[] STYLE             = { REGULAR, BOLD, ITALIC, BOLD_ITALIC };
+    private static final String[] SIZE              = { "3", "4", "6", "8", "10", "12", "14", "16", "18", "20", "22",
+            "24", "26", "28", "36", "72"           };
+    private static final int      OK_OPTION         = 1;
+    private static final int      CANCEL_OPTION     = 2;
+    private Font                  _font;
+    private int                   _option;
+    private String                _type;
+    private int                   _style;
+    private int                   _size;
+    private final JList           _font_list        = new JList( Util.getAvailableFontFamiliesSorted() );
+    private final JList           _style_list       = new JList( STYLE );
+    private final JList           _size_list        = new JList( SIZE );
+    private final JTextField      _fonts_tf         = new JTextField();
+    private final JTextField      _style_tf         = new JTextField();
+    private final JTextField      _size_tf          = new JTextField();
+    private final JLabel          _fonts_label      = new JLabel( "Font:" );
+    private final JLabel          _style_label      = new JLabel( "Style:" );
+    private final JLabel          _size_label       = new JLabel( "Size:" );
+    private final JScrollPane     _font_jsp         = new JScrollPane( _font_list );
+    private final JScrollPane     _style_jsp        = new JScrollPane( _style_list );
+    private final JScrollPane     _size_jsp         = new JScrollPane( _size_list );
+    private final JButton         _ok_button        = new JButton( "OK" );
+    private final JButton         _cancel_button    = new JButton( "Cancel" );
+    private final JTextField      _test_tf          = new JTextField( "AaBbZz012" );
+
+    public FontChooser() {
+        this( new Font( DEFAULT_FONT_NAME, Font.PLAIN, 12 ) );
+    }
+
+    public FontChooser( final Font font ) {
+        final Container container = getContentPane();
+        final JPanel panel = new JPanel();
+        final TitledBorder panel_border = new TitledBorder( "Demo" );
+        _font = font;
+        _type = _font.getFontName();
+        _style = _font.getStyle();
+        _size = _font.getSize();
+        _font_list.setSelectionMode( 0 );
+        _style_list.setSelectionMode( 0 );
+        _size_list.setSelectionMode( 0 );
+        _font_jsp.setHorizontalScrollBarPolicy( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
+        _style_jsp.setHorizontalScrollBarPolicy( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
+        _size_jsp.setHorizontalScrollBarPolicy( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER );
+        panel.setBorder( panel_border );
+        _fonts_tf.setBounds( 8, 32, 121, 20 );
+        _font_jsp.setBounds( 8, 56, 121, 82 );
+        _style_tf.setBounds( 136, 32, 121, 20 );
+        _style_jsp.setBounds( 136, 56, 121, 82 );
+        _size_tf.setBounds( 264, 32, 41, 20 );
+        _size_jsp.setBounds( 264, 56, 41, 82 );
+        _ok_button.setBounds( 320, 8, 89, 17 );
+        _cancel_button.setBounds( 320, 32, 89, 17 );
+        panel.setBounds( 320, 64, 89, 73 );
+        container.add( _fonts_label );
+        container.add( _fonts_tf );
+        container.add( _font_jsp );
+        container.add( _style_label );
+        container.add( _style_tf );
+        container.add( _style_jsp );
+        container.add( _size_label );
+        container.add( _size_tf );
+        container.add( _size_jsp );
+        container.add( _ok_button );
+        container.add( _cancel_button );
+        container.add( panel );
+        _test_tf.setBounds( 8, 25, 73, 30 );
+        panel.add( _test_tf );
+        container.setLayout( null );
+        panel.setLayout( null );
+        setSize( 424, 177 );
+        setResizable( false );
+        setModal( true );
+        _fonts_tf.addActionListener( this );
+        _size_tf.addActionListener( this );
+        _style_tf.addActionListener( this );
+        _cancel_button.addActionListener( this );
+        _ok_button.addActionListener( this );
+        _font_list.addListSelectionListener( this );
+        _style_list.addListSelectionListener( this );
+        _size_list.addListSelectionListener( this );
+    }
+
+    public FontChooser( final String font_name, final int font_style, final int size ) {
+        this( new Font( font_name, font_style, size ) );
+    }
+
+    public void actionPerformed( final ActionEvent e ) {
+        if ( e.getSource() == _fonts_tf ) {
+            boolean found = false;
+            _type = _fonts_tf.getText();
+            for( int i = 0; i < _font_list.getModel().getSize(); i++ ) {
+                if ( ( ( String ) _font_list.getModel().getElementAt( i ) ).startsWith( _fonts_tf.getText().trim() ) ) {
+                    _font_list.setSelectedIndex( i );
+                    setScrollPos( _font_jsp, _font_list, i );
+                    found = true;
+                    break;
+                }
+            }
+            if ( !found ) {
+                _font_list.clearSelection();
+            }
+            else {
+                _test_tf.setFont( new Font( _type, _style, _size ) );
+            }
+        }
+        else if ( e.getSource() == _size_tf ) {
+            boolean found = false;
+            parseSize();
+            _test_tf.setFont( new Font( _type, _style, _size ) );
+            for( int i = 0; i < _size_list.getModel().getSize(); i++ ) {
+                if ( _size_tf.getText().trim().equals( _size_list.getModel().getElementAt( i ) ) ) {
+                    _size_list.setSelectedIndex( i );
+                    setScrollPos( _size_jsp, _size_list, i );
+                    found = true;
+                    break;
+                }
+            }
+            if ( !found ) {
+                _size_list.clearSelection();
+            }
+        }
+        else if ( e.getSource() == _style_tf ) {
+            if ( _style_tf.getText().equals( REGULAR ) ) {
+                _style = Font.PLAIN;
+            }
+            else if ( _style_tf.getText().equals( BOLD ) ) {
+                _style = Font.BOLD;
+            }
+            else if ( _style_tf.getText().equals( ITALIC ) ) {
+                _style = Font.ITALIC;
+            }
+            else if ( _style_tf.getText().equals( BOLD_ITALIC ) ) {
+                _style = Font.BOLD & Font.ITALIC;
+            }
+            _style_list.setSelectedIndex( _style );
+            _test_tf.setFont( new Font( _type, _style, _size ) );
+        }
+        else if ( e.getSource() == _ok_button ) {
+            parseSize();
+            _option = OK_OPTION;
+            _font = new Font( _type, _style, _size );
+            setVisible( false );
+        }
+        else if ( e.getSource() == _cancel_button ) {
+            _option = CANCEL_OPTION;
+            setVisible( false );
+        }
+    }
+
+    @Override
+    public Font getFont() {
+        return _font;
+    }
+
+    public String getFontName() {
+        return _font.getFontName();
+    }
+
+    public int getFontSize() {
+        return _font.getSize();
+    }
+
+    public int getFontStyle() {
+        return _font.getStyle();
+    }
+
+    private void parseSize() {
+        try {
+            _size = ( Integer.parseInt( _size_tf.getText().trim() ) );
+        }
+        catch ( final Exception ex ) {
+            // Ignore.
+        }
+        if ( _size < 1 ) {
+            _size = 1;
+        }
+    }
+
+    @Override
+    public void setFont( final Font font ) {
+        _font = font;
+    }
+
+    private void setScrollPos( final JScrollPane sp, final JList list, final int index ) {
+        final int unit_size = sp.getVerticalScrollBar().getMaximum() / list.getModel().getSize();
+        sp.getVerticalScrollBar().setValue( ( index - 2 ) * unit_size );
+    }
+
+    public int showDialog( final Component parent, final String title ) {
+        boolean found = false;
+        _option = CANCEL_OPTION;
+        setTitle( title );
+        _test_tf.setFont( new Font( _type, _style, _size ) );
+        for( int i = 0; i < _font_list.getModel().getSize(); i++ ) {
+            _font_list.setSelectedIndex( i );
+            if ( _font.getFamily().equals( _font_list.getSelectedValue() ) ) {
+                found = true;
+                setScrollPos( _font_jsp, _font_list, i );
+                break;
+            }
+        }
+        if ( !found ) {
+            _font_list.clearSelection();
+        }
+        _style_list.setSelectedIndex( _font.getStyle() );
+        found = false;
+        for( int i = 0; i < _size_list.getModel().getSize(); i++ ) {
+            _size_list.setSelectedIndex( i );
+            if ( _font.getSize() <= Integer.parseInt( ( String ) _size_list.getSelectedValue() ) ) {
+                found = true;
+                setScrollPos( _size_jsp, _size_list, i );
+                break;
+            }
+        }
+        if ( !found ) {
+            _size_list.clearSelection();
+        }
+        setLocationRelativeTo( parent );
+        setVisible( true );
+        return _option;
+    }
+
+    public void valueChanged( final ListSelectionEvent e ) {
+        if ( e.getSource() == _font_list ) {
+            if ( _font_list.getSelectedValue() != null ) {
+                _fonts_tf.setText( ( ( String ) ( _font_list.getSelectedValue() ) ) );
+            }
+            _type = _fonts_tf.getText();
+            _test_tf.setFont( new Font( _type, _style, _size ) );
+        }
+        else if ( e.getSource() == _style_list ) {
+            _style_tf.setText( ( ( String ) ( _style_list.getSelectedValue() ) ) );
+            if ( _style_tf.getText().equals( REGULAR ) ) {
+                _style = 0;
+            }
+            else if ( _style_tf.getText().equals( BOLD ) ) {
+                _style = 1;
+            }
+            else if ( _style_tf.getText().equals( ITALIC ) ) {
+                _style = 2;
+            }
+            else if ( _style_tf.getText().equals( BOLD_ITALIC ) ) {
+                _style = 3;
+            }
+            _test_tf.setFont( new Font( _type, _style, _size ) );
+        }
+        else if ( e.getSource() == _size_list ) {
+            if ( _size_list.getSelectedValue() != null ) {
+                _size_tf.setText( ( ( String ) ( _size_list.getSelectedValue() ) ) );
+            }
+            _size = ( Integer.parseInt( _size_tf.getText().trim() ) );
+            _test_tf.setFont( new Font( _type, _style, _size ) );
+        }
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/ImageLoader.java b/forester/java/src/org/forester/archaeopteryx/ImageLoader.java
new file mode 100644 (file)
index 0000000..f9d5d89
--- /dev/null
@@ -0,0 +1,114 @@
+// $Id:
+// forester -- software libraries and applications
+// for genomics and evolutionary biology research.
+//
+// Copyright (C) 2010 Christian M Zmasek
+// Copyright (C) 2010 Sanford-Burnham Medical Research Institute
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.Taxonomy;
+import org.forester.phylogeny.data.Uri;
+import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
+
+public class ImageLoader implements Runnable {
+
+    private final TreePanel            _tp;
+    private static final BufferedImage PLACEHOLDER = new BufferedImage( 1, 1, BufferedImage.TYPE_INT_RGB );
+
+    public ImageLoader( final TreePanel tp ) {
+        _tp = tp;
+    }
+
+    private void load() {
+        Hashtable<String, BufferedImage> image_map = null;
+        if ( _tp.getImageMap() != null ) {
+            image_map = _tp.getImageMap();
+        }
+        else {
+            image_map = new Hashtable<String, BufferedImage>();
+            _tp.setImageMap( image_map );
+        }
+        // ImageIO.setUseCache( false );
+        for( final PhylogenyNodeIterator it = _tp.getPhylogeny().iteratorPreorder(); it.hasNext(); ) {
+            final PhylogenyNode node = it.next();
+            if ( node.getNodeData().isHasTaxonomy() && ( node.getNodeData().getTaxonomy().getUris() != null )
+                    && !node.getNodeData().getTaxonomy().getUris().isEmpty() ) {
+                final List<Uri> us = new ArrayList<Uri>();
+                for( final Taxonomy t : node.getNodeData().getTaxonomies() ) {
+                    for( final Uri uri : t.getUris() ) {
+                        us.add( uri );
+                    }
+                }
+                for( final Uri uri : us ) {
+                    if ( uri != null ) {
+                        final String type = uri.getType().toLowerCase();
+                        final String uri_str = uri.getValue().toString().toLowerCase();
+                        if ( ( !image_map.containsKey( uri_str ) )
+                                && ( type.equals( "image" ) || type.equals( "img" ) || type.equals( "photo" )
+                                        || type.equals( "picture" ) || uri_str.endsWith( ".jpg" )
+                                        || uri_str.endsWith( ".jpeg" ) || uri_str.endsWith( ".png" )
+                                        || uri_str.endsWith( ".gif" ) || uri_str.endsWith( ".bmp" ) ) ) {
+                            image_map.put( uri_str, PLACEHOLDER );
+                            BufferedImage bi = null;
+                            if ( !Constants.__RELEASE && !Constants.__SNAPSHOT_RELEASE ) {
+                                System.out.println( "accessing:" + uri );
+                            }
+                            try {
+                                bi = ImageIO.read( uri.getValue().toURL() );
+                            }
+                            catch ( final MalformedURLException e ) {
+                                Util.printWarningMessage( Constants.PRG_NAME, "\"" + uri.getValue()
+                                        + "\": Malformed URL Exception: " + e.getLocalizedMessage() );
+                            }
+                            catch ( final IOException e ) {
+                                Util.printWarningMessage( Constants.PRG_NAME, "\"" + uri.getValue()
+                                        + "\": IO Exception: " + e.getLocalizedMessage() );
+                            }
+                            if ( bi != null ) {
+                                image_map.put( uri_str, bi );
+                                _tp.repaint();
+                            }
+                            else {
+                                image_map.remove( uri_str );
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void run() {
+        load();
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/MainFrame.java b/forester/java/src/org/forester/archaeopteryx/MainFrame.java
new file mode 100644 (file)
index 0000000..48c52e8
--- /dev/null
@@ -0,0 +1,1260 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2010 Christian M. Zmasek
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.Container;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.swing.JApplet;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JRadioButtonMenuItem;
+
+import org.forester.archaeopteryx.Options.CLADOGRAM_TYPE;
+import org.forester.archaeopteryx.Options.NODE_LABEL_DIRECTION;
+import org.forester.archaeopteryx.Options.PHYLOGENY_GRAPHICS_TYPE;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.util.ForesterConstants;
+import org.forester.util.ForesterUtil;
+
+public abstract class MainFrame extends JFrame implements ActionListener {
+
+    static final String       USE_MOUSEWHEEL_SHIFT_TO_ROTATE     = "In this display type, use mousewheel + Shift to rotate [or A and S]";
+    static final String       PHYLOXML_REF_TOOL_TIP              = Constants.PHYLOXML_REFERENCE;                                                                                                                                       //TODO //FIXME
+    static final String       APTX_REF_TOOL_TIP                  = Constants.APTX_REFERENCE;
+    private static final long serialVersionUID                   = 3655000897845508358L;
+    final static Font         menu_font                          = new Font( Configuration.getDefaultFontFamilyName(),
+                                                                             Font.PLAIN,
+                                                                             10 );
+    static final String       TYPE_MENU_HEADER                   = "Type";
+    static final String       RECTANGULAR_TYPE_CBMI_LABEL        = "Rectangular";
+    static final String       EURO_TYPE_CBMI_LABEL               = "Euro Type";
+    static final String       CURVED_TYPE_CBMI_LABEL             = "Curved";
+    static final String       TRIANGULAR_TYPE_CBMI_LABEL         = "Triangular";
+    static final String       CONVEX_TYPE_CBMI_LABEL             = "Convex";
+    static final String       ROUNDED_TYPE_CBMI_LABEL            = "Rounded";
+    static final String       UNROOTED_TYPE_CBMI_LABEL           = "Unrooted (alpha)";                                                                                                                                                 //TODO
+    static final String       CIRCULAR_TYPE_CBMI_LABEL           = "Circular (alpha)";                                                                                                                                                 //TODO
+    static final String       OPTIONS_HEADER                     = "Options";
+    static final String       SEARCH_SUBHEADER                   = "Search:";
+    static final String       DISPLAY_SUBHEADER                  = "Display:";
+    static final String       SEARCH_TERMS_ONLY_LABEL            = "Match Complete Terms Only";
+    static final String       SEARCH_CASE_SENSITIVE_LABEL        = "Case Sensitive";
+    static final String       INVERSE_SEARCH_RESULT_LABEL        = "Negate Result";
+    static final String       DISPLAY_BRANCH_LENGTH_VALUES_LABEL = "Display Branch Length Values";
+    static final String       DISPLAY_SCALE_LABEL                = "Display Scale";
+    static final String       NON_LINED_UP_CLADOGRAMS_LABEL      = "Non-Lined Up Cladograms";
+    static final String       UNIFORM_CLADOGRAMS_LABEL           = "Total Node Sum Dependent Cladograms";
+    static final String       LABEL_DIRECTION_LABEL              = "Radial Labels";
+    static final String       LABEL_DIRECTION_TIP                = "To use radial node labels in radial and unrooted display types";
+    static final String       SCREEN_ANTIALIAS_LABEL             = "Antialias";
+    static final String       COLOR_LABELS_LABEL                 = "Colorize Labels Same as Parent Branch";
+    static final String       BG_GRAD_LABEL                      = "Background Color Gradient";
+    static final String       DISPLAY_NODE_BOXES_LABEL           = "Display Node Boxes";
+    static final String       SHOW_OVERVIEW_LABEL                = "Show Overview";
+    static final String       FONT_SIZE_MENU_LABEL               = "Font Size";
+    static final String       NONUNIFORM_CLADOGRAMS_LABEL        = "External Node Sum Dependent Cladograms";
+    static final String       SHOW_DOMAIN_LABELS_LABEL           = "Show Domain Labels";
+    static final String       COLOR_LABELS_TIP                   = "To use parent branch colors for node labels as well, need to turn off taxonomy dependent colorization and turn on branch colorization for this to become apparent";
+    static final String       ABBREV_SN_LABEL                    = "Abbreviate Scientific Taxonomic Names";
+    JMenuBar                  _jmenubar;
+    JMenu                     _file_jmenu;
+    JMenu                     _tools_menu;
+    JMenu                     _view_jmenu;
+    JMenu                     _options_jmenu;
+    JMenu                     _font_size_menu;
+    JMenu                     _help_jmenu;
+    JMenuItem[]               _load_phylogeny_from_webservice_menu_items;
+    // file menu:
+    JMenuItem                 _open_item;
+    JMenuItem                 _open_url_item;
+    JMenuItem                 _save_item;
+    JMenuItem                 _save_all_item;
+    JMenuItem                 _close_item;
+    JMenuItem                 _exit_item;
+    JMenuItem                 _new_item;
+    // tools menu:
+    JMenuItem                 _midpoint_root_item;
+    JMenuItem                 _taxcolor_item;
+    JMenuItem                 _confcolor_item;
+    JMenuItem                 _infer_common_sn_names_item;
+    JMenuItem                 _collapse_species_specific_subtrees;
+    JMenuItem                 _collapse_below_threshold;                                                                                                                                                                               //TODO implememt me
+    JMenuItem                 _obtain_detailed_taxonomic_information_jmi;
+    JMenuItem                 _move_node_names_to_tax_sn_jmi;
+    JMenuItem                 _move_node_names_to_seq_names_jmi;
+    JMenuItem                 _extract_tax_code_from_node_names_jmi;
+    // font size menu:
+    JMenuItem                 _super_tiny_fonts_item;
+    JMenuItem                 _tiny_fonts_item;
+    JMenuItem                 _small_fonts_item;
+    JMenuItem                 _medium_fonts_item;
+    JMenuItem                 _large_fonts_item;
+    // options menu:
+    // _  screen and print
+    JMenuItem                 _choose_font_mi;
+    JMenuItem                 _switch_colors_mi;
+    JCheckBoxMenuItem         _label_direction_cbmi;
+    // _  screen display
+    JCheckBoxMenuItem         _screen_antialias_cbmi;
+    JCheckBoxMenuItem         _background_gradient_cbmi;
+    JCheckBoxMenuItem         _show_node_boxes_cbmi;
+    JRadioButtonMenuItem      _non_lined_up_cladograms_rbmi;
+    JRadioButtonMenuItem      _uniform_cladograms_rbmi;
+    JRadioButtonMenuItem      _ext_node_dependent_cladogram_rbmi;
+    JCheckBoxMenuItem         _show_branch_length_values_cbmi;
+    JCheckBoxMenuItem         _show_scale_cbmi;                                                                                                                                                                                        //TODO fix me
+    JCheckBoxMenuItem         _show_overview_cbmi;
+    JCheckBoxMenuItem         _show_domain_labels;
+    JCheckBoxMenuItem         _abbreviate_scientific_names;
+    JCheckBoxMenuItem         _color_labels_same_as_parent_branch;
+    JMenuItem                 _overview_placment_mi;
+    JMenuItem                 _choose_minimal_confidence_mi;
+    // _  print
+    JCheckBoxMenuItem         _graphics_export_visible_only_cbmi;
+    JCheckBoxMenuItem         _antialias_print_cbmi;
+    JCheckBoxMenuItem         _print_black_and_white_cbmi;
+    JCheckBoxMenuItem         _print_using_actual_size_cbmi;
+    JCheckBoxMenuItem         _graphics_export_using_actual_size_cbmi;
+    JMenuItem                 _print_size_mi;
+    JMenuItem                 _choose_pdf_width_mi;
+    // _  parsing
+    JCheckBoxMenuItem         _internal_number_are_confidence_for_nh_parsing_cbmi;
+    JCheckBoxMenuItem         _extract_pfam_style_tax_codes_cbmi;
+    JCheckBoxMenuItem         _replace_underscores_cbmi;
+    // _  search
+    JCheckBoxMenuItem         _search_case_senstive_cbmi;
+    JCheckBoxMenuItem         _search_whole_words_only_cbmi;
+    JCheckBoxMenuItem         _inverse_search_result_cbmi;
+    // type menu:
+    JMenu                     _type_menu;
+    JCheckBoxMenuItem         _rectangular_type_cbmi;
+    JCheckBoxMenuItem         _triangular_type_cbmi;
+    JCheckBoxMenuItem         _curved_type_cbmi;
+    JCheckBoxMenuItem         _convex_type_cbmi;
+    JCheckBoxMenuItem         _euro_type_cbmi;
+    JCheckBoxMenuItem         _rounded_type_cbmi;
+    JCheckBoxMenuItem         _unrooted_type_cbmi;
+    JCheckBoxMenuItem         _circular_type_cbmi;
+    // view as text menu:
+    JMenuItem                 _view_as_NH_item;
+    JMenuItem                 _view_as_NHX_item;
+    JMenuItem                 _view_as_XML_item;
+    JMenuItem                 _view_as_nexus_item;
+    // help menu:
+    JMenuItem                 _about_item;
+    JMenuItem                 _help_item;
+    JMenuItem                 _website_item;
+    JMenuItem                 _phyloxml_website_item;
+    JMenuItem                 _phyloxml_ref_item;
+    JMenuItem                 _aptx_ref_item;
+    // Handy pointers to child components:
+    MainPanel                 _mainpanel;
+    Container                 _contentpane;
+    TextFrame                 _textframe;
+    Configuration             _configuration;
+    JMenuItem                 _remove_branch_color_item;
+    Options                   _options;
+
+    MainFrame() {
+        // Empty constructor.
+    }
+
+    /**
+     * Action performed.
+     */
+    public void actionPerformed( final ActionEvent e ) {
+        final Object o = e.getSource();
+        boolean is_applet = false;
+        JApplet applet = null;
+        if ( getCurrentTreePanel() != null ) {
+            is_applet = getCurrentTreePanel().isApplet();
+            if ( is_applet ) {
+                applet = getCurrentTreePanel().obtainApplet();
+            }
+        }
+        if ( o == _open_url_item ) {
+            readPhylogeniesFromURL();
+        }
+        else if ( o == _exit_item ) {
+            close();
+        }
+        else if ( o == _taxcolor_item ) {
+            taxColor();
+        }
+        else if ( o == _confcolor_item ) {
+            confColor();
+        }
+        else if ( o == _infer_common_sn_names_item ) {
+            if ( isSubtreeDisplayed() ) {
+                return;
+            }
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().inferCommonPartOfScientificNames();
+            }
+        }
+        else if ( o == _collapse_species_specific_subtrees ) {
+            if ( isSubtreeDisplayed() ) {
+                return;
+            }
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().collapseSpeciesSpecificSubtrees();
+            }
+        }
+        else if ( o == _remove_branch_color_item ) {
+            if ( isSubtreeDisplayed() ) {
+                return;
+            }
+            removeBranchColors();
+        }
+        else if ( o == _midpoint_root_item ) {
+            if ( isSubtreeDisplayed() ) {
+                return;
+            }
+            midpointRoot();
+        }
+        else if ( o == _switch_colors_mi ) {
+            switchColors();
+        }
+        else if ( o == _view_as_NH_item ) {
+            viewAsNH();
+        }
+        else if ( o == _view_as_NHX_item ) {
+            viewAsNHX();
+        }
+        else if ( o == _view_as_XML_item ) {
+            viewAsXML();
+        }
+        else if ( o == _view_as_nexus_item ) {
+            viewAsNexus();
+        }
+        else if ( o == _super_tiny_fonts_item ) {
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().setSuperTinyFonts();
+                getCurrentTreePanel().repaint();
+            }
+        }
+        else if ( o == _tiny_fonts_item ) {
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().setTinyFonts();
+                getCurrentTreePanel().repaint();
+            }
+        }
+        else if ( o == _small_fonts_item ) {
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().setSmallFonts();
+                getCurrentTreePanel().repaint();
+            }
+        }
+        else if ( o == _medium_fonts_item ) {
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().setMediumFonts();
+                getCurrentTreePanel().repaint();
+            }
+        }
+        else if ( o == _large_fonts_item ) {
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().setLargeFonts();
+                getCurrentTreePanel().repaint();
+            }
+        }
+        else if ( o == _choose_font_mi ) {
+            chooseFont();
+        }
+        else if ( o == _choose_minimal_confidence_mi ) {
+            chooseMinimalConfidence();
+        }
+        else if ( o == _overview_placment_mi ) {
+            MainFrame.cycleOverview( getOptions(), getCurrentTreePanel() );
+        }
+        else if ( o == _screen_antialias_cbmi ) {
+            updateOptions( getOptions() );
+            updateScreenTextAntialias( getMainPanel().getTreePanels() );
+        }
+        else if ( o == _background_gradient_cbmi ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _show_domain_labels ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _abbreviate_scientific_names ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _color_labels_same_as_parent_branch ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _show_node_boxes_cbmi ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _non_lined_up_cladograms_rbmi ) {
+            updateOptions( getOptions() );
+            showWhole();
+        }
+        else if ( o == _uniform_cladograms_rbmi ) {
+            updateOptions( getOptions() );
+            showWhole();
+        }
+        else if ( o == _ext_node_dependent_cladogram_rbmi ) {
+            updateOptions( getOptions() );
+            showWhole();
+        }
+        else if ( o == _search_case_senstive_cbmi ) {
+            updateOptions( getOptions() );
+            getMainPanel().getControlPanel().search();
+        }
+        else if ( o == _search_whole_words_only_cbmi ) {
+            updateOptions( getOptions() );
+            getMainPanel().getControlPanel().search();
+        }
+        else if ( o == _inverse_search_result_cbmi ) {
+            updateOptions( getOptions() );
+            getMainPanel().getControlPanel().search();
+        }
+        else if ( o == _show_scale_cbmi ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _show_branch_length_values_cbmi ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _label_direction_cbmi ) {
+            updateOptions( getOptions() );
+        }
+        else if ( o == _show_overview_cbmi ) {
+            updateOptions( getOptions() );
+            if ( getCurrentTreePanel() != null ) {
+                getCurrentTreePanel().updateOvSizes();
+            }
+        }
+        else if ( ( o == _rectangular_type_cbmi ) || ( o == _triangular_type_cbmi ) || ( o == _curved_type_cbmi )
+                || ( o == _convex_type_cbmi ) || ( o == _euro_type_cbmi ) || ( o == _rounded_type_cbmi )
+                || ( o == _unrooted_type_cbmi ) || ( o == _circular_type_cbmi ) ) {
+            typeChanged( o );
+        }
+        else if ( o == _about_item ) {
+            about();
+        }
+        else if ( o == _help_item ) {
+            help( getConfiguration().getWebLinks() );
+        }
+        else if ( o == _website_item ) {
+            try {
+                Util.openWebsite( Constants.APTX_WEB_SITE, is_applet, applet );
+            }
+            catch ( final IOException e1 ) {
+                ForesterUtil.printErrorMessage( Constants.PRG_NAME, e1.toString() );
+            }
+        }
+        else if ( o == _phyloxml_website_item ) {
+            try {
+                Util.openWebsite( Constants.PHYLOXML_WEB_SITE, is_applet, applet );
+            }
+            catch ( final IOException e1 ) {
+                ForesterUtil.printErrorMessage( Constants.PRG_NAME, e1.toString() );
+            }
+        }
+        else if ( o == _aptx_ref_item ) {
+            try {
+                Util.openWebsite( Constants.APTX_REFERENCE_URL, is_applet, applet );
+            }
+            catch ( final IOException e1 ) {
+                ForesterUtil.printErrorMessage( Constants.PRG_NAME, e1.toString() );
+            }
+        }
+        else if ( o == _phyloxml_ref_item ) {
+            try {
+                Util.openWebsite( Constants.PHYLOXML_REFERENCE_URL, is_applet, applet );
+            }
+            catch ( final IOException e1 ) {
+                ForesterUtil.printErrorMessage( Constants.PRG_NAME, e1.toString() );
+            }
+        }
+        else {
+            if ( _load_phylogeny_from_webservice_menu_items != null ) {
+                for( int i = 0; i < _load_phylogeny_from_webservice_menu_items.length; ++i ) {
+                    if ( o == _load_phylogeny_from_webservice_menu_items[ i ] ) {
+                        readPhylogeniesFromWebservice( i );
+                    }
+                }
+            }
+        }
+        _contentpane.repaint();
+    }
+
+    boolean isSubtreeDisplayed() {
+        if ( getCurrentTreePanel().isCurrentTreeIsSubtree() ) {
+            JOptionPane
+                    .showMessageDialog( this,
+                                        "This operation can only be performed on a complete tree, not on the currently displayed sub-tree only.",
+                                        "Operation can not be exectuted on a sub-tree",
+                                        JOptionPane.WARNING_MESSAGE );
+            return true;
+        }
+        return false;
+    }
+
+    void activateSaveAllIfNeeded() {
+        if ( ( getMainPanel().getTabbedPane() != null ) && ( getMainPanel().getTabbedPane().getTabCount() > 1 ) ) {
+            _save_all_item.setEnabled( true );
+        }
+        else {
+            _save_all_item.setEnabled( false );
+        }
+    }
+
+    void buildFileMenu() {
+        _file_jmenu = createMenu( "File", getConfiguration() );
+        _file_jmenu.add( _open_url_item = new JMenuItem( "Read tree from URL/webservice..." ) );
+        _file_jmenu.addSeparator();
+        _file_jmenu.add( _exit_item = new JMenuItem( "Exit" ) );
+        customizeJMenuItem( _open_url_item );
+        customizeJMenuItem( _exit_item );
+        _jmenubar.add( _file_jmenu );
+    }
+
+    void buildFontSizeMenu() {
+        _font_size_menu = createMenu( FONT_SIZE_MENU_LABEL, getConfiguration() );
+        _font_size_menu.add( _super_tiny_fonts_item = new JMenuItem( "Super Tiny Fonts" ) );
+        _font_size_menu.add( _tiny_fonts_item = new JMenuItem( "Tiny Fonts" ) );
+        _font_size_menu.add( _small_fonts_item = new JMenuItem( "Small Fonts" ) );
+        _font_size_menu.add( _medium_fonts_item = new JMenuItem( "Medium Fonts" ) );
+        _font_size_menu.add( _large_fonts_item = new JMenuItem( "Large Fonts" ) );
+        customizeJMenuItem( _super_tiny_fonts_item );
+        customizeJMenuItem( _tiny_fonts_item );
+        customizeJMenuItem( _small_fonts_item );
+        customizeJMenuItem( _medium_fonts_item );
+        customizeJMenuItem( _large_fonts_item );
+        _jmenubar.add( _font_size_menu );
+    }
+
+    void buildHelpMenu() {
+        _help_jmenu = createMenu( "Help", getConfiguration() );
+        _help_jmenu.add( _help_item = new JMenuItem( "Help" ) );
+        _help_jmenu.add( _website_item = new JMenuItem( "Archaeopteryx Home" ) );
+        _aptx_ref_item = new JMenuItem( "Archaeopteryx Reference" );
+        _help_jmenu.add( _phyloxml_website_item = new JMenuItem( "phyloXML Home" ) );
+        _help_jmenu.add( _phyloxml_ref_item = new JMenuItem( "phyloXML Reference" ) );
+        _help_jmenu.addSeparator();
+        _help_jmenu.add( _about_item = new JMenuItem( "About" ) );
+        customizeJMenuItem( _help_item );
+        customizeJMenuItem( _website_item );
+        customizeJMenuItem( _phyloxml_website_item );
+        customizeJMenuItem( _aptx_ref_item );
+        customizeJMenuItem( _phyloxml_ref_item );
+        customizeJMenuItem( _about_item );
+        _phyloxml_ref_item.setToolTipText( PHYLOXML_REF_TOOL_TIP );
+        _aptx_ref_item.setToolTipText( APTX_REF_TOOL_TIP );
+        _jmenubar.add( _help_jmenu );
+    }
+
+    void buildTypeMenu() {
+        _type_menu = createMenu( TYPE_MENU_HEADER, getConfiguration() );
+        _type_menu.add( _rectangular_type_cbmi = new JCheckBoxMenuItem( MainFrame.RECTANGULAR_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _euro_type_cbmi = new JCheckBoxMenuItem( MainFrame.EURO_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _rounded_type_cbmi = new JCheckBoxMenuItem( MainFrame.ROUNDED_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _curved_type_cbmi = new JCheckBoxMenuItem( MainFrame.CURVED_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _triangular_type_cbmi = new JCheckBoxMenuItem( MainFrame.TRIANGULAR_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _convex_type_cbmi = new JCheckBoxMenuItem( MainFrame.CONVEX_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _unrooted_type_cbmi = new JCheckBoxMenuItem( MainFrame.UNROOTED_TYPE_CBMI_LABEL ) );
+        _type_menu.add( _circular_type_cbmi = new JCheckBoxMenuItem( MainFrame.CIRCULAR_TYPE_CBMI_LABEL ) );
+        customizeCheckBoxMenuItem( _rectangular_type_cbmi, false );
+        customizeCheckBoxMenuItem( _triangular_type_cbmi, false );
+        customizeCheckBoxMenuItem( _euro_type_cbmi, false );
+        customizeCheckBoxMenuItem( _rounded_type_cbmi, false );
+        customizeCheckBoxMenuItem( _curved_type_cbmi, false );
+        customizeCheckBoxMenuItem( _convex_type_cbmi, false );
+        customizeCheckBoxMenuItem( _unrooted_type_cbmi, false );
+        customizeCheckBoxMenuItem( _circular_type_cbmi, false );
+        _unrooted_type_cbmi.setToolTipText( MainFrame.USE_MOUSEWHEEL_SHIFT_TO_ROTATE );
+        _circular_type_cbmi.setToolTipText( MainFrame.USE_MOUSEWHEEL_SHIFT_TO_ROTATE );
+        initializeTypeMenu( getOptions() );
+        _jmenubar.add( _type_menu );
+    }
+
+    void buildViewMenu() {
+        _view_jmenu = createMenu( "View as Text", getConfiguration() );
+        _view_jmenu.add( _view_as_XML_item = new JMenuItem( "View as phyloXML" ) );
+        _view_jmenu.add( _view_as_NH_item = new JMenuItem( "View as Newick" ) );
+        _view_jmenu.add( _view_as_NHX_item = new JMenuItem( "View as NHX" ) );
+        _view_jmenu.add( _view_as_nexus_item = new JMenuItem( "View as Nexus" ) );
+        customizeJMenuItem( _view_as_NH_item );
+        customizeJMenuItem( _view_as_NHX_item );
+        customizeJMenuItem( _view_as_XML_item );
+        customizeJMenuItem( _view_as_nexus_item );
+        _jmenubar.add( _view_jmenu );
+    }
+
+    private void chooseFont() {
+        final FontChooser fc = new FontChooser();
+        fc.setFont( getMainPanel().getTreeFontSet().getLargeFont() );
+        fc.showDialog( this, "Select the Base Font" );
+        getMainPanel().getTreeFontSet().setBaseFont( fc.getFont() );
+    }
+
+    private void chooseMinimalConfidence() {
+        final String s = ( String ) JOptionPane
+                .showInputDialog( this,
+                                  "Please enter the minimum for confidence values to be displayed.\n"
+                                          + "[current value: " + getOptions().getMinConfidenceValue() + "]\n",
+                                  "Minimal Confidence Value",
+                                  JOptionPane.QUESTION_MESSAGE,
+                                  null,
+                                  null,
+                                  getOptions().getMinConfidenceValue() );
+        if ( !ForesterUtil.isEmpty( s ) ) {
+            boolean success = true;
+            double m = 0.0;
+            final String m_str = s.trim();
+            if ( !ForesterUtil.isEmpty( m_str ) ) {
+                try {
+                    m = Double.parseDouble( m_str );
+                }
+                catch ( final Exception ex ) {
+                    success = false;
+                }
+            }
+            else {
+                success = false;
+            }
+            if ( success && ( m >= 0.0 ) ) {
+                getOptions().setMinConfidenceValue( m );
+            }
+        }
+    }
+
+    void close() {
+        removeTextFrame();
+        if ( _mainpanel != null ) {
+            _mainpanel.terminate();
+        }
+        if ( _contentpane != null ) {
+            _contentpane.removeAll();
+        }
+        setVisible( false );
+        dispose();
+    }
+
+    void confColor() {
+        if ( _mainpanel.getCurrentTreePanel() != null ) {
+            _mainpanel.getCurrentTreePanel().confColor();
+        }
+    }
+
+    void customizeCheckBoxMenuItem( final JCheckBoxMenuItem item, final boolean is_selected ) {
+        if ( item != null ) {
+            item.setFont( MainFrame.menu_font );
+            if ( !getConfiguration().isUseNativeUI() ) {
+                item.setBackground( getConfiguration().getGuiMenuBackgroundColor() );
+                item.setForeground( getConfiguration().getGuiMenuTextColor() );
+            }
+            item.setSelected( is_selected );
+            item.addActionListener( this );
+        }
+    }
+
+    void customizeJMenuItem( final JMenuItem jmi ) {
+        if ( jmi != null ) {
+            jmi.setFont( MainFrame.menu_font );
+            if ( !getConfiguration().isUseNativeUI() ) {
+                jmi.setBackground( getConfiguration().getGuiMenuBackgroundColor() );
+                jmi.setForeground( getConfiguration().getGuiMenuTextColor() );
+            }
+            jmi.addActionListener( this );
+        }
+    }
+
+    void customizeRadioButtonMenuItem( final JRadioButtonMenuItem item, final boolean is_selected ) {
+        if ( item != null ) {
+            item.setFont( MainFrame.menu_font );
+            if ( !getConfiguration().isUseNativeUI() ) {
+                item.setBackground( getConfiguration().getGuiMenuBackgroundColor() );
+                item.setForeground( getConfiguration().getGuiMenuTextColor() );
+            }
+            item.setSelected( is_selected );
+            item.addActionListener( this );
+        }
+    }
+
+    void exceptionOccuredDuringOpenFile( final Exception e ) {
+        try {
+            _mainpanel.getCurrentTreePanel().setArrowCursor();
+        }
+        catch ( final Exception ex ) {
+            // Do nothing.
+        }
+        JOptionPane.showMessageDialog( this,
+                                       ForesterUtil.wordWrap( e.getLocalizedMessage(), 80 ),
+                                       "Error during File|Open",
+                                       JOptionPane.ERROR_MESSAGE );
+    }
+
+    void exceptionOccuredDuringSaveAs( final Exception e ) {
+        try {
+            _mainpanel.getCurrentTreePanel().setArrowCursor();
+        }
+        catch ( final Exception ex ) {
+            // Do nothing.
+        }
+        JOptionPane.showMessageDialog( this, "Exception" + e, "Error during File|SaveAs", JOptionPane.ERROR_MESSAGE );
+    }
+
+    boolean GAndSDoHaveMoreThanOneSpeciesInComman( final Phylogeny gene_tree ) {
+        if ( ( gene_tree == null ) || gene_tree.isEmpty() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Gene tree and species tree have no species in common.",
+                                           "Error during SDI",
+                                           JOptionPane.ERROR_MESSAGE );
+            return false;
+        }
+        else if ( gene_tree.getNumberOfExternalNodes() < 2 ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Gene tree and species tree have only one species in common.",
+                                           "Error during SDI",
+                                           JOptionPane.ERROR_MESSAGE );
+            return false;
+        }
+        else {
+            return true;
+        }
+    }
+
+    Configuration getConfiguration() {
+        return _configuration;
+    }
+
+    TreePanel getCurrentTreePanel() {
+        return getMainPanel().getCurrentTreePanel();
+    }
+
+    JMenu getHelpMenu() {
+        return _help_jmenu;
+    }
+
+    JCheckBoxMenuItem getlabelDirectionCbmi() {
+        return _label_direction_cbmi;
+    }
+
+    MainPanel getMainPanel() {
+        return _mainpanel;
+    }
+
+    JMenuBar getMenuBarOfMainFrame() {
+        return _jmenubar;
+    }
+
+    Options getOptions() {
+        return _options;
+    }
+
+    void initializeTypeMenu( final Options options ) {
+        setTypeMenuToAllUnselected();
+        switch ( options.getPhylogenyGraphicsType() ) {
+            case CONVEX:
+                _convex_type_cbmi.setSelected( true );
+                break;
+            case CURVED:
+                _curved_type_cbmi.setSelected( true );
+                break;
+            case EURO_STYLE:
+                _euro_type_cbmi.setSelected( true );
+                break;
+            case ROUNDED:
+                _rounded_type_cbmi.setSelected( true );
+                break;
+            case TRIANGULAR:
+                _triangular_type_cbmi.setSelected( true );
+                break;
+            case UNROOTED:
+                _unrooted_type_cbmi.setSelected( true );
+                break;
+            case CIRCULAR:
+                _circular_type_cbmi.setSelected( true );
+                break;
+            default:
+                _rectangular_type_cbmi.setSelected( true );
+                break;
+        }
+    }
+
+    void midpointRoot() {
+        if ( _mainpanel.getCurrentTreePanel() != null ) {
+            _mainpanel.getCurrentTreePanel().midpointRoot();
+        }
+    }
+
+    abstract void readPhylogeniesFromURL();
+
+    void readPhylogeniesFromWebservice( final int i ) {
+        final UrlTreeReader reader = new UrlTreeReader( this, i );
+        new Thread( reader ).start();
+    }
+
+    private void removeBranchColors() {
+        if ( getMainPanel().getCurrentPhylogeny() != null ) {
+            Util.removeBranchColors( getMainPanel().getCurrentPhylogeny() );
+        }
+    }
+
+    void removeTextFrame() {
+        if ( _textframe != null ) {
+            _textframe.close();
+            _textframe = null;
+        }
+    }
+
+    void setConfiguration( final Configuration configuration ) {
+        _configuration = configuration;
+    }
+
+    void setOptions( final Options options ) {
+        _options = options;
+    }
+
+    void setSelectedTypeInTypeMenu( final PHYLOGENY_GRAPHICS_TYPE type ) {
+        setTypeMenuToAllUnselected();
+        switch ( type ) {
+            case CIRCULAR:
+                _circular_type_cbmi.setSelected( true );
+                break;
+            case CONVEX:
+                _convex_type_cbmi.setSelected( true );
+                break;
+            case CURVED:
+                _curved_type_cbmi.setSelected( true );
+                break;
+            case EURO_STYLE:
+                _euro_type_cbmi.setSelected( true );
+                break;
+            case ROUNDED:
+                _rounded_type_cbmi.setSelected( true );
+                break;
+            case RECTANGULAR:
+                _rectangular_type_cbmi.setSelected( true );
+                break;
+            case TRIANGULAR:
+                _triangular_type_cbmi.setSelected( true );
+                break;
+            case UNROOTED:
+                _unrooted_type_cbmi.setSelected( true );
+                break;
+            default:
+                throw new IllegalArgumentException( "unknown type: " + type );
+        }
+    }
+
+    void setTypeMenuToAllUnselected() {
+        _convex_type_cbmi.setSelected( false );
+        _curved_type_cbmi.setSelected( false );
+        _euro_type_cbmi.setSelected( false );
+        _rounded_type_cbmi.setSelected( false );
+        _triangular_type_cbmi.setSelected( false );
+        _rectangular_type_cbmi.setSelected( false );
+        _unrooted_type_cbmi.setSelected( false );
+        _circular_type_cbmi.setSelected( false );
+    }
+
+    void showWhole() {
+        _mainpanel.getControlPanel().showWhole();
+    }
+
+    void switchColors() {
+        final TreeColorSet colorset = _mainpanel.getTreeColorSet();
+        final ColorSchemeChooser csc = new ColorSchemeChooser( getMainPanel(), colorset );
+        csc.setVisible( true );
+    }
+
+    void taxColor() {
+        if ( _mainpanel.getCurrentTreePanel() != null ) {
+            _mainpanel.getCurrentTreePanel().taxColor();
+        }
+    }
+
+    void typeChanged( final Object o ) {
+        updateTypeCheckboxes( getOptions(), o );
+        updateOptions( getOptions() );
+        if ( getCurrentTreePanel() != null ) {
+            final PHYLOGENY_GRAPHICS_TYPE previous_type = getCurrentTreePanel().getPhylogenyGraphicsType();
+            final PHYLOGENY_GRAPHICS_TYPE new_type = getOptions().getPhylogenyGraphicsType();
+            if ( ( ( previous_type == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && ( new_type != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) )
+                    || ( ( previous_type == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) && ( new_type != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) )
+                    || ( ( previous_type != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && ( new_type == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) )
+                    || ( ( previous_type != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) && ( new_type == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) ) {
+                getCurrentTreePanel().getControlPanel().showWhole();
+            }
+            if ( getCurrentTreePanel().isPhyHasBranchLengths() && ( new_type != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
+                getCurrentTreePanel().getControlPanel().setDrawPhylogramEnabled( true );
+            }
+            else {
+                getCurrentTreePanel().getControlPanel().setDrawPhylogramEnabled( false );
+            }
+            getCurrentTreePanel().setPhylogenyGraphicsType( getOptions().getPhylogenyGraphicsType() );
+            updateScreenTextAntialias( getMainPanel().getTreePanels() );
+            if ( getCurrentTreePanel().getControlPanel().getDynamicallyHideData() != null ) {
+                if ( new_type == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+                    getCurrentTreePanel().getControlPanel().getDynamicallyHideData().setEnabled( false );
+                }
+                else {
+                    getCurrentTreePanel().getControlPanel().getDynamicallyHideData().setEnabled( true );
+                }
+            }
+        }
+    }
+
+    void updateOptions( final Options options ) {
+        options.setAntialiasScreen( ( _screen_antialias_cbmi != null ) && _screen_antialias_cbmi.isSelected() );
+        options.setBackgroundColorGradient( ( _background_gradient_cbmi != null )
+                && _background_gradient_cbmi.isSelected() );
+        options.setShowDomainLabels( ( _show_domain_labels != null ) && _show_domain_labels.isSelected() );
+        options.setAbbreviateScientificTaxonNames( ( _abbreviate_scientific_names != null )
+                && _abbreviate_scientific_names.isSelected() );
+        options.setColorLabelsSameAsParentBranch( ( _color_labels_same_as_parent_branch != null )
+                && _color_labels_same_as_parent_branch.isSelected() );
+        options.setShowNodeBoxes( ( _show_node_boxes_cbmi != null ) && _show_node_boxes_cbmi.isSelected() );
+        if ( ( _non_lined_up_cladograms_rbmi != null ) && ( _non_lined_up_cladograms_rbmi.isSelected() ) ) {
+            options.setCladogramType( CLADOGRAM_TYPE.NON_LINED_UP );
+        }
+        else if ( ( _uniform_cladograms_rbmi != null ) && ( _uniform_cladograms_rbmi.isSelected() ) ) {
+            options.setCladogramType( CLADOGRAM_TYPE.TOTAL_NODE_SUM_DEP );
+        }
+        else if ( ( _ext_node_dependent_cladogram_rbmi != null ) && ( _ext_node_dependent_cladogram_rbmi.isSelected() ) ) {
+            options.setCladogramType( CLADOGRAM_TYPE.EXT_NODE_SUM_DEP );
+        }
+        options.setSearchCaseSensitive( ( _search_case_senstive_cbmi != null )
+                && _search_case_senstive_cbmi.isSelected() );
+        if ( ( _show_scale_cbmi != null ) && _show_scale_cbmi.isEnabled() ) {
+            options.setShowScale( _show_scale_cbmi.isSelected() );
+        }
+        if ( _label_direction_cbmi != null ) {
+            if ( _label_direction_cbmi.isSelected() ) {
+                options.setNodeLabelDirection( NODE_LABEL_DIRECTION.RADIAL );
+            }
+            else {
+                options.setNodeLabelDirection( NODE_LABEL_DIRECTION.HORIZONTAL );
+            }
+        }
+        options.setShowOverview( ( _show_overview_cbmi != null ) && _show_overview_cbmi.isSelected() );
+        if ( ( _show_branch_length_values_cbmi != null ) && _show_branch_length_values_cbmi.isEnabled() ) {
+            options.setShowBranchLengthValues( _show_branch_length_values_cbmi.isSelected() );
+        }
+        options.setPrintUsingActualSize( ( _print_using_actual_size_cbmi != null )
+                && ( _print_using_actual_size_cbmi.isSelected() ) );
+        options.setGraphicsExportUsingActualSize( ( _graphics_export_using_actual_size_cbmi != null )
+                && ( _graphics_export_using_actual_size_cbmi.isSelected() ) );
+        options.setAntialiasPrint( ( _antialias_print_cbmi != null ) && _antialias_print_cbmi.isSelected() );
+        options.setPrintBlackAndWhite( ( _print_black_and_white_cbmi != null )
+                && _print_black_and_white_cbmi.isSelected() );
+        options
+                .setInternalNumberAreConfidenceForNhParsing( ( _internal_number_are_confidence_for_nh_parsing_cbmi != null )
+                        && _internal_number_are_confidence_for_nh_parsing_cbmi.isSelected() );
+        options.setExtractPfamTaxonomyCodesInNhParsing( ( _extract_pfam_style_tax_codes_cbmi != null )
+                && _extract_pfam_style_tax_codes_cbmi.isSelected() );
+        options.setReplaceUnderscoresInNhParsing( ( _replace_underscores_cbmi != null )
+                && _replace_underscores_cbmi.isSelected() );
+        options.setMatchWholeTermsOnly( ( _search_whole_words_only_cbmi != null )
+                && _search_whole_words_only_cbmi.isSelected() );
+        options.setInverseSearchResult( ( _inverse_search_result_cbmi != null )
+                && _inverse_search_result_cbmi.isSelected() );
+        if ( _graphics_export_visible_only_cbmi != null ) {
+            options.setGraphicsExportVisibleOnly( _graphics_export_visible_only_cbmi.isSelected() );
+            if ( _graphics_export_visible_only_cbmi.isSelected() && ( _graphics_export_using_actual_size_cbmi != null ) ) {
+                _graphics_export_using_actual_size_cbmi.setSelected( true );
+                _graphics_export_using_actual_size_cbmi.setEnabled( false );
+            }
+            else {
+                _graphics_export_using_actual_size_cbmi.setEnabled( true );
+            }
+        }
+        if ( ( _rectangular_type_cbmi != null ) && _rectangular_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
+        }
+        else if ( ( _triangular_type_cbmi != null ) && _triangular_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR );
+        }
+        else if ( ( _curved_type_cbmi != null ) && _curved_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CURVED );
+        }
+        else if ( ( _convex_type_cbmi != null ) && _convex_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CONVEX );
+        }
+        else if ( ( _euro_type_cbmi != null ) && _euro_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE );
+        }
+        else if ( ( _rounded_type_cbmi != null ) && _rounded_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.ROUNDED );
+        }
+        else if ( ( _unrooted_type_cbmi != null ) && _unrooted_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
+        }
+        else if ( ( _circular_type_cbmi != null ) && _circular_type_cbmi.isSelected() ) {
+            options.setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CIRCULAR );
+        }
+    }
+
+    void updateTypeCheckboxes( final Options options, final Object o ) {
+        setTypeMenuToAllUnselected();
+        ( ( JCheckBoxMenuItem ) o ).setSelected( true );
+    }
+
+    void viewAsNexus() {
+        removeTextFrame();
+        if ( ( _mainpanel.getCurrentPhylogeny() == null ) || _mainpanel.getCurrentPhylogeny().isEmpty()
+                || ( _mainpanel.getCurrentPhylogeny().getNumberOfExternalNodes() > 10000 ) ) {
+            return;
+        }
+        _textframe = TextFrame.instantiate( _mainpanel.getCurrentPhylogeny().toNexus() );
+    }
+
+    void viewAsNH() {
+        removeTextFrame();
+        if ( ( _mainpanel.getCurrentPhylogeny() == null ) || _mainpanel.getCurrentPhylogeny().isEmpty()
+                || ( _mainpanel.getCurrentPhylogeny().getNumberOfExternalNodes() > 10000 ) ) {
+            return;
+        }
+        _textframe = TextFrame.instantiate( _mainpanel.getCurrentPhylogeny().toNewHampshire( false ) );
+    }
+
+    void viewAsNHX() {
+        removeTextFrame();
+        if ( ( _mainpanel.getCurrentPhylogeny() == null ) || _mainpanel.getCurrentPhylogeny().isEmpty()
+                || ( _mainpanel.getCurrentPhylogeny().getNumberOfExternalNodes() > 10000 ) ) {
+            return;
+        }
+        _textframe = TextFrame.instantiate( _mainpanel.getCurrentPhylogeny().toNewHampshireX() );
+    }
+
+    void viewAsXML() {
+        removeTextFrame();
+        if ( ( _mainpanel.getCurrentPhylogeny() != null ) && !_mainpanel.getCurrentPhylogeny().isEmpty()
+                && ( _mainpanel.getCurrentPhylogeny().getNumberOfExternalNodes() <= 10000 ) ) {
+            _textframe = TextFrame.instantiate( _mainpanel.getCurrentPhylogeny().toPhyloXML( 0 ) );
+        }
+    }
+
+    /**
+     * Display the about box.
+     */
+    static void about() {
+        final StringBuffer about = new StringBuffer( "Archaeopteryx\nVersion " + Constants.VERSION + "\n" );
+        about.append( "Copyright (C) 2007-2011 Christian Zmasek\n" );
+        about.append( "All Rights Reserved\n" );
+        about.append( "License: GNU Lesser General Public License (LGPL)\n" );
+        about.append( "Last modified: " + Constants.PRG_DATE + "\n" );
+        about.append( "phyloXML version : " + ForesterConstants.PHYLO_XML_VERSION + "\n" );
+        about.append( "phyloXML location: " + ForesterConstants.PHYLO_XML_LOCATION + "\n" );
+        if ( !ForesterUtil.isEmpty( ForesterUtil.JAVA_VERSION ) && !ForesterUtil.isEmpty( ForesterUtil.JAVA_VENDOR ) ) {
+            about.append( "[your Java version: " + ForesterUtil.JAVA_VERSION + " " + ForesterUtil.JAVA_VENDOR + "]\n" );
+        }
+        if ( !ForesterUtil.isEmpty( ForesterUtil.OS_NAME ) && !ForesterUtil.isEmpty( ForesterUtil.OS_ARCH )
+                && !ForesterUtil.isEmpty( ForesterUtil.OS_VERSION ) ) {
+            about.append( "[your OS: " + ForesterUtil.OS_NAME + " " + ForesterUtil.OS_ARCH + " "
+                    + ForesterUtil.OS_VERSION + "]\n" );
+        }
+        final Runtime rt = java.lang.Runtime.getRuntime();
+        final long free_memory = rt.freeMemory() / 1000000;
+        final long total_memory = rt.totalMemory() / 1000000;
+        about.append( "[free memory: " + free_memory + "MB, total memory: " + total_memory + "MB]\n" );
+        about.append( "[locale: " + Locale.getDefault() + "]\n" );
+        about.append( "References:\n" );
+        about.append( Constants.PHYLOXML_REFERENCE_SHORT + "\n" );
+        about.append( "For more information & download:\n" );
+        about.append( Constants.APTX_WEB_SITE + "\n" );
+        about.append( "Comments: " + Constants.AUTHOR_EMAIL );
+        JOptionPane.showMessageDialog( null, about, Constants.PRG_NAME, JOptionPane.PLAIN_MESSAGE );
+    }
+
+    static String createCurrentFontDesc( final TreeFontSet tree_font_set ) {
+        return tree_font_set.getLargeFont().getFamily() + " " + tree_font_set.getLargeFont().getSize();
+    }
+
+    static JMenu createMenu( final String title, final Configuration conf ) {
+        final JMenu jmenu = new JMenu( title );
+        if ( !conf.isUseNativeUI() ) {
+            jmenu.setFont( MainFrame.menu_font );
+            jmenu.setBackground( conf.getGuiMenuBackgroundColor() );
+            jmenu.setForeground( conf.getGuiMenuTextColor() );
+        }
+        return jmenu;
+    }
+
+    static JMenuItem customizeMenuItemAsLabel( final JMenuItem label, final Configuration configuration ) {
+        label.setFont( MainFrame.menu_font.deriveFont( Font.BOLD ) );
+        if ( !configuration.isUseNativeUI() ) {
+            label.setBackground( configuration.getGuiMenuBackgroundColor() );
+            label.setForeground( configuration.getGuiMenuTextColor() );
+            label.setOpaque( true );
+        }
+        label.setSelected( false );
+        label.setEnabled( false );
+        return label;
+    }
+
+    static void cycleOverview( final Options op, final TreePanel tree_panel ) {
+        switch ( op.getOvPlacement() ) {
+            case LOWER_LEFT:
+                op.setOvPlacement( Options.OVERVIEW_PLACEMENT_TYPE.UPPER_LEFT );
+                break;
+            case LOWER_RIGHT:
+                op.setOvPlacement( Options.OVERVIEW_PLACEMENT_TYPE.LOWER_LEFT );
+                break;
+            case UPPER_LEFT:
+                op.setOvPlacement( Options.OVERVIEW_PLACEMENT_TYPE.UPPER_RIGHT );
+                break;
+            case UPPER_RIGHT:
+                op.setOvPlacement( Options.OVERVIEW_PLACEMENT_TYPE.LOWER_RIGHT );
+                break;
+            default:
+                throw new RuntimeException( "unknown placement: " + op.getOvPlacement() );
+        }
+        tree_panel.updateOvSettings();
+    }
+
+    static void help( final Map<String, WebLink> weblinks ) {
+        final StringBuilder sb = new StringBuilder();
+        sb.append( "Display options\n" );
+        sb.append( "-------------------\n" );
+        sb.append( "Use the checkboxes to select types of information to display on the tree.\n\n" );
+        sb.append( "Clickable tree nodes\n" );
+        sb.append( "--------------------\n" );
+        sb.append( "Tree nodes can be clicked, the action is determined by the 'click on node to' menu\n" );
+        sb.append( "or by right clicking:\n" );
+        sb.append( "o  Display Node Data -- display information for a node\n" );
+        sb.append( "o  Collapse/Uncollapse -- collapse and uncollapse subtree from clicked node\n" );
+        sb.append( "o  Root/Reroot -- change tree root to clicked node\n" );
+        sb.append( "o  Sub/Super Tree -- toggle between subtree from clicked node and whole tree\n" );
+        sb.append( "o  Swap Descendants -- switch descendant on either side of clicked node\n" );
+        sb.append( "o  Colorize Subtree -- color a subtree\n" );
+        sb.append( "o  Open Sequence Web -- launch a web browser to display sequence information\n" );
+        sb.append( "o  Open Taxonomy Web -- launch a web browser to display taxonomy information\n" );
+        sb.append( "-  there may be additional choices depending on this particular setup\n\n" );
+        sb.append( "Right clicking on a node always displays the information of a node.\n\n" );
+        sb.append( "Zooming\n" );
+        sb.append( "---------\n" );
+        sb.append( "The mouse wheel and the plus and minus keys control zooming.\n" );
+        sb.append( "Mouse wheel+Ctrl changes the text size.\n" );
+        sb.append( "Mouse wheel+Shift controls zooming in vertical direction only.\n" );
+        sb.append( "Use the buttons on the control panel to zoom the tree in and out, horizontally or vertically.\n" );
+        sb
+                .append( "The entire tree can be fitted into the window by clicking the \"F\" button, or by pressing F, Delete, or Home.\n" );
+        sb.append( "The up, down, left, and right keys can be used to move the visible part (if zoomed in).\n" );
+        sb.append( "Up, down, left, and right+Shift can be used to control zooming horizontally and vertically.\n" );
+        sb.append( "Plus and minus keys+Ctrl change the text size; F+Ctrl, Delete+Ctrl, or Home+Ctrl resets it.\n\n" );
+        sb.append( "Quick tree manipulation:\n" );
+        sb.append( "------------------------\n" );
+        sb.append( "Order Subtrees -- order the tree by branch length\n" );
+        sb.append( "Uncollapse All -- uncollapse any and all collapsed branches\n\n" );
+        sb.append( "Memory problems (Java heap space error)\n" );
+        sb.append( "---------------------------------------\n" );
+        sb.append( "Since the Java default memory allocation is quite small, it might by necessary (for trees\n" );
+        sb
+                .append( "with more than approximately 5000 external nodes) to increase the memory which Java can use, with\n" );
+        sb.append( "the '-Xmx' Java command line option. For example:\n" );
+        sb.append( "java -Xms32m -Xmx256m -cp path\\to\\forester.jar org.forester.archaeopteryx.Archaeopteryx\n\n" );
+        if ( ( weblinks != null ) && ( weblinks.size() > 0 ) ) {
+            sb.append( "Active web links\n" );
+            sb.append( "--------------------\n" );
+            for( final String key : weblinks.keySet() ) {
+                sb.append( " " + weblinks.get( key ).toString() + "\n" );
+            }
+        }
+        // + "General remarks\n"
+        // + "---------------\n"
+        // +
+        // "o  The application version permits copying to the clipboard \n"
+        // +
+        // "    in the \"View\"|\"View as ...\" frame (either by control-c or button press).\n"
+        // +
+        // "o  Changes made to a subtree affect this subtree and its subtrees,\n"
+        // + "    but not any of its parent tree(s).\n"
+        // +
+        // "o  Archaeopteryx tries to detect whether the numerical values in a NH tree\n"
+        // +
+        // "    are likely to be bootstrap values instead of branch length values.\n\n"
+        // +
+        // " Remarks regarding SDI (Speciation Duplication Inference):\n"
+        // +
+        // "o  Each external node of the gene tree (in display) needs to be associated with\n"
+        // +
+        // "    a species: either directly through the \"Species\" field, or the species\n"
+        // +
+        // "    is part of the sequence name in the form \"XXXX_SPECIES\"\n"
+        // +
+        // "    (e.g. \"ACON_DROME\" or \"ACON_DROME/123-4489\" which is also acceptable).\n"
+        // +
+        // "o  A species tree for each species of the gene tree needs to be loaded with\n"
+        // +
+        // "   \"SDI\"|\"Load species tree\" prior the SDI execution.\n"
+        // +
+        // "o  !External nodes of the gene tree associated with species not present in\n"
+        // +
+        // "    the species tree are REMOVED prior to SDI execution!\n"
+        // +
+        // "o  Both the gene tree and the species tree must be completely binary.\n"
+        // +
+        // "o  Duplications and speciations are a function of the position of the root.\n"
+        // +
+        // "    Hence, after each manual \"Root/Reroot\"ing some duplications will be\n"
+        // + "    incorrect and need to be inferred again\n"
+        // +
+        // "    with: \"SDI\"|\"SDI (Speciation Duplication Inference)\n\n"
+        sb.append( "\n" );
+        sb.append( "phyloXML\n" );
+        sb.append( "-------------------\n" );
+        sb.append( "Reference: " + Constants.PHYLOXML_REFERENCE + "\n" );
+        sb.append( "Website: " + Constants.PHYLOXML_WEB_SITE + "\n" );
+        sb.append( "Version: " + ForesterConstants.PHYLO_XML_VERSION + "\n" );
+        sb.append( "\n" );
+        sb.append( "For more information: http://www.phylosoft.org/archaeopteryx/\n" );
+        sb.append( "Email: " + Constants.AUTHOR_EMAIL + "\n\n" );
+        TextFrame.instantiate( sb.toString() );
+    }
+
+    static void setOvPlacementColorChooseMenuItem( final JMenuItem mi, final TreePanel tree_panel ) {
+        if ( ( tree_panel != null ) && ( tree_panel.getTreeColorSet() != null ) ) {
+            mi.setText( "Overview Placement... (current: " + tree_panel.getOptions().getOvPlacement() + ")" );
+        }
+        else {
+            mi.setText( "Overview Placement..." );
+        }
+    }
+
+    static void setTextColorChooseMenuItem( final JMenuItem mi, final TreePanel tree_panel ) {
+        if ( ( tree_panel != null ) && ( tree_panel.getTreeColorSet() != null ) ) {
+            mi.setText( "Select Colors... (current: " + tree_panel.getTreeColorSet().getCurrentColorSchemeName() + ")" );
+        }
+        else {
+            mi.setText( "Select Colors..." );
+        }
+    }
+
+    static void setTextForFontChooserMenuItem( final JMenuItem mi, final String font_desc ) {
+        mi.setText( "Select Font... (current: " + font_desc + ")" );
+    }
+
+    static void setTextMinSupportMenuItem( final JMenuItem mi, final Options options, final TreePanel current_tree_panel ) {
+        if ( ( current_tree_panel == null ) || ( current_tree_panel.getPhylogeny() == null ) ) {
+            mi.setEnabled( true );
+        }
+        else if ( ForesterUtil.isHasAtLeastOneBranchWithSupportValues( current_tree_panel.getPhylogeny() ) ) {
+            mi.setEnabled( true );
+        }
+        else {
+            mi.setEnabled( false );
+        }
+        mi.setText( "Enter Min Confidence Value... (current: " + options.getMinConfidenceValue() + ")" );
+    }
+
+    static void updateOptionsMenuDependingOnPhylogenyType( final MainPanel main_panel,
+                                                           final JCheckBoxMenuItem scale,
+                                                           final JCheckBoxMenuItem branch_lengths,
+                                                           final JRadioButtonMenuItem non_lined_up,
+                                                           final JRadioButtonMenuItem uniform_clado,
+                                                           final JRadioButtonMenuItem nonuniform_clado,
+                                                           final JCheckBoxMenuItem label_direction_cbmi ) {
+        final TreePanel tree_panel = main_panel.getCurrentTreePanel();
+        final ControlPanel control = main_panel.getControlPanel();
+        final Options options = main_panel.getOptions();
+        scale.setSelected( options.isShowScale() );
+        branch_lengths.setSelected( options.isShowBranchLengthValues() );
+        // non_lined_up.setSelected( options.isNonLinedUpCladogram() );
+        if ( ( tree_panel != null ) && ( !tree_panel.isPhyHasBranchLengths() ) ) {
+            scale.setSelected( false );
+            scale.setEnabled( false );
+            branch_lengths.setSelected( false );
+            branch_lengths.setEnabled( false );
+        }
+        else if ( ( tree_panel != null ) && !control.isDrawPhylogram() ) {
+            scale.setSelected( false );
+            scale.setEnabled( false );
+            branch_lengths.setEnabled( true );
+        }
+        else {
+            scale.setEnabled( true );
+            branch_lengths.setEnabled( true );
+        }
+        if ( ( tree_panel != null )
+                && ( ( tree_panel.getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.ROUNDED )
+                        && ( tree_panel.getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) && ( tree_panel
+                        .getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ) ) ) {
+            branch_lengths.setSelected( false );
+            branch_lengths.setEnabled( false );
+        }
+        if ( tree_panel != null ) {
+            if ( ( tree_panel.getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR )
+                    || ( tree_panel.getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) ) {
+                non_lined_up.setEnabled( false );
+                uniform_clado.setEnabled( false );
+                nonuniform_clado.setEnabled( false );
+            }
+            else {
+                non_lined_up.setEnabled( true );
+                uniform_clado.setEnabled( true );
+                nonuniform_clado.setEnabled( true );
+            }
+        }
+        else {
+            if ( ( tree_panel != null )
+                    && ( ( tree_panel.getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) && ( tree_panel
+                            .getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ) ) ) {
+                branch_lengths.setSelected( false );
+                branch_lengths.setEnabled( false );
+            }
+            if ( ( tree_panel != null )
+                    && ( ( tree_panel.getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) || ( tree_panel
+                            .getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) ) ) {
+                non_lined_up.setEnabled( false );
+            }
+            else {
+                // non_lined_up.setSelected( options.isNonLinedUpCladogram() );
+                non_lined_up.setEnabled( true );
+            }
+        }
+        label_direction_cbmi.setEnabled( true );
+        if ( tree_panel != null ) {
+            if ( ( tree_panel.getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
+                    && ( tree_panel.getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
+                label_direction_cbmi.setEnabled( false );
+            }
+            if ( tree_panel.getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) {
+                scale.setSelected( false );
+                scale.setEnabled( false );
+            }
+        }
+    }
+
+    static void updateScreenTextAntialias( final List<TreePanel> treepanels ) {
+        for( final TreePanel tree_panel : treepanels ) {
+            tree_panel.setTextAntialias();
+        }
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/MainFrameApplet.java b/forester/java/src/org/forester/archaeopteryx/MainFrameApplet.java
new file mode 100644 (file)
index 0000000..3ac938c
--- /dev/null
@@ -0,0 +1,269 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// Copyright (C) 2000-2001 Washington University School of Medicine
+// and Howard Hughes Medical Institute
+// Copyright (C) 2003-2007 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.BorderLayout;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.net.URL;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JApplet;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.forester.archaeopteryx.Options.CLADOGRAM_TYPE;
+import org.forester.archaeopteryx.Options.NODE_LABEL_DIRECTION;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.util.ForesterUtil;
+
+public final class MainFrameApplet extends MainFrame {
+
+    private static final long    serialVersionUID = 1941019292746717053L;
+    private final static int     FRAME_X_SIZE     = 640, FRAME_Y_SIZE = 580;
+    private final ArchaeopteryxA _applet;
+    private ButtonGroup          _radio_group_1;
+
+    MainFrameApplet( final ArchaeopteryxA parent_applet, final Configuration configuration ) {
+        setTitle( ArchaeopteryxA.NAME );
+        _applet = parent_applet;
+        setConfiguration( configuration );
+        setOptions( Options.createInstance( configuration ) );
+        _textframe = null;
+        URL url = null;
+        Phylogeny[] phys = null;
+        // Get URL to tree file
+        if ( _applet.getUrlString() != null ) {
+            try {
+                url = new URL( _applet.getUrlString() );
+            }
+            catch ( final Exception e ) {
+                ForesterUtil.printErrorMessage( ArchaeopteryxA.NAME, e.toString() );
+                e.printStackTrace();
+                JOptionPane
+                        .showMessageDialog( this,
+                                            ArchaeopteryxA.NAME + ": Could not create URL from: \""
+                                                    + _applet.getUrlString() + "\"\nError: " + e,
+                                            "Failed to create URL",
+                                            JOptionPane.ERROR_MESSAGE );
+                close();
+            }
+        }
+        // Load the tree from URL
+        if ( url != null ) {
+            try {
+                phys = Util.readPhylogeniesFromUrl( url, getConfiguration().isValidatePhyloXmlAgainstSchema() );
+            }
+            catch ( final Exception e ) {
+                ForesterUtil.printErrorMessage( ArchaeopteryxA.NAME, e.toString() );
+                e.printStackTrace();
+                JOptionPane.showMessageDialog( this, ArchaeopteryxA.NAME + ": Failed to read phylogenies: "
+                        + "\nError: " + e, "Failed to read phylogenies", JOptionPane.ERROR_MESSAGE );
+                close();
+            }
+        }
+        if ( ( phys == null ) || ( phys.length < 1 ) ) {
+            ForesterUtil.printErrorMessage( ArchaeopteryxA.NAME, "phylogenies from [" + url + "] are null or empty" );
+            JOptionPane.showMessageDialog( this, ArchaeopteryxA.NAME + ": phylogenies from [" + url
+                    + "] are null or empty", "Failed to read phylogenies", JOptionPane.ERROR_MESSAGE );
+        }
+        else {
+            Util.printAppletMessage( ArchaeopteryxA.NAME, "loaded " + phys.length + " phylogenies from: " + url );
+        }
+        _mainpanel = new MainPanelApplets( _configuration, this );
+        // build the menu bar
+        _jmenubar = new JMenuBar();
+        if ( !_configuration.isUseNativeUI() ) {
+            _jmenubar.setBackground( _configuration.getGuiMenuBackgroundColor() );
+        }
+        buildToolsMenu();
+        buildViewMenu();
+        buildFontSizeMenu();
+        buildOptionsMenu();
+        buildTypeMenu();
+        buildHelpMenu();
+        setJMenuBar( _jmenubar );
+        _contentpane = getContentPane();
+        _contentpane.setLayout( new BorderLayout() );
+        _contentpane.add( _mainpanel, BorderLayout.CENTER );
+        setSize( FRAME_X_SIZE, FRAME_Y_SIZE );
+        addWindowListener( new WindowAdapter() {
+
+            @Override
+            public void windowClosing( final WindowEvent e ) {
+                close();
+            }
+        } );
+        addComponentListener( new ComponentAdapter() {
+
+            @Override
+            public void componentResized( final ComponentEvent e ) {
+                if ( _mainpanel.getCurrentTreePanel() != null ) {
+                    _mainpanel.getCurrentTreePanel().setParametersForPainting( _mainpanel.getCurrentTreePanel()
+                                                                                       .getWidth(),
+                                                                               _mainpanel.getCurrentTreePanel()
+                                                                                       .getHeight(),
+                                                                               false );
+                }
+            }
+        } );
+        setFocusable( true );
+        requestFocus();
+        requestFocusInWindow();
+        // All done: hello, world!
+        setVisible( true );
+        System.gc();
+    }
+
+    void buildOptionsMenu() {
+        _options_jmenu = MainFrame.createMenu( MainFrame.OPTIONS_HEADER, getConfiguration() );
+        _options_jmenu.addChangeListener( new ChangeListener() {
+
+            @Override
+            public void stateChanged( final ChangeEvent e ) {
+                MainFrame.setOvPlacementColorChooseMenuItem( _overview_placment_mi, getCurrentTreePanel() );
+                MainFrame.setTextColorChooseMenuItem( _switch_colors_mi, getCurrentTreePanel() );
+                MainFrame
+                        .setTextMinSupportMenuItem( _choose_minimal_confidence_mi, getOptions(), getCurrentTreePanel() );
+                MainFrame.setTextForFontChooserMenuItem( _choose_font_mi, createCurrentFontDesc( getMainPanel()
+                        .getTreeFontSet() ) );
+                MainFrame.updateOptionsMenuDependingOnPhylogenyType( getMainPanel(),
+                                                                     _show_scale_cbmi,
+                                                                     _show_branch_length_values_cbmi,
+                                                                     _non_lined_up_cladograms_rbmi,
+                                                                     _uniform_cladograms_rbmi,
+                                                                     _ext_node_dependent_cladogram_rbmi,
+                                                                     _label_direction_cbmi );
+            }
+        } );
+        _options_jmenu.add( MainFrame.customizeMenuItemAsLabel( new JMenuItem( MainFrame.DISPLAY_SUBHEADER ),
+                                                                getConfiguration() ) );
+        _options_jmenu
+                .add( _ext_node_dependent_cladogram_rbmi = new JRadioButtonMenuItem( MainFrame.NONUNIFORM_CLADOGRAMS_LABEL ) );
+        _options_jmenu.add( _uniform_cladograms_rbmi = new JRadioButtonMenuItem( MainFrame.UNIFORM_CLADOGRAMS_LABEL ) );
+        _options_jmenu.add( _non_lined_up_cladograms_rbmi = new JRadioButtonMenuItem( NON_LINED_UP_CLADOGRAMS_LABEL ) );
+        _radio_group_1 = new ButtonGroup();
+        _radio_group_1.add( _ext_node_dependent_cladogram_rbmi );
+        _radio_group_1.add( _uniform_cladograms_rbmi );
+        _radio_group_1.add( _non_lined_up_cladograms_rbmi );
+        _options_jmenu.add( _show_node_boxes_cbmi = new JCheckBoxMenuItem( MainFrame.DISPLAY_NODE_BOXES_LABEL ) );
+        _options_jmenu.add( _show_scale_cbmi = new JCheckBoxMenuItem( MainFrame.DISPLAY_SCALE_LABEL ) );
+        _options_jmenu
+                .add( _show_branch_length_values_cbmi = new JCheckBoxMenuItem( MainFrame.DISPLAY_BRANCH_LENGTH_VALUES_LABEL ) );
+        _options_jmenu.add( _show_overview_cbmi = new JCheckBoxMenuItem( MainFrame.SHOW_OVERVIEW_LABEL ) );
+        _options_jmenu.add( _label_direction_cbmi = new JCheckBoxMenuItem( LABEL_DIRECTION_LABEL ) );
+        _label_direction_cbmi.setToolTipText( LABEL_DIRECTION_TIP );
+        _options_jmenu.add( _color_labels_same_as_parent_branch = new JCheckBoxMenuItem( COLOR_LABELS_LABEL ) );
+        _color_labels_same_as_parent_branch.setToolTipText( MainFrame.COLOR_LABELS_TIP );
+        _options_jmenu.add( _abbreviate_scientific_names = new JCheckBoxMenuItem( MainFrame.ABBREV_SN_LABEL ) );
+        _options_jmenu.add( _screen_antialias_cbmi = new JCheckBoxMenuItem( MainFrame.SCREEN_ANTIALIAS_LABEL ) );
+        _options_jmenu.add( _background_gradient_cbmi = new JCheckBoxMenuItem( MainFrame.BG_GRAD_LABEL ) );
+        if ( getConfiguration().doDisplayOption( Configuration.show_domain_architectures ) ) {
+            _options_jmenu.add( _show_domain_labels = new JCheckBoxMenuItem( SHOW_DOMAIN_LABELS_LABEL ) );
+        }
+        _options_jmenu.add( _choose_minimal_confidence_mi = new JMenuItem( "" ) );
+        _options_jmenu.add( _overview_placment_mi = new JMenuItem( "" ) );
+        _options_jmenu.add( _switch_colors_mi = new JMenuItem( "" ) );
+        _options_jmenu.add( _choose_font_mi = new JMenuItem( "" ) );
+        _options_jmenu.addSeparator();
+        _options_jmenu.add( MainFrame.customizeMenuItemAsLabel( new JMenuItem( MainFrame.SEARCH_SUBHEADER ),
+                                                                getConfiguration() ) );
+        _options_jmenu
+                .add( _search_case_senstive_cbmi = new JCheckBoxMenuItem( MainFrame.SEARCH_CASE_SENSITIVE_LABEL ) );
+        _options_jmenu.add( _search_whole_words_only_cbmi = new JCheckBoxMenuItem( MainFrame.SEARCH_TERMS_ONLY_LABEL ) );
+        _options_jmenu.add( _inverse_search_result_cbmi = new JCheckBoxMenuItem( INVERSE_SEARCH_RESULT_LABEL ) );
+        customizeJMenuItem( _choose_font_mi );
+        customizeJMenuItem( _switch_colors_mi );
+        customizeJMenuItem( _choose_minimal_confidence_mi );
+        customizeJMenuItem( _overview_placment_mi );
+        customizeCheckBoxMenuItem( _show_node_boxes_cbmi, getOptions().isShowNodeBoxes() );
+        customizeCheckBoxMenuItem( _color_labels_same_as_parent_branch, getOptions().isColorLabelsSameAsParentBranch() );
+        customizeCheckBoxMenuItem( _screen_antialias_cbmi, getOptions().isAntialiasScreen() );
+        customizeCheckBoxMenuItem( _background_gradient_cbmi, getOptions().isBackgroundColorGradient() );
+        customizeCheckBoxMenuItem( _show_domain_labels, getOptions().isShowDomainLabels() );
+        customizeCheckBoxMenuItem( _abbreviate_scientific_names, getOptions().isAbbreviateScientificTaxonNames() );
+        customizeCheckBoxMenuItem( _search_case_senstive_cbmi, getOptions().isSearchCaseSensitive() );
+        customizeCheckBoxMenuItem( _show_scale_cbmi, getOptions().isShowScale() );
+        customizeRadioButtonMenuItem( _non_lined_up_cladograms_rbmi,
+                                      getOptions().getCladogramType() == CLADOGRAM_TYPE.NON_LINED_UP );
+        customizeRadioButtonMenuItem( _uniform_cladograms_rbmi,
+                                      getOptions().getCladogramType() == CLADOGRAM_TYPE.TOTAL_NODE_SUM_DEP );
+        customizeRadioButtonMenuItem( _ext_node_dependent_cladogram_rbmi,
+                                      getOptions().getCladogramType() == CLADOGRAM_TYPE.EXT_NODE_SUM_DEP );
+        customizeCheckBoxMenuItem( _show_branch_length_values_cbmi, getOptions().isShowBranchLengthValues() );
+        customizeCheckBoxMenuItem( _show_overview_cbmi, getOptions().isShowOverview() );
+        customizeCheckBoxMenuItem( _label_direction_cbmi,
+                                   getOptions().getNodeLabelDirection() == NODE_LABEL_DIRECTION.RADIAL );
+        customizeCheckBoxMenuItem( _search_whole_words_only_cbmi, getOptions().isMatchWholeTermsOnly() );
+        customizeCheckBoxMenuItem( _inverse_search_result_cbmi, getOptions().isInverseSearchResult() );
+        _jmenubar.add( _options_jmenu );
+    }
+
+    void buildToolsMenu() {
+        _tools_menu = MainFrame.createMenu( "Tools", getConfiguration() );
+        _tools_menu.add( _confcolor_item = new JMenuItem( "Colorize Branches Depending on Confidence" ) );
+        customizeJMenuItem( _confcolor_item );
+        _tools_menu.add( _taxcolor_item = new JMenuItem( "Taxonomy Colorize Branches" ) );
+        customizeJMenuItem( _taxcolor_item );
+        _tools_menu.add( _remove_branch_color_item = new JMenuItem( "Delete Branch Colors" ) );
+        _remove_branch_color_item.setToolTipText( "To delete branch color values from the current phylogeny." );
+        customizeJMenuItem( _remove_branch_color_item );
+        _tools_menu.addSeparator();
+        _tools_menu.add( _midpoint_root_item = new JMenuItem( "Midpoint-Root" ) );
+        customizeJMenuItem( _midpoint_root_item );
+        _tools_menu.addSeparator();
+        _tools_menu
+                .add( _infer_common_sn_names_item = new JMenuItem( "Infer Common Parts of Internal Scientific Names" ) );
+        customizeJMenuItem( _infer_common_sn_names_item );
+        _tools_menu.add( _collapse_species_specific_subtrees = new JMenuItem( "Collapse Species-Specific Subtrees" ) );
+        customizeJMenuItem( _collapse_species_specific_subtrees );
+        _jmenubar.add( _tools_menu );
+    }
+
+    JApplet getApplet() {
+        return _applet;
+    }
+
+    @Override
+    MainPanel getMainPanel() {
+        return _mainpanel;
+    }
+
+    @Override
+    void readPhylogeniesFromURL() {
+        throw new NoSuchMethodError( "not implemented" );
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/MainFrameApplication.java b/forester/java/src/org/forester/archaeopteryx/MainFrameApplication.java
new file mode 100644 (file)
index 0000000..a6e2569
--- /dev/null
@@ -0,0 +1,2600 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// Copyright (C) 2003-2007 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.BorderLayout;
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JFileChooser;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JRadioButtonMenuItem;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+import javax.swing.WindowConstants;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.filechooser.FileFilter;
+
+import org.forester.archaeopteryx.Options.CLADOGRAM_TYPE;
+import org.forester.archaeopteryx.Options.NODE_LABEL_DIRECTION;
+import org.forester.archaeopteryx.Options.PHYLOGENY_GRAPHICS_TYPE;
+import org.forester.archaeopteryx.Util.GraphicsExportType;
+import org.forester.archaeopteryx.webservices.PhylogeniesWebserviceClient;
+import org.forester.archaeopteryx.webservices.WebservicesManager;
+import org.forester.io.parsers.FastaParser;
+import org.forester.io.parsers.GeneralMsaParser;
+import org.forester.io.parsers.PhylogenyParser;
+import org.forester.io.parsers.nexus.NexusPhylogeniesParser;
+import org.forester.io.parsers.nhx.NHXParser;
+import org.forester.io.parsers.phyloxml.PhyloXmlParser;
+import org.forester.io.parsers.phyloxml.PhyloXmlUtil;
+import org.forester.io.parsers.tol.TolParser;
+import org.forester.io.writers.PhylogenyWriter;
+import org.forester.io.writers.SequenceWriter;
+import org.forester.msa.Msa;
+import org.forester.msa.MsaFormatException;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.phylogeny.PhylogenyMethods;
+import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.Confidence;
+import org.forester.phylogeny.data.Taxonomy;
+import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
+import org.forester.phylogeny.factories.PhylogenyFactory;
+import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
+import org.forester.sdi.GSDI;
+import org.forester.sdi.SDI;
+import org.forester.sdi.SDIR;
+import org.forester.sdi.SDIse;
+import org.forester.sequence.Sequence;
+import org.forester.util.BasicDescriptiveStatistics;
+import org.forester.util.BasicTable;
+import org.forester.util.BasicTableParser;
+import org.forester.util.DescriptiveStatistics;
+import org.forester.util.ForesterUtil;
+import org.forester.util.WindowsUtils;
+import org.forester.util.ForesterUtil.PhylogenyNodeField;
+import org.forester.util.ForesterUtil.TAXONOMY_EXTRACTION;
+
+class DefaultFilter extends FileFilter {
+
+    @Override
+    public boolean accept( final File f ) {
+        final String file_name = f.getName().trim().toLowerCase();
+        return file_name.endsWith( ".nh" ) || file_name.endsWith( ".newick" ) || file_name.endsWith( ".phy" )
+                || file_name.endsWith( ".nwk" ) || file_name.endsWith( ".phb" ) || file_name.endsWith( ".ph" )
+                || file_name.endsWith( ".tr" ) || file_name.endsWith( ".dnd" ) || file_name.endsWith( ".tree" )
+                || file_name.endsWith( ".nhx" ) || file_name.endsWith( ".xml" ) || file_name.endsWith( ".phyloxml" )
+                || file_name.endsWith( "phylo.xml" ) || file_name.endsWith( ".pxml" ) || file_name.endsWith( ".nexus" )
+                || file_name.endsWith( ".nx" ) || file_name.endsWith( ".nex" ) || file_name.endsWith( ".tre" )
+                || file_name.endsWith( ".zip" ) || file_name.endsWith( ".tol" ) || file_name.endsWith( ".tolxml" )
+                || file_name.endsWith( ".con" ) || f.isDirectory();
+    }
+
+    @Override
+    public String getDescription() {
+        return "All supported files (*.xml, *.phyloxml, *phylo.xml, *.nhx, *.nh, *.newick, *.nex, *.nexus, *.phy, *.tre, *.tree, *.tol, ...)";
+    }
+}
+
+class GraphicsFileFilter extends FileFilter {
+
+    @Override
+    public boolean accept( final File f ) {
+        final String file_name = f.getName().trim().toLowerCase();
+        return file_name.endsWith( ".jpg" ) || file_name.endsWith( ".jpeg" ) || file_name.endsWith( ".png" )
+                || file_name.endsWith( ".gif" ) || file_name.endsWith( ".bmp" ) || f.isDirectory();
+    }
+
+    @Override
+    public String getDescription() {
+        return "Image files (*.jpg, *.jpeg, *.png, *.gif, *.bmp)";
+    }
+}
+
+class MsaFileFilter extends FileFilter {
+
+    @Override
+    public boolean accept( final File f ) {
+        final String file_name = f.getName().trim().toLowerCase();
+        return file_name.endsWith( ".msa" ) || file_name.endsWith( ".aln" ) || file_name.endsWith( ".fasta" )
+                || file_name.endsWith( ".fas" ) || file_name.endsWith( ".fa" ) || f.isDirectory();
+    }
+
+    @Override
+    public String getDescription() {
+        return "Multiple sequence alignment files (*.msa, *.aln, *.fasta, *.fa, *.fas)";
+    }
+}
+
+class SequencesFileFilter extends FileFilter {
+
+    @Override
+    public boolean accept( final File f ) {
+        final String file_name = f.getName().trim().toLowerCase();
+        return file_name.endsWith( ".fasta" ) || file_name.endsWith( ".fa" ) || file_name.endsWith( ".fas" )
+                || file_name.endsWith( ".seqs" ) || f.isDirectory();
+    }
+
+    @Override
+    public String getDescription() {
+        return "Sequences files (*.fasta, *.fa, *.fas, *.seqs )";
+    }
+}
+
+public final class MainFrameApplication extends MainFrame {
+
+    private final static int                 FRAME_X_SIZE                    = 800;
+    private final static int                 FRAME_Y_SIZE                    = 800;
+    // Filters for the file-open dialog (classes defined in this file)
+    private final static NHFilter            nhfilter                        = new NHFilter();
+    private final static NHXFilter           nhxfilter                       = new NHXFilter();
+    private final static XMLFilter           xmlfilter                       = new XMLFilter();
+    private final static TolFilter           tolfilter                       = new TolFilter();
+    private final static NexusFilter         nexusfilter                     = new NexusFilter();
+    private final static PdfFilter           pdffilter                       = new PdfFilter();
+    private final static GraphicsFileFilter  graphicsfilefilter              = new GraphicsFileFilter();
+    private final static MsaFileFilter       msafilter                       = new MsaFileFilter();
+    private final static SequencesFileFilter seqsfilter                      = new SequencesFileFilter();
+    private final static DefaultFilter       defaultfilter                   = new DefaultFilter();
+    private static final long                serialVersionUID                = -799735726778865234L;
+    private final JFileChooser               _values_filechooser;
+    private final JFileChooser               _open_filechooser;
+    private final JFileChooser               _msa_filechooser;
+    private final JFileChooser               _seqs_filechooser;
+    private final JFileChooser               _open_filechooser_for_species_tree;
+    private final JFileChooser               _save_filechooser;
+    private final JFileChooser               _writetopdf_filechooser;
+    private final JFileChooser               _writetographics_filechooser;
+    // Analysis menu
+    private JMenu                            _analysis_menu;
+    private JMenuItem                        _load_species_tree_item;
+    private JMenuItem                        _sdi_item;
+    private JMenuItem                        _gsdi_item;
+    private JMenuItem                        _root_min_dups_item;
+    private JMenuItem                        _root_min_cost_l_item;
+    private JMenuItem                        _lineage_inference;
+    private JMenuItem                        _function_analysis;
+    // Application-only print menu items
+    private JMenuItem                        _print_item;
+    private JMenuItem                        _write_to_pdf_item;
+    private JMenuItem                        _write_to_jpg_item;
+    private JMenuItem                        _write_to_gif_item;
+    private JMenuItem                        _write_to_tif_item;
+    private JMenuItem                        _write_to_png_item;
+    private JMenuItem                        _write_to_bmp_item;
+    private Phylogeny                        _species_tree;
+    private File                             _current_dir;
+    private ButtonGroup                      _radio_group_1;
+    // Others:
+    double                                   _min_not_collapse               = Constants.MIN_NOT_COLLAPSE_DEFAULT;
+    // Phylogeny Inference menu
+    private JMenu                            _inference_menu;
+    private JMenuItem                        _inference_from_msa_item;
+    private JMenuItem                        _inference_from_seqs_item;
+    // Phylogeny Inference
+    private PhylogeneticInferenceOptions     _phylogenetic_inference_options = null;
+    private Msa                              _msa                            = null;
+    private File                             _msa_file                       = null;
+    private List<Sequence>                   _seqs                           = null;
+    private File                             _seqs_file                      = null;
+    // expression values menu:
+    JMenuItem                                _read_values_jmi;
+
+    private MainFrameApplication( final Phylogeny[] phys, final Configuration config, final String title ) {
+        _configuration = config;
+        if ( _configuration == null ) {
+            throw new IllegalArgumentException( "configuration is null" );
+        }
+        try {
+            if ( _configuration.isUseNativeUI() ) {
+                UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
+            }
+            else {
+                UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
+            }
+        }
+        catch ( final UnsupportedLookAndFeelException e ) {
+            Util.dieWithSystemError( "UnsupportedLookAndFeelException: " + e.toString() );
+        }
+        catch ( final ClassNotFoundException e ) {
+            Util.dieWithSystemError( "ClassNotFoundException: " + e.toString() );
+        }
+        catch ( final InstantiationException e ) {
+            Util.dieWithSystemError( "InstantiationException: " + e.toString() );
+        }
+        catch ( final IllegalAccessException e ) {
+            Util.dieWithSystemError( "IllegalAccessException: " + e.toString() );
+        }
+        catch ( final Exception e ) {
+            Util.dieWithSystemError( e.toString() );
+        }
+        // hide until everything is ready
+        setVisible( false );
+        setOptions( Options.createInstance( _configuration ) );
+        setPhylogeneticInferenceOptions( PhylogeneticInferenceOptions.createInstance( _configuration ) );
+        _textframe = null;
+        _species_tree = null;
+        // set title
+        setTitle( Constants.PRG_NAME + " " + Constants.VERSION + " (" + Constants.PRG_DATE + ")" );
+        _mainpanel = new MainPanel( _configuration, this );
+        // The file dialogs
+        _open_filechooser = new JFileChooser();
+        _open_filechooser.setCurrentDirectory( new File( "." ) );
+        _open_filechooser.setMultiSelectionEnabled( false );
+        _open_filechooser.addChoosableFileFilter( MainFrameApplication.xmlfilter );
+        _open_filechooser.addChoosableFileFilter( MainFrameApplication.nhxfilter );
+        _open_filechooser.addChoosableFileFilter( MainFrameApplication.nhfilter );
+        _open_filechooser.addChoosableFileFilter( MainFrameApplication.nexusfilter );
+        _open_filechooser.addChoosableFileFilter( MainFrameApplication.tolfilter );
+        _open_filechooser.addChoosableFileFilter( _open_filechooser.getAcceptAllFileFilter() );
+        _open_filechooser.setFileFilter( MainFrameApplication.defaultfilter );
+        _open_filechooser_for_species_tree = new JFileChooser();
+        _open_filechooser_for_species_tree.setCurrentDirectory( new File( "." ) );
+        _open_filechooser_for_species_tree.setMultiSelectionEnabled( false );
+        _open_filechooser_for_species_tree.addChoosableFileFilter( MainFrameApplication.xmlfilter );
+        _open_filechooser_for_species_tree.addChoosableFileFilter( MainFrameApplication.tolfilter );
+        _open_filechooser_for_species_tree.setFileFilter( MainFrameApplication.xmlfilter );
+        _save_filechooser = new JFileChooser();
+        _save_filechooser.setCurrentDirectory( new File( "." ) );
+        _save_filechooser.setMultiSelectionEnabled( false );
+        _save_filechooser.setFileFilter( MainFrameApplication.xmlfilter );
+        _save_filechooser.addChoosableFileFilter( MainFrameApplication.nhxfilter );
+        _save_filechooser.addChoosableFileFilter( MainFrameApplication.nhfilter );
+        _save_filechooser.addChoosableFileFilter( MainFrameApplication.nexusfilter );
+        _save_filechooser.addChoosableFileFilter( _save_filechooser.getAcceptAllFileFilter() );
+        _writetopdf_filechooser = new JFileChooser();
+        _writetopdf_filechooser.addChoosableFileFilter( MainFrameApplication.pdffilter );
+        _writetographics_filechooser = new JFileChooser();
+        _writetographics_filechooser.addChoosableFileFilter( MainFrameApplication.graphicsfilefilter );
+        // Msa:
+        _msa_filechooser = new JFileChooser();
+        _msa_filechooser.setName( "Read Multiple Sequence Alignment File" );
+        _msa_filechooser.setCurrentDirectory( new File( "." ) );
+        _msa_filechooser.setMultiSelectionEnabled( false );
+        _msa_filechooser.addChoosableFileFilter( _msa_filechooser.getAcceptAllFileFilter() );
+        _msa_filechooser.addChoosableFileFilter( MainFrameApplication.msafilter );
+        // Seqs:
+        _seqs_filechooser = new JFileChooser();
+        _seqs_filechooser.setName( "Read Sequences File" );
+        _seqs_filechooser.setCurrentDirectory( new File( "." ) );
+        _seqs_filechooser.setMultiSelectionEnabled( false );
+        _seqs_filechooser.addChoosableFileFilter( _seqs_filechooser.getAcceptAllFileFilter() );
+        _seqs_filechooser.addChoosableFileFilter( MainFrameApplication.seqsfilter );
+        // Expression
+        _values_filechooser = new JFileChooser();
+        _values_filechooser.setCurrentDirectory( new File( "." ) );
+        _values_filechooser.setMultiSelectionEnabled( false );
+        // build the menu bar
+        _jmenubar = new JMenuBar();
+        if ( !_configuration.isUseNativeUI() ) {
+            _jmenubar.setBackground( getConfiguration().getGuiMenuBackgroundColor() );
+        }
+        buildFileMenu();
+        if ( Constants.__ALLOW_PHYLOGENETIC_INFERENCE ) {
+            buildPhylogeneticInferenceMenu();
+        }
+        buildAnalysisMenu();
+        buildToolsMenu();
+        buildViewMenu();
+        buildFontSizeMenu();
+        buildOptionsMenu();
+        buildTypeMenu();
+        buildHelpMenu();
+        setJMenuBar( _jmenubar );
+        _jmenubar.add( _help_jmenu );
+        _contentpane = getContentPane();
+        _contentpane.setLayout( new BorderLayout() );
+        _contentpane.add( _mainpanel, BorderLayout.CENTER );
+        // App is this big
+        setSize( MainFrameApplication.FRAME_X_SIZE, MainFrameApplication.FRAME_Y_SIZE );
+        //        addWindowFocusListener( new WindowAdapter() {
+        //
+        //            @Override
+        //            public void windowGainedFocus( WindowEvent e ) {
+        //                requestFocusInWindow();
+        //            }
+        //        } );
+        // The window listener
+        setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE );
+        addWindowListener( new WindowAdapter() {
+
+            @Override
+            public void windowClosing( final WindowEvent e ) {
+                if ( isUnsavedDataPresent() ) {
+                    final int r = JOptionPane.showConfirmDialog( null,
+                                                                 "Exit despite potentially unsaved changes?",
+                                                                 "Exit?",
+                                                                 JOptionPane.YES_NO_OPTION );
+                    if ( r != JOptionPane.YES_OPTION ) {
+                        return;
+                    }
+                }
+                else {
+                    final int r = JOptionPane.showConfirmDialog( null,
+                                                                 "Exit Archaeopteryx?",
+                                                                 "Exit?",
+                                                                 JOptionPane.YES_NO_OPTION );
+                    if ( r != JOptionPane.YES_OPTION ) {
+                        return;
+                    }
+                }
+                exit();
+            }
+        } );
+        // The component listener
+        addComponentListener( new ComponentAdapter() {
+
+            @Override
+            public void componentResized( final ComponentEvent e ) {
+                if ( _mainpanel.getCurrentTreePanel() != null ) {
+                    _mainpanel.getCurrentTreePanel().setParametersForPainting( _mainpanel.getCurrentTreePanel()
+                                                                                       .getWidth(),
+                                                                               _mainpanel.getCurrentTreePanel()
+                                                                                       .getHeight(),
+                                                                               false );
+                }
+            }
+        } );
+        requestFocusInWindow();
+        // addKeyListener( this );
+        setVisible( true );
+        if ( ( phys != null ) && ( phys.length > 0 ) ) {
+            Util.addPhylogeniesToTabs( phys, title, null, _configuration, _mainpanel );
+            validate();
+            getMainPanel().getControlPanel().showWholeAll();
+            getMainPanel().getControlPanel().showWhole();
+        }
+        activateSaveAllIfNeeded();
+        // ...and its children
+        _contentpane.repaint();
+        System.gc();
+    }
+
+    private MainFrameApplication( final Phylogeny[] phys, final String config_file, final String title ) {
+        // Reads the config file (false, false => not url, not applet):
+        this( phys, new Configuration( config_file, false, false ), title );
+    }
+
+    @Override
+    public void actionPerformed( final ActionEvent e ) {
+        try {
+            super.actionPerformed( e );
+            final Object o = e.getSource();
+            // Handle app-specific actions here:
+            if ( o == _open_item ) {
+                readPhylogeniesFromFile();
+            }
+            else if ( o == _save_item ) {
+                writeToFile( _mainpanel.getCurrentPhylogeny() );
+                // If subtree currently displayed, save it, instead of complete
+                // tree.
+            }
+            else if ( o == _new_item ) {
+                newTree();
+            }
+            else if ( o == _save_all_item ) {
+                writeAllToFile();
+            }
+            else if ( o == _close_item ) {
+                closeCurrentPane();
+            }
+            else if ( o == _write_to_pdf_item ) {
+                writeToPdf( _mainpanel.getCurrentPhylogeny() );
+            }
+            else if ( o == _write_to_jpg_item ) {
+                writeToGraphicsFile( _mainpanel.getCurrentPhylogeny(), GraphicsExportType.JPG );
+            }
+            else if ( o == _write_to_png_item ) {
+                writeToGraphicsFile( _mainpanel.getCurrentPhylogeny(), GraphicsExportType.PNG );
+            }
+            else if ( o == _write_to_gif_item ) {
+                writeToGraphicsFile( _mainpanel.getCurrentPhylogeny(), GraphicsExportType.GIF );
+            }
+            else if ( o == _write_to_tif_item ) {
+                writeToGraphicsFile( _mainpanel.getCurrentPhylogeny(), GraphicsExportType.TIFF );
+            }
+            else if ( o == _write_to_bmp_item ) {
+                writeToGraphicsFile( _mainpanel.getCurrentPhylogeny(), GraphicsExportType.BMP );
+            }
+            else if ( o == _print_item ) {
+                print();
+            }
+            else if ( o == _load_species_tree_item ) {
+                readSpeciesTreeFromFile();
+            }
+            else if ( o == _sdi_item ) {
+                if ( isSubtreeDisplayed() ) {
+                    return;
+                }
+                executeSDI();
+            }
+            else if ( o == _lineage_inference ) {
+                if ( isSubtreeDisplayed() ) {
+                    JOptionPane.showMessageDialog( this,
+                                                   "Subtree is shown.",
+                                                   "Cannot infer ancestral taxonomies",
+                                                   JOptionPane.ERROR_MESSAGE );
+                    return;
+                }
+                executeLineageInference();
+            }
+            else if ( o == _function_analysis ) {
+                executeFunctionAnalysis();
+            }
+            else if ( o == _obtain_detailed_taxonomic_information_jmi ) {
+                if ( isSubtreeDisplayed() ) {
+                    return;
+                }
+                obtainDetailedTaxonomicInformation();
+            }
+            else if ( o == _read_values_jmi ) {
+                if ( isSubtreeDisplayed() ) {
+                    return;
+                }
+                addExpressionValuesFromFile();
+            }
+            else if ( o == _move_node_names_to_tax_sn_jmi ) {
+                moveNodeNamesToTaxSn();
+            }
+            else if ( o == _move_node_names_to_seq_names_jmi ) {
+                moveNodeNamesToSeqNames();
+            }
+            else if ( o == _extract_tax_code_from_node_names_jmi ) {
+                extractTaxCodeFromNodeNames();
+            }
+            else if ( o == _gsdi_item ) {
+                if ( isSubtreeDisplayed() ) {
+                    return;
+                }
+                executeGSDI();
+            }
+            else if ( o == _root_min_dups_item ) {
+                if ( isSubtreeDisplayed() ) {
+                    return;
+                }
+                executeSDIR( false );
+            }
+            else if ( o == _root_min_cost_l_item ) {
+                if ( isSubtreeDisplayed() ) {
+                    return;
+                }
+                executeSDIR( true );
+            }
+            else if ( o == _graphics_export_visible_only_cbmi ) {
+                updateOptions( getOptions() );
+            }
+            else if ( o == _antialias_print_cbmi ) {
+                updateOptions( getOptions() );
+            }
+            else if ( o == _print_black_and_white_cbmi ) {
+                updateOptions( getOptions() );
+            }
+            else if ( o == _print_using_actual_size_cbmi ) {
+                updateOptions( getOptions() );
+            }
+            else if ( o == _graphics_export_using_actual_size_cbmi ) {
+                updateOptions( getOptions() );
+            }
+            else if ( o == _print_size_mi ) {
+                choosePrintSize();
+            }
+            else if ( o == _choose_pdf_width_mi ) {
+                choosePdfWidth();
+            }
+            else if ( o == _internal_number_are_confidence_for_nh_parsing_cbmi ) {
+                updateOptions( getOptions() );
+            }
+            else if ( o == _replace_underscores_cbmi ) {
+                if ( ( _extract_pfam_style_tax_codes_cbmi != null ) && _replace_underscores_cbmi.isSelected() ) {
+                    _extract_pfam_style_tax_codes_cbmi.setSelected( false );
+                }
+                updateOptions( getOptions() );
+            }
+            else if ( o == _collapse_below_threshold ) {
+                if ( isSubtreeDisplayed() ) {
+                    return;
+                }
+                collapseBelowThreshold();
+            }
+            else if ( o == _extract_pfam_style_tax_codes_cbmi ) {
+                if ( ( _replace_underscores_cbmi != null ) && _extract_pfam_style_tax_codes_cbmi.isSelected() ) {
+                    _replace_underscores_cbmi.setSelected( false );
+                }
+                updateOptions( getOptions() );
+            }
+            else if ( o == _inference_from_msa_item ) {
+                executePhyleneticInference( false );
+            }
+            else if ( o == _inference_from_seqs_item ) {
+                executePhyleneticInference( true );
+            }
+            _contentpane.repaint();
+        }
+        catch ( final Exception ex ) {
+            Util.unexpectedException( ex );
+        }
+        catch ( final Error err ) {
+            Util.unexpectedError( err );
+        }
+    }
+
+    void buildAnalysisMenu() {
+        _analysis_menu = MainFrame.createMenu( "Analysis", getConfiguration() );
+        _analysis_menu.add( _sdi_item = new JMenuItem( "SDI (Speciation Duplication Inference)" ) );
+        if ( !Constants.__RELEASE && !Constants.__SNAPSHOT_RELEASE ) {
+            _analysis_menu.add( _gsdi_item = new JMenuItem( "GSDI (Generalized Speciation Duplication Inference)" ) );
+        }
+        _analysis_menu.addSeparator();
+        _analysis_menu.add( _root_min_dups_item = new JMenuItem( "Root by Minimizing Duplications | Height (SDI)" ) );
+        _analysis_menu.add( _root_min_cost_l_item = new JMenuItem( "Root by Minimizing Cost L | Height (SDI)" ) );
+        _analysis_menu.addSeparator();
+        _analysis_menu.add( _load_species_tree_item = new JMenuItem( "Load Species Tree..." ) );
+        customizeJMenuItem( _sdi_item );
+        customizeJMenuItem( _gsdi_item );
+        customizeJMenuItem( _root_min_dups_item );
+        customizeJMenuItem( _root_min_cost_l_item );
+        customizeJMenuItem( _load_species_tree_item );
+        _analysis_menu.addSeparator();
+        _analysis_menu.add( _lineage_inference = new JMenuItem( "Infer Ancestor Taxonomies" ) );
+        customizeJMenuItem( _lineage_inference );
+        _lineage_inference.setToolTipText( "Inference of ancestor taxonomies/lineages" );
+        _jmenubar.add( _analysis_menu );
+    }
+
+    void buildPhylogeneticInferenceMenu() {
+        _inference_menu = MainFrame.createMenu( "Inference", getConfiguration() );
+        _inference_menu
+                .add( _inference_from_msa_item = new JMenuItem( "From Multiple Sequence Alignment...(EXPERIMENTAL - DO NOT USE!!) " ) );
+        customizeJMenuItem( _inference_from_msa_item );
+        _inference_from_msa_item.setToolTipText( "Basic phylogenetic inference from MSA" );
+        _inference_menu
+                .add( _inference_from_seqs_item = new JMenuItem( "From Unaligned Sequences...(EXPERIMENTAL - DO NOT USE!!) " ) );
+        customizeJMenuItem( _inference_from_seqs_item );
+        _inference_from_seqs_item.setToolTipText( "Basic phylogenetic inference including multiple sequence alignment" );
+        _jmenubar.add( _inference_menu );
+    }
+
+    @Override
+    void buildFileMenu() {
+        _file_jmenu = MainFrame.createMenu( "File", getConfiguration() );
+        _file_jmenu.add( _open_item = new JMenuItem( "Read Tree from File..." ) );
+        _file_jmenu.addSeparator();
+        _file_jmenu.add( _open_url_item = new JMenuItem( "Read Tree from URL/Webservice..." ) );
+        _file_jmenu.addSeparator();
+        final WebservicesManager webservices_manager = WebservicesManager.getInstance();
+        _load_phylogeny_from_webservice_menu_items = new JMenuItem[ webservices_manager
+                .getAvailablePhylogeniesWebserviceClients().size() ];
+        for( int i = 0; i < webservices_manager.getAvailablePhylogeniesWebserviceClients().size(); ++i ) {
+            final PhylogeniesWebserviceClient client = webservices_manager.getAvailablePhylogeniesWebserviceClient( i );
+            _load_phylogeny_from_webservice_menu_items[ i ] = new JMenuItem( client.getMenuName() );
+            _file_jmenu.add( _load_phylogeny_from_webservice_menu_items[ i ] );
+        }
+        if ( getConfiguration().isEditable() ) {
+            _file_jmenu.addSeparator();
+            _file_jmenu.add( _new_item = new JMenuItem( "New" ) );
+            _new_item.setToolTipText( "to create a new tree with one node, as source for manual tree construction" );
+        }
+        _file_jmenu.addSeparator();
+        _file_jmenu.add( _save_item = new JMenuItem( "Save Tree As..." ) );
+        _file_jmenu.add( _save_all_item = new JMenuItem( "Save All Trees As..." ) );
+        _save_all_item.setToolTipText( "Write all phylogenies to one file." );
+        _save_all_item.setEnabled( false );
+        _file_jmenu.addSeparator();
+        _file_jmenu.add( _write_to_pdf_item = new JMenuItem( "Export to PDF file ..." ) );
+        if ( Util.canWriteFormat( "tif" ) || Util.canWriteFormat( "tiff" ) || Util.canWriteFormat( "TIF" ) ) {
+            _file_jmenu.add( _write_to_tif_item = new JMenuItem( "Export to TIFF file..." ) );
+        }
+        _file_jmenu.add( _write_to_png_item = new JMenuItem( "Export to PNG file..." ) );
+        _file_jmenu.add( _write_to_jpg_item = new JMenuItem( "Export to JPG file..." ) );
+        if ( Util.canWriteFormat( "gif" ) ) {
+            _file_jmenu.add( _write_to_gif_item = new JMenuItem( "Export to GIF file..." ) );
+        }
+        if ( Util.canWriteFormat( "bmp" ) ) {
+            _file_jmenu.add( _write_to_bmp_item = new JMenuItem( "Export to BMP file..." ) );
+        }
+        _file_jmenu.addSeparator();
+        _file_jmenu.add( _print_item = new JMenuItem( "Print..." ) );
+        _file_jmenu.addSeparator();
+        _file_jmenu.add( _close_item = new JMenuItem( "Close Tab" ) );
+        _close_item.setToolTipText( "To close the current pane." );
+        _close_item.setEnabled( true );
+        _file_jmenu.addSeparator();
+        _file_jmenu.add( _exit_item = new JMenuItem( "Exit" ) );
+        // For print in color option item
+        customizeJMenuItem( _open_item );
+        _open_item
+                .setFont( new Font( _open_item.getFont().getFontName(), Font.BOLD, _open_item.getFont().getSize() + 4 ) );
+        customizeJMenuItem( _open_url_item );
+        for( int i = 0; i < webservices_manager.getAvailablePhylogeniesWebserviceClients().size(); ++i ) {
+            customizeJMenuItem( _load_phylogeny_from_webservice_menu_items[ i ] );
+        }
+        customizeJMenuItem( _save_item );
+        if ( getConfiguration().isEditable() ) {
+            customizeJMenuItem( _new_item );
+        }
+        customizeJMenuItem( _close_item );
+        customizeJMenuItem( _save_all_item );
+        customizeJMenuItem( _write_to_pdf_item );
+        customizeJMenuItem( _write_to_png_item );
+        customizeJMenuItem( _write_to_jpg_item );
+        customizeJMenuItem( _write_to_gif_item );
+        customizeJMenuItem( _write_to_tif_item );
+        customizeJMenuItem( _write_to_bmp_item );
+        customizeJMenuItem( _print_item );
+        customizeJMenuItem( _exit_item );
+        _jmenubar.add( _file_jmenu );
+    }
+
+    void buildOptionsMenu() {
+        _options_jmenu = MainFrame.createMenu( OPTIONS_HEADER, getConfiguration() );
+        _options_jmenu.addChangeListener( new ChangeListener() {
+
+            @Override
+            public void stateChanged( final ChangeEvent e ) {
+                MainFrame.setOvPlacementColorChooseMenuItem( _overview_placment_mi, getCurrentTreePanel() );
+                MainFrame.setTextColorChooseMenuItem( _switch_colors_mi, getCurrentTreePanel() );
+                MainFrame
+                        .setTextMinSupportMenuItem( _choose_minimal_confidence_mi, getOptions(), getCurrentTreePanel() );
+                MainFrame.setTextForFontChooserMenuItem( _choose_font_mi, MainFrame
+                        .createCurrentFontDesc( getMainPanel().getTreeFontSet() ) );
+                setTextForGraphicsSizeChooserMenuItem( _print_size_mi, getOptions() );
+                setTextForPdfLineWidthChooserMenuItem( _choose_pdf_width_mi, getOptions() );
+                MainFrame.updateOptionsMenuDependingOnPhylogenyType( getMainPanel(),
+                                                                     _show_scale_cbmi,
+                                                                     _show_branch_length_values_cbmi,
+                                                                     _non_lined_up_cladograms_rbmi,
+                                                                     _uniform_cladograms_rbmi,
+                                                                     _ext_node_dependent_cladogram_rbmi,
+                                                                     _label_direction_cbmi );
+            }
+        } );
+        _options_jmenu.add( customizeMenuItemAsLabel( new JMenuItem( DISPLAY_SUBHEADER ), getConfiguration() ) );
+        _options_jmenu
+                .add( _ext_node_dependent_cladogram_rbmi = new JRadioButtonMenuItem( MainFrame.NONUNIFORM_CLADOGRAMS_LABEL ) );
+        _options_jmenu.add( _uniform_cladograms_rbmi = new JRadioButtonMenuItem( MainFrame.UNIFORM_CLADOGRAMS_LABEL ) );
+        _options_jmenu.add( _non_lined_up_cladograms_rbmi = new JRadioButtonMenuItem( NON_LINED_UP_CLADOGRAMS_LABEL ) );
+        _radio_group_1 = new ButtonGroup();
+        _radio_group_1.add( _ext_node_dependent_cladogram_rbmi );
+        _radio_group_1.add( _uniform_cladograms_rbmi );
+        _radio_group_1.add( _non_lined_up_cladograms_rbmi );
+        _options_jmenu.add( _show_node_boxes_cbmi = new JCheckBoxMenuItem( DISPLAY_NODE_BOXES_LABEL ) );
+        _options_jmenu.add( _show_scale_cbmi = new JCheckBoxMenuItem( DISPLAY_SCALE_LABEL ) );
+        _options_jmenu
+                .add( _show_branch_length_values_cbmi = new JCheckBoxMenuItem( DISPLAY_BRANCH_LENGTH_VALUES_LABEL ) );
+        _options_jmenu.add( _show_overview_cbmi = new JCheckBoxMenuItem( SHOW_OVERVIEW_LABEL ) );
+        _options_jmenu.add( _label_direction_cbmi = new JCheckBoxMenuItem( LABEL_DIRECTION_LABEL ) );
+        _label_direction_cbmi.setToolTipText( LABEL_DIRECTION_TIP );
+        _options_jmenu.add( _color_labels_same_as_parent_branch = new JCheckBoxMenuItem( COLOR_LABELS_LABEL ) );
+        _color_labels_same_as_parent_branch.setToolTipText( MainFrame.COLOR_LABELS_TIP );
+        _options_jmenu.add( _abbreviate_scientific_names = new JCheckBoxMenuItem( ABBREV_SN_LABEL ) );
+        _options_jmenu.add( _screen_antialias_cbmi = new JCheckBoxMenuItem( SCREEN_ANTIALIAS_LABEL ) );
+        _options_jmenu.add( _background_gradient_cbmi = new JCheckBoxMenuItem( BG_GRAD_LABEL ) );
+        if ( getConfiguration().doDisplayOption( Configuration.show_domain_architectures ) ) {
+            _options_jmenu.add( _show_domain_labels = new JCheckBoxMenuItem( SHOW_DOMAIN_LABELS_LABEL ) );
+        }
+        _options_jmenu.add( _choose_minimal_confidence_mi = new JMenuItem( "" ) );
+        _options_jmenu.add( _overview_placment_mi = new JMenuItem( "" ) );
+        _options_jmenu.add( _switch_colors_mi = new JMenuItem( "" ) );
+        _options_jmenu.add( _choose_font_mi = new JMenuItem( "" ) );
+        _options_jmenu.addSeparator();
+        _options_jmenu.add( customizeMenuItemAsLabel( new JMenuItem( SEARCH_SUBHEADER ), getConfiguration() ) );
+        _options_jmenu.add( _search_case_senstive_cbmi = new JCheckBoxMenuItem( SEARCH_CASE_SENSITIVE_LABEL ) );
+        _options_jmenu.add( _search_whole_words_only_cbmi = new JCheckBoxMenuItem( SEARCH_TERMS_ONLY_LABEL ) );
+        _options_jmenu.add( _inverse_search_result_cbmi = new JCheckBoxMenuItem( INVERSE_SEARCH_RESULT_LABEL ) );
+        _options_jmenu.addSeparator();
+        _options_jmenu.add( customizeMenuItemAsLabel( new JMenuItem( "Graphics Export & Printing:" ),
+                                                      getConfiguration() ) );
+        _options_jmenu.add( _antialias_print_cbmi = new JCheckBoxMenuItem( "Antialias" ) );
+        _options_jmenu.add( _print_black_and_white_cbmi = new JCheckBoxMenuItem( "Export in Black and White" ) );
+        _options_jmenu
+                .add( _print_using_actual_size_cbmi = new JCheckBoxMenuItem( "Use Current Image Size for PDF export and Printing" ) );
+        _options_jmenu
+                .add( _graphics_export_using_actual_size_cbmi = new JCheckBoxMenuItem( "Use Current Image Size for PNG, JPG, and GIF export" ) );
+        _options_jmenu
+                .add( _graphics_export_visible_only_cbmi = new JCheckBoxMenuItem( "Limit to Visible ('Screenshot') for PNG, JPG, and GIF export" ) );
+        _options_jmenu.add( _print_size_mi = new JMenuItem( "" ) );
+        _options_jmenu.add( _choose_pdf_width_mi = new JMenuItem( "" ) );
+        _options_jmenu.addSeparator();
+        _options_jmenu
+                .add( customizeMenuItemAsLabel( new JMenuItem( "Newick/NHX/Nexus Parsing:" ), getConfiguration() ) );
+        _options_jmenu
+                .add( _internal_number_are_confidence_for_nh_parsing_cbmi = new JCheckBoxMenuItem( "Internal Numbers Are Confidence Values" ) );
+        _options_jmenu.add( _replace_underscores_cbmi = new JCheckBoxMenuItem( "Replace Underscores with Spaces" ) );
+        _options_jmenu
+                .add( _extract_pfam_style_tax_codes_cbmi = new JCheckBoxMenuItem( "Extract Taxonomy Codes from Pfam-style Labels" ) );
+        customizeJMenuItem( _choose_font_mi );
+        customizeJMenuItem( _choose_minimal_confidence_mi );
+        customizeJMenuItem( _switch_colors_mi );
+        customizeJMenuItem( _print_size_mi );
+        customizeJMenuItem( _choose_pdf_width_mi );
+        customizeJMenuItem( _overview_placment_mi );
+        customizeCheckBoxMenuItem( _show_node_boxes_cbmi, getOptions().isShowNodeBoxes() );
+        customizeCheckBoxMenuItem( _color_labels_same_as_parent_branch, getOptions().isColorLabelsSameAsParentBranch() );
+        customizeCheckBoxMenuItem( _screen_antialias_cbmi, getOptions().isAntialiasScreen() );
+        customizeCheckBoxMenuItem( _background_gradient_cbmi, getOptions().isBackgroundColorGradient() );
+        customizeCheckBoxMenuItem( _show_domain_labels, getOptions().isShowDomainLabels() );
+        customizeCheckBoxMenuItem( _abbreviate_scientific_names, getOptions().isAbbreviateScientificTaxonNames() );
+        customizeCheckBoxMenuItem( _search_case_senstive_cbmi, getOptions().isSearchCaseSensitive() );
+        customizeCheckBoxMenuItem( _show_scale_cbmi, getOptions().isShowScale() );
+        customizeRadioButtonMenuItem( _non_lined_up_cladograms_rbmi,
+                                      getOptions().getCladogramType() == CLADOGRAM_TYPE.NON_LINED_UP );
+        customizeRadioButtonMenuItem( _uniform_cladograms_rbmi,
+                                      getOptions().getCladogramType() == CLADOGRAM_TYPE.TOTAL_NODE_SUM_DEP );
+        customizeRadioButtonMenuItem( _ext_node_dependent_cladogram_rbmi,
+                                      getOptions().getCladogramType() == CLADOGRAM_TYPE.EXT_NODE_SUM_DEP );
+        customizeCheckBoxMenuItem( _show_branch_length_values_cbmi, getOptions().isShowBranchLengthValues() );
+        customizeCheckBoxMenuItem( _show_overview_cbmi, getOptions().isShowOverview() );
+        customizeCheckBoxMenuItem( _label_direction_cbmi,
+                                   getOptions().getNodeLabelDirection() == NODE_LABEL_DIRECTION.RADIAL );
+        customizeCheckBoxMenuItem( _antialias_print_cbmi, getOptions().isAntialiasPrint() );
+        customizeCheckBoxMenuItem( _print_black_and_white_cbmi, getOptions().isPrintBlackAndWhite() );
+        customizeCheckBoxMenuItem( _internal_number_are_confidence_for_nh_parsing_cbmi, getOptions()
+                .isInternalNumberAreConfidenceForNhParsing() );
+        customizeCheckBoxMenuItem( _extract_pfam_style_tax_codes_cbmi, getOptions()
+                .isExtractPfamTaxonomyCodesInNhParsing() );
+        customizeCheckBoxMenuItem( _replace_underscores_cbmi, getOptions().isReplaceUnderscoresInNhParsing() );
+        customizeCheckBoxMenuItem( _search_whole_words_only_cbmi, getOptions().isMatchWholeTermsOnly() );
+        customizeCheckBoxMenuItem( _inverse_search_result_cbmi, getOptions().isInverseSearchResult() );
+        customizeCheckBoxMenuItem( _graphics_export_visible_only_cbmi, getOptions().isGraphicsExportVisibleOnly() );
+        customizeCheckBoxMenuItem( _print_using_actual_size_cbmi, getOptions().isPrintUsingActualSize() );
+        customizeCheckBoxMenuItem( _graphics_export_using_actual_size_cbmi, getOptions()
+                .isGraphicsExportUsingActualSize() );
+        _jmenubar.add( _options_jmenu );
+    }
+
+    void buildToolsMenu() {
+        _tools_menu = createMenu( "Tools", getConfiguration() );
+        _tools_menu.add( _confcolor_item = new JMenuItem( "Colorize Branches Depending on Confidence" ) );
+        customizeJMenuItem( _confcolor_item );
+        _tools_menu.add( _taxcolor_item = new JMenuItem( "Taxonomy Colorize Branches" ) );
+        customizeJMenuItem( _taxcolor_item );
+        _tools_menu.add( _remove_branch_color_item = new JMenuItem( "Delete Branch Colors" ) );
+        _remove_branch_color_item.setToolTipText( "To delete branch color values from the current phylogeny" );
+        customizeJMenuItem( _remove_branch_color_item );
+        _tools_menu.addSeparator();
+        _tools_menu.add( _midpoint_root_item = new JMenuItem( "Midpoint-Root" ) );
+        customizeJMenuItem( _midpoint_root_item );
+        _tools_menu.addSeparator();
+        _tools_menu.add( _collapse_species_specific_subtrees = new JMenuItem( "Collapse Species-Specific Subtrees" ) );
+        customizeJMenuItem( _collapse_species_specific_subtrees );
+        _tools_menu
+                .add( _collapse_below_threshold = new JMenuItem( "Collapse Branches with Confidence Below Threshold" ) );
+        customizeJMenuItem( _collapse_below_threshold );
+        _collapse_below_threshold
+                .setToolTipText( "To permanently collapse branches without at least one support value above a given threshold" );
+        _tools_menu.addSeparator();
+        _tools_menu
+                .add( _move_node_names_to_tax_sn_jmi = new JMenuItem( "Transfer Node Names to Taxonomic Scientific Names" ) );
+        customizeJMenuItem( _move_node_names_to_tax_sn_jmi );
+        _move_node_names_to_tax_sn_jmi.setToolTipText( "To interpret node names as taxonomic scientific names" );
+        _tools_menu.add( _move_node_names_to_seq_names_jmi = new JMenuItem( "Transfer Node Names to Sequence Names" ) );
+        customizeJMenuItem( _move_node_names_to_seq_names_jmi );
+        _move_node_names_to_seq_names_jmi.setToolTipText( "To interpret node names as sequence (protein, gene) names" );
+        _tools_menu
+                .add( _extract_tax_code_from_node_names_jmi = new JMenuItem( "Extract Taxonomic Codes from Node Names" ) );
+        customizeJMenuItem( _extract_tax_code_from_node_names_jmi );
+        _extract_tax_code_from_node_names_jmi
+                .setToolTipText( "To extract taxonomic codes (mnemonics) from nodes names in the form of 'xyz_ECOLI'" );
+        _tools_menu.addSeparator();
+        _tools_menu
+                .add( _infer_common_sn_names_item = new JMenuItem( "Infer Common Parts of Internal Scientific Names" ) );
+        customizeJMenuItem( _infer_common_sn_names_item );
+        _tools_menu.addSeparator();
+        _tools_menu
+                .add( _obtain_detailed_taxonomic_information_jmi = new JMenuItem( "Obtain Detailed Taxonomic Information" ) );
+        customizeJMenuItem( _obtain_detailed_taxonomic_information_jmi );
+        _obtain_detailed_taxonomic_information_jmi
+                .setToolTipText( "To add additional taxonomic information (from UniProt Taxonomy)" );
+        _tools_menu.addSeparator();
+        if ( !Constants.__RELEASE ) {
+            _tools_menu.add( _function_analysis = new JMenuItem( "Add UniProtKB Annotations" ) );
+            customizeJMenuItem( _function_analysis );
+            _function_analysis
+                    .setToolTipText( "To add UniProtKB annotations for sequences with appropriate identifiers" );
+            _tools_menu.addSeparator();
+        }
+        _tools_menu.add( _read_values_jmi = new JMenuItem( "Read Vector/Expression Values" ) );
+        customizeJMenuItem( _read_values_jmi );
+        _read_values_jmi.setToolTipText( "To add vector (e.g. gene expression) values (beta)" );
+        _jmenubar.add( _tools_menu );
+    }
+
+    private void choosePdfWidth() {
+        final String s = ( String ) JOptionPane.showInputDialog( this,
+                                                                 "Please enter the default line width for PDF export.\n"
+                                                                         + "[current value: "
+                                                                         + getOptions().getPrintLineWidth() + "]\n",
+                                                                 "Line Width for PDF Export",
+                                                                 JOptionPane.QUESTION_MESSAGE,
+                                                                 null,
+                                                                 null,
+                                                                 getOptions().getPrintLineWidth() );
+        if ( !ForesterUtil.isEmpty( s ) ) {
+            boolean success = true;
+            float f = 0.0f;
+            final String m_str = s.trim();
+            if ( !ForesterUtil.isEmpty( m_str ) ) {
+                try {
+                    f = Float.parseFloat( m_str );
+                }
+                catch ( final Exception ex ) {
+                    success = false;
+                }
+            }
+            else {
+                success = false;
+            }
+            if ( success && ( f > 0.0 ) ) {
+                getOptions().setPrintLineWidth( f );
+            }
+        }
+    }
+
+    private void choosePrintSize() {
+        final String s = ( String ) JOptionPane.showInputDialog( this,
+                                                                 "Please enter values for width and height,\nseparated by a comma.\n"
+                                                                         + "[current values: "
+                                                                         + getOptions().getPrintSizeX() + ", "
+                                                                         + getOptions().getPrintSizeY() + "]\n"
+                                                                         + "[A4: " + Constants.A4_SIZE_X + ", "
+                                                                         + Constants.A4_SIZE_Y + "]\n" + "[US Letter: "
+                                                                         + Constants.US_LETTER_SIZE_X + ", "
+                                                                         + Constants.US_LETTER_SIZE_Y + "]",
+                                                                 "Default Size for Graphics Export",
+                                                                 JOptionPane.QUESTION_MESSAGE,
+                                                                 null,
+                                                                 null,
+                                                                 getOptions().getPrintSizeX() + ", "
+                                                                         + getOptions().getPrintSizeY() );
+        if ( !ForesterUtil.isEmpty( s ) && ( s.indexOf( ',' ) > 0 ) ) {
+            boolean success = true;
+            int x = 0;
+            int y = 0;
+            final String[] str_ary = s.split( "," );
+            if ( str_ary.length == 2 ) {
+                final String x_str = str_ary[ 0 ].trim();
+                final String y_str = str_ary[ 1 ].trim();
+                if ( !ForesterUtil.isEmpty( x_str ) && !ForesterUtil.isEmpty( y_str ) ) {
+                    try {
+                        x = Integer.parseInt( x_str );
+                        y = Integer.parseInt( y_str );
+                    }
+                    catch ( final Exception ex ) {
+                        success = false;
+                    }
+                }
+                else {
+                    success = false;
+                }
+            }
+            else {
+                success = false;
+            }
+            if ( success && ( x > 1 ) && ( y > 1 ) ) {
+                getOptions().setPrintSizeX( x );
+                getOptions().setPrintSizeY( y );
+            }
+        }
+    }
+
+    @Override
+    void close() {
+        if ( isUnsavedDataPresent() ) {
+            final int r = JOptionPane.showConfirmDialog( this,
+                                                         "Exit despite potentially unsaved changes?",
+                                                         "Exit?",
+                                                         JOptionPane.YES_NO_OPTION );
+            if ( r != JOptionPane.YES_OPTION ) {
+                return;
+            }
+        }
+        exit();
+    }
+
+    private void closeCurrentPane() {
+        if ( getMainPanel().getCurrentTreePanel() != null ) {
+            if ( getMainPanel().getCurrentTreePanel().isEdited() ) {
+                final int r = JOptionPane.showConfirmDialog( this,
+                                                             "Close tab despite potentially unsaved changes?",
+                                                             "Close Tab?",
+                                                             JOptionPane.YES_NO_OPTION );
+                if ( r != JOptionPane.YES_OPTION ) {
+                    return;
+                }
+            }
+            getMainPanel().closeCurrentPane();
+            activateSaveAllIfNeeded();
+        }
+    }
+
+    private void collapse( final Phylogeny phy, final double m ) {
+        final PhylogenyNodeIterator it = phy.iteratorPostorder();
+        final List<PhylogenyNode> to_be_removed = new ArrayList<PhylogenyNode>();
+        double min_support = Double.MAX_VALUE;
+        boolean conf_present = false;
+        while ( it.hasNext() ) {
+            final PhylogenyNode n = it.next();
+            if ( !n.isExternal() && !n.isRoot() ) {
+                final List<Confidence> c = n.getBranchData().getConfidences();
+                if ( ( c != null ) && ( c.size() > 0 ) ) {
+                    conf_present = true;
+                    double max = 0;
+                    for( final Confidence confidence : c ) {
+                        if ( confidence.getValue() > max ) {
+                            max = confidence.getValue();
+                        }
+                    }
+                    if ( max < getMinNotCollapseConfidenceValue() ) {
+                        to_be_removed.add( n );
+                    }
+                    if ( max < min_support ) {
+                        min_support = max;
+                    }
+                }
+            }
+        }
+        if ( conf_present ) {
+            for( final PhylogenyNode node : to_be_removed ) {
+                PhylogenyMethods.removeNode( node, phy );
+            }
+            if ( to_be_removed.size() > 0 ) {
+                phy.externalNodesHaveChanged();
+                phy.hashIDs();
+                phy.recalculateNumberOfExternalDescendants( true );
+                getCurrentTreePanel().resetNodeIdToDistToLeafMap();
+                getCurrentTreePanel().setEdited( true );
+                getCurrentTreePanel().repaint();
+            }
+            if ( to_be_removed.size() > 0 ) {
+                JOptionPane.showMessageDialog( this, "Collapsed " + to_be_removed.size()
+                        + " branches with\nconfidence values below " + getMinNotCollapseConfidenceValue(), "Collapsed "
+                        + to_be_removed.size() + " branches", JOptionPane.INFORMATION_MESSAGE );
+            }
+            else {
+                JOptionPane.showMessageDialog( this, "No branch collapsed,\nminimum confidence value per branch is "
+                        + min_support, "No branch collapsed", JOptionPane.INFORMATION_MESSAGE );
+            }
+        }
+        else {
+            JOptionPane.showMessageDialog( this,
+                                           "No branch collapsed because no confidence values present",
+                                           "No confidence values present",
+                                           JOptionPane.INFORMATION_MESSAGE );
+        }
+    }
+
+    private void collapseBelowThreshold() {
+        if ( getCurrentTreePanel() != null ) {
+            final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
+            if ( ( phy != null ) && !phy.isEmpty() ) {
+                final String s = ( String ) JOptionPane.showInputDialog( this,
+                                                                         "Please enter the minimum confidence value\n",
+                                                                         "Minimal Confidence Value",
+                                                                         JOptionPane.QUESTION_MESSAGE,
+                                                                         null,
+                                                                         null,
+                                                                         getMinNotCollapseConfidenceValue() );
+                if ( !ForesterUtil.isEmpty( s ) ) {
+                    boolean success = true;
+                    double m = 0.0;
+                    final String m_str = s.trim();
+                    if ( !ForesterUtil.isEmpty( m_str ) ) {
+                        try {
+                            m = Double.parseDouble( m_str );
+                        }
+                        catch ( final Exception ex ) {
+                            success = false;
+                        }
+                    }
+                    else {
+                        success = false;
+                    }
+                    if ( success && ( m >= 0.0 ) ) {
+                        setMinNotCollapseConfidenceValue( m );
+                        collapse( phy, m );
+                    }
+                }
+            }
+        }
+    }
+
+    private PhyloXmlParser createPhyloXmlParser() {
+        PhyloXmlParser xml_parser = null;
+        if ( getConfiguration().isValidatePhyloXmlAgainstSchema() ) {
+            try {
+                xml_parser = PhyloXmlParser.createPhyloXmlParserXsdValidating();
+            }
+            catch ( final Exception e ) {
+                JOptionPane.showMessageDialog( this,
+                                               e.getLocalizedMessage(),
+                                               "failed to create validating XML parser",
+                                               JOptionPane.WARNING_MESSAGE );
+            }
+        }
+        if ( xml_parser == null ) {
+            xml_parser = new PhyloXmlParser();
+        }
+        return xml_parser;
+    }
+
+    void executeGSDI() {
+        if ( !isOKforSDI( false, true ) ) {
+            return;
+        }
+        if ( !_mainpanel.getCurrentPhylogeny().isRooted() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Gene tree is not rooted.",
+                                           "Cannot execute GSDI",
+                                           JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        final Phylogeny gene_tree = _mainpanel.getCurrentPhylogeny().copy();
+        gene_tree.setAllNodesToNotCollapse();
+        gene_tree.recalculateNumberOfExternalDescendants( false );
+        GSDI gsdi = null;
+        int duplications = -1;
+        try {
+            gsdi = new GSDI( gene_tree, _species_tree.copy(), true );
+            duplications = gsdi.getDuplicationsSum();
+        }
+        catch ( final Exception e ) {
+            JOptionPane.showMessageDialog( this, e.toString(), "Error during GSDI", JOptionPane.ERROR_MESSAGE );
+        }
+        gene_tree.setRerootable( false );
+        _mainpanel.getCurrentTreePanel().setTree( gene_tree );
+        getControlPanel().setShowEvents( true );
+        showWhole();
+        _mainpanel.getCurrentTreePanel().setEdited( true );
+        JOptionPane.showMessageDialog( this,
+                                       "Number of duplications: " + duplications,
+                                       "GSDI successfully completed",
+                                       JOptionPane.INFORMATION_MESSAGE );
+    }
+
+    void executeFunctionAnalysis() {
+        if ( ( _mainpanel.getCurrentPhylogeny() == null ) || ( _mainpanel.getCurrentPhylogeny().isEmpty() ) ) {
+            return;
+        }
+        final MainPanelEdit a = new MainPanelEdit( this, _mainpanel.getCurrentTreePanel(), _mainpanel
+                .getCurrentPhylogeny() );
+        new Thread( a ).start();
+    }
+
+    void executeLineageInference() {
+        if ( ( _mainpanel.getCurrentPhylogeny() == null ) || ( _mainpanel.getCurrentPhylogeny().isEmpty() ) ) {
+            return;
+        }
+        if ( !_mainpanel.getCurrentPhylogeny().isRooted() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Phylogeny is not rooted.",
+                                           "Cannot infer ancestral taxonomies",
+                                           JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        final Phylogeny phy = _mainpanel.getCurrentPhylogeny().copy();
+        final AncestralTaxonomyInferrer inferrer = new AncestralTaxonomyInferrer( this, _mainpanel
+                .getCurrentTreePanel(), phy );
+        new Thread( inferrer ).start();
+    }
+
+    private void executePhyleneticInference( final boolean from_unaligned_seqs ) {
+        final PhyloInferenceDialog dialog = new PhyloInferenceDialog( this,
+                                                                      getPhylogeneticInferenceOptions(),
+                                                                      from_unaligned_seqs );
+        dialog.activate();
+        if ( dialog.getValue() == JOptionPane.OK_OPTION ) {
+            if ( !from_unaligned_seqs ) {
+                if ( getMsa() != null ) {
+                    final PhylogeneticInferrer inferrer = new PhylogeneticInferrer( getMsa(),
+                                                                                    getPhylogeneticInferenceOptions()
+                                                                                            .copy(),
+                                                                                    this );
+                    new Thread( inferrer ).start();
+                }
+                else {
+                    JOptionPane.showMessageDialog( this,
+                                                   "No multiple sequence alignment selected",
+                                                   "Phylogenetic Inference Not Launched",
+                                                   JOptionPane.WARNING_MESSAGE );
+                }
+            }
+            else {
+                if ( getSeqs() != null ) {
+                    final PhylogeneticInferrer inferrer = new PhylogeneticInferrer( getSeqs(),
+                                                                                    getPhylogeneticInferenceOptions()
+                                                                                            .copy(),
+                                                                                    this );
+                    new Thread( inferrer ).start();
+                }
+                else {
+                    JOptionPane.showMessageDialog( this,
+                                                   "No input sequences selected",
+                                                   "Phylogenetic Inference Not Launched",
+                                                   JOptionPane.WARNING_MESSAGE );
+                }
+            }
+        }
+    }
+
+    void executeSDI() {
+        if ( !isOKforSDI( true, true ) ) {
+            return;
+        }
+        if ( !_mainpanel.getCurrentPhylogeny().isRooted() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Gene tree is not rooted",
+                                           "Cannot execute SDI",
+                                           JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        final Phylogeny gene_tree = _mainpanel.getCurrentPhylogeny().copy();
+        gene_tree.setAllNodesToNotCollapse();
+        gene_tree.recalculateNumberOfExternalDescendants( false );
+        SDI sdi = null;
+        int duplications = -1;
+        try {
+            sdi = new SDIse( gene_tree, _species_tree.copy() );
+            duplications = sdi.getDuplicationsSum();
+        }
+        catch ( final Exception e ) {
+            JOptionPane.showMessageDialog( this, e.toString(), "Error during SDI", JOptionPane.ERROR_MESSAGE );
+        }
+        gene_tree.setRerootable( false );
+        _mainpanel.getCurrentTreePanel().setTree( gene_tree );
+        getControlPanel().setShowEvents( true );
+        showWhole();
+        _mainpanel.getCurrentTreePanel().setEdited( true );
+        JOptionPane.showMessageDialog( this,
+                                       "Number of duplications: " + duplications,
+                                       "SDI successfully completed",
+                                       JOptionPane.INFORMATION_MESSAGE );
+    }
+
+    void executeSDIR( final boolean minimize_cost ) {
+        if ( !isOKforSDI( true, true ) ) {
+            return;
+        }
+        Phylogeny gene_tree = _mainpanel.getCurrentPhylogeny().copy();
+        final SDIR sdiunrooted = new SDIR();
+        gene_tree.setAllNodesToNotCollapse();
+        gene_tree.recalculateNumberOfExternalDescendants( false );
+        try {
+            gene_tree = sdiunrooted.infer( gene_tree, _species_tree, minimize_cost, // minimize cost
+                                           !minimize_cost, // minimize sum of dups
+                                           true, // minimize height
+                                           true, // return tree(s)
+                                           1 )[ 0 ]; // # of trees to return
+        }
+        catch ( final Exception e ) {
+            JOptionPane.showMessageDialog( this, e.toString(), "Error during SDIR", JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        final int duplications = sdiunrooted.getMinimalDuplications();
+        gene_tree.setRerootable( false );
+        _mainpanel.getCurrentTreePanel().setTree( gene_tree );
+        getControlPanel().setShowEvents( true );
+        showWhole();
+        _mainpanel.getCurrentTreePanel().setEdited( true );
+        JOptionPane.showMessageDialog( this,
+                                       "Number of duplications: " + duplications,
+                                       "SDIR successfully completed",
+                                       JOptionPane.INFORMATION_MESSAGE );
+    }
+
+    void exit() {
+        removeTextFrame();
+        _mainpanel.terminate();
+        _contentpane.removeAll();
+        setVisible( false );
+        dispose();
+        System.exit( 0 );
+    }
+
+    private void extractTaxCodeFromNodeNames() {
+        if ( getCurrentTreePanel() != null ) {
+            final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
+            if ( ( phy != null ) && !phy.isEmpty() ) {
+                final PhylogenyNodeIterator it = phy.iteratorPostorder();
+                while ( it.hasNext() ) {
+                    final PhylogenyNode n = it.next();
+                    final String name = n.getName().trim();
+                    if ( !ForesterUtil.isEmpty( name ) ) {
+                        final String code = ForesterUtil.extractTaxonomyCodeFromNodeName( name,
+                                                                                          false,
+                                                                                          TAXONOMY_EXTRACTION.YES );
+                        if ( !ForesterUtil.isEmpty( code ) ) {
+                            PhylogenyMethods.setTaxonomyCode( n, code );
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private ControlPanel getControlPanel() {
+        return getMainPanel().getControlPanel();
+    }
+
+    private File getCurrentDir() {
+        if ( ( _current_dir == null ) || !_current_dir.canRead() ) {
+            if ( ForesterUtil.OS_NAME.toLowerCase().indexOf( "win" ) > -1 ) {
+                try {
+                    _current_dir = new File( WindowsUtils.getCurrentUserDesktopPath() );
+                }
+                catch ( final Exception e ) {
+                    _current_dir = null;
+                }
+            }
+        }
+        if ( ( _current_dir == null ) || !_current_dir.canRead() ) {
+            if ( System.getProperty( "user.home" ) != null ) {
+                _current_dir = new File( System.getProperty( "user.home" ) );
+            }
+            else if ( System.getProperty( "user.dir" ) != null ) {
+                _current_dir = new File( System.getProperty( "user.dir" ) );
+            }
+        }
+        return _current_dir;
+    }
+
+    @Override
+    MainPanel getMainPanel() {
+        return _mainpanel;
+    }
+
+    private double getMinNotCollapseConfidenceValue() {
+        return _min_not_collapse;
+    }
+
+    boolean isOKforSDI( final boolean species_tree_has_to_binary, final boolean gene_tree_has_to_binary ) {
+        if ( ( _mainpanel.getCurrentPhylogeny() == null ) || _mainpanel.getCurrentPhylogeny().isEmpty() ) {
+            return false;
+        }
+        else if ( ( _species_tree == null ) || _species_tree.isEmpty() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "No species tree loaded",
+                                           "Cannot execute SDI",
+                                           JOptionPane.ERROR_MESSAGE );
+            return false;
+        }
+        else if ( species_tree_has_to_binary && !_species_tree.isCompletelyBinary() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Species tree is not completely binary",
+                                           "Cannot execute SDI",
+                                           JOptionPane.ERROR_MESSAGE );
+            return false;
+        }
+        else if ( gene_tree_has_to_binary && !_mainpanel.getCurrentPhylogeny().isCompletelyBinary() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Gene tree is not completely binary",
+                                           "Cannot execute SDI",
+                                           JOptionPane.ERROR_MESSAGE );
+            return false;
+        }
+        else {
+            return true;
+        }
+    }
+
+    private boolean isUnsavedDataPresent() {
+        final List<TreePanel> tps = getMainPanel().getTreePanels();
+        for( final TreePanel tp : tps ) {
+            if ( tp.isEdited() ) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void moveNodeNamesToSeqNames() {
+        if ( getCurrentTreePanel() != null ) {
+            final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
+            if ( ( phy != null ) && !phy.isEmpty() ) {
+                ForesterUtil.transferNodeNameToField( phy, PhylogenyNodeField.SEQUENCE_NAME );
+            }
+        }
+    }
+
+    private void moveNodeNamesToTaxSn() {
+        if ( getCurrentTreePanel() != null ) {
+            final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
+            if ( ( phy != null ) && !phy.isEmpty() ) {
+                ForesterUtil.transferNodeNameToField( phy, PhylogenyNodeField.TAXONOMY_SCIENTIFIC_NAME );
+            }
+        }
+    }
+
+    private void newTree() {
+        final Phylogeny[] phys = new Phylogeny[ 1 ];
+        final Phylogeny phy = new Phylogeny();
+        final PhylogenyNode node = new PhylogenyNode();
+        phy.setRoot( node );
+        phy.setRooted( true );
+        phys[ 0 ] = phy;
+        Util.addPhylogeniesToTabs( phys, "", "", getConfiguration(), getMainPanel() );
+        _mainpanel.getControlPanel().showWhole();
+        _mainpanel.getCurrentTreePanel().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
+        _mainpanel.getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
+        if ( getMainPanel().getMainFrame() == null ) {
+            // Must be "E" applet version.
+            ( ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet() )
+                    .setSelectedTypeInTypeMenu( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
+        }
+        else {
+            getMainPanel().getMainFrame().setSelectedTypeInTypeMenu( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
+        }
+        activateSaveAllIfNeeded();
+        System.gc();
+    }
+
+    private void obtainDetailedTaxonomicInformation() {
+        if ( getCurrentTreePanel() != null ) {
+            final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
+            if ( ( phy != null ) && !phy.isEmpty() ) {
+                final TaxonomyDataObtainer t = new TaxonomyDataObtainer( this, _mainpanel.getCurrentTreePanel(), phy
+                        .copy() );
+                new Thread( t ).start();
+            }
+        }
+    }
+
+    private void print() {
+        if ( ( getCurrentTreePanel() == null ) || ( getCurrentTreePanel().getPhylogeny() == null )
+                || getCurrentTreePanel().getPhylogeny().isEmpty() ) {
+            return;
+        }
+        if ( !getOptions().isPrintUsingActualSize() ) {
+            getCurrentTreePanel().setParametersForPainting( getOptions().getPrintSizeX() - 80,
+                                                            getOptions().getPrintSizeY() - 140,
+                                                            true );
+            getCurrentTreePanel().resetPreferredSize();
+            getCurrentTreePanel().repaint();
+        }
+        final String job_name = Constants.PRG_NAME;
+        boolean error = false;
+        String printer_name = null;
+        try {
+            printer_name = Printer.print( getCurrentTreePanel(), job_name );
+        }
+        catch ( final Exception e ) {
+            error = true;
+            JOptionPane.showMessageDialog( this, e.getMessage(), "Printing Error", JOptionPane.ERROR_MESSAGE );
+        }
+        if ( !error && ( printer_name != null ) ) {
+            String msg = "Printing data sent to printer";
+            if ( printer_name.length() > 1 ) {
+                msg += " [" + printer_name + "]";
+            }
+            JOptionPane.showMessageDialog( this, msg, "Printing...", JOptionPane.INFORMATION_MESSAGE );
+        }
+        if ( !getOptions().isPrintUsingActualSize() ) {
+            getControlPanel().showWhole();
+        }
+    }
+
+    private void printPhylogenyToPdf( final String file_name ) {
+        if ( !getOptions().isPrintUsingActualSize() ) {
+            getCurrentTreePanel().setParametersForPainting( getOptions().getPrintSizeX(),
+                                                            getOptions().getPrintSizeY(),
+                                                            true );
+            getCurrentTreePanel().resetPreferredSize();
+            getCurrentTreePanel().repaint();
+        }
+        String pdf_written_to = "";
+        boolean error = false;
+        try {
+            if ( getOptions().isPrintUsingActualSize() ) {
+                pdf_written_to = PdfExporter.writePhylogenyToPdf( file_name,
+                                                                  getCurrentTreePanel(),
+                                                                  getCurrentTreePanel().getWidth(),
+                                                                  getCurrentTreePanel().getHeight() );
+            }
+            else {
+                pdf_written_to = PdfExporter.writePhylogenyToPdf( file_name, getCurrentTreePanel(), getOptions()
+                        .getPrintSizeX(), getOptions().getPrintSizeY() );
+            }
+        }
+        catch ( final IOException e ) {
+            error = true;
+            JOptionPane.showMessageDialog( this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE );
+        }
+        if ( !error ) {
+            if ( !ForesterUtil.isEmpty( pdf_written_to ) ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Wrote PDF to: " + pdf_written_to,
+                                               "Information",
+                                               JOptionPane.INFORMATION_MESSAGE );
+            }
+            else {
+                JOptionPane.showMessageDialog( this,
+                                               "There was an unknown problem when attempting to write to PDF file: \""
+                                                       + file_name + "\"",
+                                               "Error",
+                                               JOptionPane.ERROR_MESSAGE );
+            }
+        }
+        if ( !getOptions().isPrintUsingActualSize() ) {
+            getControlPanel().showWhole();
+        }
+    }
+
+    private void addExpressionValuesFromFile() {
+        if ( ( getCurrentTreePanel() == null ) || ( getCurrentTreePanel().getPhylogeny() == null ) ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Need to load evolutionary tree first",
+                                           "Can Not Read Expression Values",
+                                           JOptionPane.WARNING_MESSAGE );
+            return;
+        }
+        final File my_dir = getCurrentDir();
+        if ( my_dir != null ) {
+            _values_filechooser.setCurrentDirectory( my_dir );
+        }
+        final int result = _values_filechooser.showOpenDialog( _contentpane );
+        final File file = _values_filechooser.getSelectedFile();
+        if ( ( file != null ) && ( file.length() > 0 ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
+            BasicTable<String> t = null;
+            try {
+                t = BasicTableParser.parse( file, "\t" );
+                if ( t.getNumberOfColumns() < 2 ) {
+                    t = BasicTableParser.parse( file, "," );
+                }
+                if ( t.getNumberOfColumns() < 2 ) {
+                    t = BasicTableParser.parse( file, " " );
+                }
+            }
+            catch ( final IOException e ) {
+                JOptionPane.showMessageDialog( this,
+                                               e.getMessage(),
+                                               "Could Not Read Expression Value Table",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            if ( t.getNumberOfColumns() < 2 ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Table contains " + t.getNumberOfColumns() + " column(s)",
+                                               "Problem with Expression Value Table",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            if ( t.getNumberOfRows() < 1 ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Table contains zero rows",
+                                               "Problem with Expression Value Table",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
+            if ( t.getNumberOfRows() != phy.getNumberOfExternalNodes() ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Table contains " + t.getNumberOfRows() + " rows, but tree contains "
+                                                       + phy.getNumberOfExternalNodes() + " external nodes",
+                                               "Warning",
+                                               JOptionPane.WARNING_MESSAGE );
+            }
+            final DescriptiveStatistics stats = new BasicDescriptiveStatistics();
+            int not_found = 0;
+            for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
+                final PhylogenyNode node = iter.next();
+                final String node_name = node.getName();
+                if ( !ForesterUtil.isEmpty( node_name ) ) {
+                    int row = -1;
+                    try {
+                        row = t.findRow( node_name );
+                    }
+                    catch ( final IllegalArgumentException e ) {
+                        JOptionPane
+                                .showMessageDialog( this,
+                                                    e.getMessage(),
+                                                    "Error Mapping Node Identifiers to Expression Value Identifiers",
+                                                    JOptionPane.ERROR_MESSAGE );
+                        return;
+                    }
+                    if ( row < 0 ) {
+                        if ( node.isExternal() ) {
+                            not_found++;
+                        }
+                        continue;
+                    }
+                    final List<Double> l = new ArrayList<Double>();
+                    for( int col = 1; col < t.getNumberOfColumns(); ++col ) {
+                        double d = -100;
+                        try {
+                            d = Double.parseDouble( t.getValueAsString( col, row ) );
+                        }
+                        catch ( final NumberFormatException e ) {
+                            JOptionPane.showMessageDialog( this,
+                                                           "Could not parse \"" + t.getValueAsString( col, row )
+                                                                   + "\" into a decimal value",
+                                                           "Issue with Expression Value Table",
+                                                           JOptionPane.ERROR_MESSAGE );
+                            return;
+                        }
+                        stats.addValue( d );
+                        l.add( d );
+                    }
+                    if ( !l.isEmpty() ) {
+                        if ( node.getNodeData().getProperties() != null ) {
+                            node.getNodeData().getProperties()
+                                    .removePropertiesWithGivenReferencePrefix( PhyloXmlUtil.VECTOR_PROPERTY_REF );
+                        }
+                        node.getNodeData().setVector( l );
+                    }
+                }
+            }
+            if ( not_found > 0 ) {
+                JOptionPane.showMessageDialog( this, "Could not fine expression values for " + not_found
+                        + " external node(s)", "Warning", JOptionPane.WARNING_MESSAGE );
+            }
+            getCurrentTreePanel().setStatisticsForExpressionValues( stats );
+        }
+    }
+
+    private void readPhylogeniesFromFile() {
+        boolean exception = false;
+        Phylogeny[] phys = null;
+        // Set an initial directory if none set yet
+        final File my_dir = getCurrentDir();
+        _open_filechooser.setMultiSelectionEnabled( true );
+        // Open file-open dialog and set current directory
+        if ( my_dir != null ) {
+            _open_filechooser.setCurrentDirectory( my_dir );
+        }
+        final int result = _open_filechooser.showOpenDialog( _contentpane );
+        // All done: get the file
+        final File[] files = _open_filechooser.getSelectedFiles();
+        setCurrentDir( _open_filechooser.getCurrentDirectory() );
+        boolean nhx_or_nexus = false;
+        if ( ( files != null ) && ( files.length > 0 ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
+            for( final File file : files ) {
+                if ( ( file != null ) && !file.isDirectory() ) {
+                    if ( _mainpanel.getCurrentTreePanel() != null ) {
+                        _mainpanel.getCurrentTreePanel().setWaitCursor();
+                    }
+                    else {
+                        _mainpanel.setWaitCursor();
+                    }
+                    if ( ( _open_filechooser.getFileFilter() == MainFrameApplication.nhfilter )
+                            || ( _open_filechooser.getFileFilter() == MainFrameApplication.nhxfilter ) ) {
+                        try {
+                            final NHXParser nhx = new NHXParser();
+                            setSpecialOptionsForNhxParser( nhx );
+                            phys = Util.readPhylogenies( nhx, file );
+                            nhx_or_nexus = true;
+                        }
+                        catch ( final Exception e ) {
+                            exception = true;
+                            exceptionOccuredDuringOpenFile( e );
+                        }
+                    }
+                    else if ( _open_filechooser.getFileFilter() == MainFrameApplication.xmlfilter ) {
+                        warnIfNotPhyloXmlValidation( getConfiguration() );
+                        try {
+                            final PhyloXmlParser xml_parser = createPhyloXmlParser();
+                            phys = Util.readPhylogenies( xml_parser, file );
+                        }
+                        catch ( final Exception e ) {
+                            exception = true;
+                            exceptionOccuredDuringOpenFile( e );
+                        }
+                    }
+                    else if ( _open_filechooser.getFileFilter() == MainFrameApplication.tolfilter ) {
+                        try {
+                            phys = Util.readPhylogenies( new TolParser(), file );
+                        }
+                        catch ( final Exception e ) {
+                            exception = true;
+                            exceptionOccuredDuringOpenFile( e );
+                        }
+                    }
+                    else if ( _open_filechooser.getFileFilter() == MainFrameApplication.nexusfilter ) {
+                        try {
+                            final NexusPhylogeniesParser nex = new NexusPhylogeniesParser();
+                            setSpecialOptionsForNexParser( nex );
+                            phys = Util.readPhylogenies( nex, file );
+                            nhx_or_nexus = true;
+                        }
+                        catch ( final Exception e ) {
+                            exception = true;
+                            exceptionOccuredDuringOpenFile( e );
+                        }
+                    }
+                    // "*.*":
+                    else {
+                        try {
+                            final PhylogenyParser parser = ForesterUtil
+                                    .createParserDependingOnFileType( file, getConfiguration()
+                                            .isValidatePhyloXmlAgainstSchema() );
+                            if ( parser instanceof NexusPhylogeniesParser ) {
+                                final NexusPhylogeniesParser nex = ( NexusPhylogeniesParser ) parser;
+                                setSpecialOptionsForNexParser( nex );
+                                nhx_or_nexus = true;
+                            }
+                            else if ( parser instanceof NHXParser ) {
+                                final NHXParser nhx = ( NHXParser ) parser;
+                                setSpecialOptionsForNhxParser( nhx );
+                                nhx_or_nexus = true;
+                            }
+                            else if ( parser instanceof PhyloXmlParser ) {
+                                warnIfNotPhyloXmlValidation( getConfiguration() );
+                            }
+                            phys = Util.readPhylogenies( parser, file );
+                        }
+                        catch ( final Exception e ) {
+                            exception = true;
+                            exceptionOccuredDuringOpenFile( e );
+                        }
+                    }
+                    if ( _mainpanel.getCurrentTreePanel() != null ) {
+                        _mainpanel.getCurrentTreePanel().setArrowCursor();
+                    }
+                    else {
+                        _mainpanel.setArrowCursor();
+                    }
+                    if ( !exception && ( phys != null ) && ( phys.length > 0 ) ) {
+                        boolean one_desc = false;
+                        if ( nhx_or_nexus ) {
+                            for( final Phylogeny phy : phys ) {
+                                if ( getOptions().isInternalNumberAreConfidenceForNhParsing() ) {
+                                    ForesterUtil.transferInternalNodeNamesToConfidence( phy );
+                                }
+                                if ( PhylogenyMethods.getMinimumDescendentsPerInternalNodes( phy ) == 1 ) {
+                                    one_desc = true;
+                                    break;
+                                }
+                            }
+                        }
+                        Util.addPhylogeniesToTabs( phys,
+                                                   file.getName(),
+                                                   file.getAbsolutePath(),
+                                                   getConfiguration(),
+                                                   getMainPanel() );
+                        _mainpanel.getControlPanel().showWhole();
+                        if ( nhx_or_nexus && one_desc ) {
+                            JOptionPane
+                                    .showMessageDialog( this,
+                                                        "One or more trees contain (a) node(s) with one descendant, "
+                                                                + ForesterUtil.LINE_SEPARATOR
+                                                                + "possibly indicating illegal parentheses within node names.",
+                                                        "Warning: Possible Error in New Hampshire Formatted Data",
+                                                        JOptionPane.WARNING_MESSAGE );
+                        }
+                    }
+                }
+            }
+        }
+        activateSaveAllIfNeeded();
+        System.gc();
+    }
+
+    void readSeqsFromFile() {
+        // Set an initial directory if none set yet
+        final File my_dir = getCurrentDir();
+        _seqs_filechooser.setMultiSelectionEnabled( false );
+        // Open file-open dialog and set current directory
+        if ( my_dir != null ) {
+            _seqs_filechooser.setCurrentDirectory( my_dir );
+        }
+        final int result = _seqs_filechooser.showOpenDialog( _contentpane );
+        // All done: get the seqs
+        final File file = _seqs_filechooser.getSelectedFile();
+        setCurrentDir( _seqs_filechooser.getCurrentDirectory() );
+        if ( ( file != null ) && !file.isDirectory() && ( result == JFileChooser.APPROVE_OPTION ) ) {
+            setSeqsFile( null );
+            setSeqs( null );
+            List<Sequence> seqs = null;
+            try {
+                if ( FastaParser.isLikelyFasta( new FileInputStream( file ) ) ) {
+                    seqs = FastaParser.parse( new FileInputStream( file ) );
+                    for( final Sequence seq : seqs ) {
+                        System.out.println( SequenceWriter.toFasta( seq, 60 ) );
+                    }
+                }
+                else {
+                    //TODO error
+                }
+            }
+            catch ( final MsaFormatException e ) {
+                try {
+                    _mainpanel.getCurrentTreePanel().setArrowCursor();
+                }
+                catch ( final Exception ex ) {
+                    // Do nothing.
+                }
+                JOptionPane.showMessageDialog( this,
+                                               e.getLocalizedMessage(),
+                                               "Multiple sequence file format error",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            catch ( final IOException e ) {
+                try {
+                    _mainpanel.getCurrentTreePanel().setArrowCursor();
+                }
+                catch ( final Exception ex ) {
+                    // Do nothing.
+                }
+                JOptionPane.showMessageDialog( this,
+                                               e.getLocalizedMessage(),
+                                               "Failed to read multiple sequence file",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            catch ( final IllegalArgumentException e ) {
+                try {
+                    _mainpanel.getCurrentTreePanel().setArrowCursor();
+                }
+                catch ( final Exception ex ) {
+                    // Do nothing.
+                }
+                JOptionPane.showMessageDialog( this,
+                                               e.getLocalizedMessage(),
+                                               "Unexpected error during reading of multiple sequence file",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            catch ( final Exception e ) {
+                try {
+                    _mainpanel.getCurrentTreePanel().setArrowCursor();
+                }
+                catch ( final Exception ex ) {
+                    // Do nothing.
+                }
+                e.printStackTrace();
+                JOptionPane.showMessageDialog( this,
+                                               e.getLocalizedMessage(),
+                                               "Unexpected error during reading of multiple sequence file",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            if ( ( seqs == null ) || ( seqs.size() < 1 ) ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Multiple sequence file is empty",
+                                               "Illegal multiple sequence file",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            if ( seqs.size() < 4 ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Multiple sequence file needs to contain at least 3 sequences",
+                                               "Illegal multiple sequence file",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            //  if ( msa.getLength() < 2 ) {
+            //       JOptionPane.showMessageDialog( this,
+            //                                      "Multiple sequence alignment needs to contain at least 2 residues",
+            //                                      "Illegal multiple sequence file",
+            //                                      JOptionPane.ERROR_MESSAGE );
+            //       return;
+            //   }
+            System.gc();
+            setSeqsFile( _seqs_filechooser.getSelectedFile() );
+            setSeqs( seqs );
+        }
+    }
+
+    void readMsaFromFile() {
+        // Set an initial directory if none set yet
+        final File my_dir = getCurrentDir();
+        _msa_filechooser.setMultiSelectionEnabled( false );
+        // Open file-open dialog and set current directory
+        if ( my_dir != null ) {
+            _msa_filechooser.setCurrentDirectory( my_dir );
+        }
+        final int result = _msa_filechooser.showOpenDialog( _contentpane );
+        // All done: get the msa
+        final File file = _msa_filechooser.getSelectedFile();
+        setCurrentDir( _msa_filechooser.getCurrentDirectory() );
+        if ( ( file != null ) && !file.isDirectory() && ( result == JFileChooser.APPROVE_OPTION ) ) {
+            setMsaFile( null );
+            setMsa( null );
+            Msa msa = null;
+            try {
+                if ( FastaParser.isLikelyFasta( new FileInputStream( file ) ) ) {
+                    msa = FastaParser.parseMsa( new FileInputStream( file ) );
+                    System.out.println( msa.toString() );
+                }
+                else {
+                    msa = GeneralMsaParser.parse( new FileInputStream( file ) );
+                }
+            }
+            catch ( final MsaFormatException e ) {
+                try {
+                    _mainpanel.getCurrentTreePanel().setArrowCursor();
+                }
+                catch ( final Exception ex ) {
+                    // Do nothing.
+                }
+                JOptionPane.showMessageDialog( this,
+                                               e.getLocalizedMessage(),
+                                               "Multiple sequence alignment format error",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            catch ( final IOException e ) {
+                try {
+                    _mainpanel.getCurrentTreePanel().setArrowCursor();
+                }
+                catch ( final Exception ex ) {
+                    // Do nothing.
+                }
+                JOptionPane.showMessageDialog( this,
+                                               e.getLocalizedMessage(),
+                                               "Failed to read multiple sequence alignment",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            catch ( final IllegalArgumentException e ) {
+                try {
+                    _mainpanel.getCurrentTreePanel().setArrowCursor();
+                }
+                catch ( final Exception ex ) {
+                    // Do nothing.
+                }
+                JOptionPane.showMessageDialog( this,
+                                               e.getLocalizedMessage(),
+                                               "Unexpected error during reading of multiple sequence alignment",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            catch ( final Exception e ) {
+                try {
+                    _mainpanel.getCurrentTreePanel().setArrowCursor();
+                }
+                catch ( final Exception ex ) {
+                    // Do nothing.
+                }
+                e.printStackTrace();
+                JOptionPane.showMessageDialog( this,
+                                               e.getLocalizedMessage(),
+                                               "Unexpected error during reading of multiple sequence alignment",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            if ( ( msa == null ) || ( msa.getNumberOfSequences() < 1 ) ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Multiple sequence alignment is empty",
+                                               "Illegal Multiple Sequence Alignment",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            if ( msa.getNumberOfSequences() < 4 ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Multiple sequence alignment needs to contain at least 3 sequences",
+                                               "Illegal multiple sequence alignment",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            if ( msa.getLength() < 2 ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Multiple sequence alignment needs to contain at least 2 residues",
+                                               "Illegal multiple sequence alignment",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            System.gc();
+            setMsaFile( _msa_filechooser.getSelectedFile() );
+            setMsa( msa );
+        }
+    }
+
+    @Override
+    void readPhylogeniesFromURL() {
+        URL url = null;
+        Phylogeny[] phys = null;
+        final String message = "Please enter a complete URL, for example \"http://www.phyloxml.org/examples/apaf.xml\"";
+        final String url_string = JOptionPane.showInputDialog( this,
+                                                               message,
+                                                               "Use URL/webservice to obtain a phylogeny",
+                                                               JOptionPane.QUESTION_MESSAGE );
+        boolean nhx_or_nexus = false;
+        if ( ( url_string != null ) && ( url_string.length() > 0 ) ) {
+            try {
+                url = new URL( url_string );
+                PhylogenyParser parser = null;
+                if ( url.getHost().toLowerCase().indexOf( "tolweb" ) >= 0 ) {
+                    parser = new TolParser();
+                }
+                else {
+                    parser = ForesterUtil.createParserDependingOnUrlContents( url, getConfiguration()
+                            .isValidatePhyloXmlAgainstSchema() );
+                }
+                if ( parser instanceof NexusPhylogeniesParser ) {
+                    nhx_or_nexus = true;
+                }
+                else if ( parser instanceof NHXParser ) {
+                    nhx_or_nexus = true;
+                }
+                if ( _mainpanel.getCurrentTreePanel() != null ) {
+                    _mainpanel.getCurrentTreePanel().setWaitCursor();
+                }
+                else {
+                    _mainpanel.setWaitCursor();
+                }
+                final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance();
+                phys = factory.create( url.openStream(), parser );
+            }
+            catch ( final MalformedURLException e ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Malformed URL: " + url + "\n" + e.getLocalizedMessage(),
+                                               "Malformed URL",
+                                               JOptionPane.ERROR_MESSAGE );
+            }
+            catch ( final IOException e ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Could not read from " + url + "\n"
+                                                       + ForesterUtil.wordWrap( e.getLocalizedMessage(), 80 ),
+                                               "Failed to read URL",
+                                               JOptionPane.ERROR_MESSAGE );
+            }
+            catch ( final Exception e ) {
+                JOptionPane.showMessageDialog( this,
+                                               ForesterUtil.wordWrap( e.getLocalizedMessage(), 80 ),
+                                               "Unexpected Exception",
+                                               JOptionPane.ERROR_MESSAGE );
+            }
+            finally {
+                if ( _mainpanel.getCurrentTreePanel() != null ) {
+                    _mainpanel.getCurrentTreePanel().setArrowCursor();
+                }
+                else {
+                    _mainpanel.setArrowCursor();
+                }
+            }
+            if ( ( phys != null ) && ( phys.length > 0 ) ) {
+                if ( nhx_or_nexus && getOptions().isInternalNumberAreConfidenceForNhParsing() ) {
+                    for( final Phylogeny phy : phys ) {
+                        ForesterUtil.transferInternalNodeNamesToConfidence( phy );
+                    }
+                }
+                Util.addPhylogeniesToTabs( phys, new File( url.getFile() ).getName(), new File( url.getFile() )
+                        .toString(), getConfiguration(), getMainPanel() );
+                _mainpanel.getControlPanel().showWhole();
+            }
+        }
+        activateSaveAllIfNeeded();
+        System.gc();
+    }
+
+    private void readSpeciesTreeFromFile() {
+        Phylogeny t = null;
+        boolean exception = false;
+        final File my_dir = getCurrentDir();
+        _open_filechooser_for_species_tree.setSelectedFile( new File( "" ) );
+        if ( my_dir != null ) {
+            _open_filechooser_for_species_tree.setCurrentDirectory( my_dir );
+        }
+        final int result = _open_filechooser_for_species_tree.showOpenDialog( _contentpane );
+        final File file = _open_filechooser_for_species_tree.getSelectedFile();
+        if ( ( file != null ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
+            if ( _open_filechooser_for_species_tree.getFileFilter() == MainFrameApplication.xmlfilter ) {
+                try {
+                    final Phylogeny[] trees = Util.readPhylogenies( new PhyloXmlParser(), file );
+                    t = trees[ 0 ];
+                }
+                catch ( final Exception e ) {
+                    exception = true;
+                    exceptionOccuredDuringOpenFile( e );
+                }
+            }
+            else if ( _open_filechooser_for_species_tree.getFileFilter() == MainFrameApplication.tolfilter ) {
+                try {
+                    final Phylogeny[] trees = Util.readPhylogenies( new TolParser(), file );
+                    t = trees[ 0 ];
+                }
+                catch ( final Exception e ) {
+                    exception = true;
+                    exceptionOccuredDuringOpenFile( e );
+                }
+            }
+            // "*.*":
+            else {
+                try {
+                    final Phylogeny[] trees = Util.readPhylogenies( new PhyloXmlParser(), file );
+                    t = trees[ 0 ];
+                }
+                catch ( final Exception e ) {
+                    exception = true;
+                    exceptionOccuredDuringOpenFile( e );
+                }
+            }
+            if ( !exception && ( t != null ) && !t.isRooted() ) {
+                exception = true;
+                t = null;
+                JOptionPane.showMessageDialog( this,
+                                               "Species tree is not rooted",
+                                               "Species tree not loaded",
+                                               JOptionPane.ERROR_MESSAGE );
+            }
+            if ( !exception && ( t != null ) ) {
+                final Set<Taxonomy> tax_set = new HashSet<Taxonomy>();
+                for( final PhylogenyNodeIterator it = t.iteratorExternalForward(); it.hasNext(); ) {
+                    final PhylogenyNode node = it.next();
+                    if ( !node.getNodeData().isHasTaxonomy() ) {
+                        exception = true;
+                        t = null;
+                        JOptionPane
+                                .showMessageDialog( this,
+                                                    "Species tree contains external node(s) without taxonomy information",
+                                                    "Species tree not loaded",
+                                                    JOptionPane.ERROR_MESSAGE );
+                        break;
+                    }
+                    else {
+                        if ( tax_set.contains( node.getNodeData().getTaxonomy() ) ) {
+                            exception = true;
+                            t = null;
+                            JOptionPane.showMessageDialog( this,
+                                                           "Taxonomy ["
+                                                                   + node.getNodeData().getTaxonomy().asSimpleText()
+                                                                   + "] is not unique in species tree",
+                                                           "Species tree not loaded",
+                                                           JOptionPane.ERROR_MESSAGE );
+                            break;
+                        }
+                        else {
+                            tax_set.add( node.getNodeData().getTaxonomy() );
+                        }
+                    }
+                }
+            }
+            if ( !exception && ( t != null ) ) {
+                _species_tree = t;
+                JOptionPane.showMessageDialog( this,
+                                               "Species tree successfully loaded",
+                                               "Species tree loaded",
+                                               JOptionPane.INFORMATION_MESSAGE );
+            }
+            _contentpane.repaint();
+            System.gc();
+        }
+    }
+
+    private void setCurrentDir( final File current_dir ) {
+        _current_dir = current_dir;
+    }
+
+    private void setMinNotCollapseConfidenceValue( final double min_not_collapse ) {
+        _min_not_collapse = min_not_collapse;
+    }
+
+    private void setSpecialOptionsForNexParser( final NexusPhylogeniesParser nex ) {
+        nex.setReplaceUnderscores( getOptions().isReplaceUnderscoresInNhParsing() );
+    }
+
+    private void setSpecialOptionsForNhxParser( final NHXParser nhx ) {
+        nhx.setReplaceUnderscores( getOptions().isReplaceUnderscoresInNhParsing() );
+        ForesterUtil.TAXONOMY_EXTRACTION te = ForesterUtil.TAXONOMY_EXTRACTION.NO;
+        if ( getOptions().isExtractPfamTaxonomyCodesInNhParsing() ) {
+            te = ForesterUtil.TAXONOMY_EXTRACTION.YES;
+        }
+        nhx.setTaxonomyExtraction( te );
+    }
+
+    private void writeAllToFile() {
+        if ( ( getMainPanel().getTabbedPane() == null ) || ( getMainPanel().getTabbedPane().getTabCount() < 1 ) ) {
+            return;
+        }
+        final File my_dir = getCurrentDir();
+        if ( my_dir != null ) {
+            _save_filechooser.setCurrentDirectory( my_dir );
+        }
+        _save_filechooser.setSelectedFile( new File( "" ) );
+        final int result = _save_filechooser.showSaveDialog( _contentpane );
+        final File file = _save_filechooser.getSelectedFile();
+        setCurrentDir( _save_filechooser.getCurrentDirectory() );
+        if ( ( file != null ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
+            if ( file.exists() ) {
+                final int i = JOptionPane.showConfirmDialog( this,
+                                                             file + " already exists. Overwrite?",
+                                                             "Warning",
+                                                             JOptionPane.OK_CANCEL_OPTION,
+                                                             JOptionPane.WARNING_MESSAGE );
+                if ( i != JOptionPane.OK_OPTION ) {
+                    return;
+                }
+                else {
+                    try {
+                        file.delete();
+                    }
+                    catch ( final Exception e ) {
+                        JOptionPane.showMessageDialog( this,
+                                                       "Failed to delete: " + file,
+                                                       "Error",
+                                                       JOptionPane.WARNING_MESSAGE );
+                    }
+                }
+            }
+            final int count = getMainPanel().getTabbedPane().getTabCount();
+            final List<Phylogeny> trees = new ArrayList<Phylogeny>();
+            for( int i = 0; i < count; ++i ) {
+                trees.add( getMainPanel().getPhylogeny( i ) );
+                getMainPanel().getTreePanels().get( i ).setEdited( false );
+            }
+            final PhylogenyWriter writer = new PhylogenyWriter();
+            try {
+                writer.toPhyloXML( file, trees, 0, ForesterUtil.LINE_SEPARATOR );
+            }
+            catch ( final IOException e ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Failed to write to: " + file,
+                                               "Error",
+                                               JOptionPane.WARNING_MESSAGE );
+            }
+        }
+    }
+
+    private boolean writeAsNewHampshire( final Phylogeny t, boolean exception, final File file ) {
+        try {
+            final PhylogenyWriter writer = new PhylogenyWriter();
+            writer.toNewHampshire( t, false, true, file );
+        }
+        catch ( final Exception e ) {
+            exception = true;
+            exceptionOccuredDuringSaveAs( e );
+        }
+        return exception;
+    }
+
+    private boolean writeAsNexus( final Phylogeny t, boolean exception, final File file ) {
+        try {
+            final PhylogenyWriter writer = new PhylogenyWriter();
+            writer.toNexus( file, t );
+        }
+        catch ( final Exception e ) {
+            exception = true;
+            exceptionOccuredDuringSaveAs( e );
+        }
+        return exception;
+    }
+
+    private boolean writeAsNHX( final Phylogeny t, boolean exception, final File file ) {
+        try {
+            final PhylogenyWriter writer = new PhylogenyWriter();
+            writer.toNewHampshireX( t, file );
+        }
+        catch ( final Exception e ) {
+            exception = true;
+            exceptionOccuredDuringSaveAs( e );
+        }
+        return exception;
+    }
+
+    private boolean writeAsPhyloXml( final Phylogeny t, boolean exception, final File file ) {
+        try {
+            final PhylogenyWriter writer = new PhylogenyWriter();
+            writer.toPhyloXML( file, t, 0 );
+        }
+        catch ( final Exception e ) {
+            exception = true;
+            exceptionOccuredDuringSaveAs( e );
+        }
+        return exception;
+    }
+
+    private void writePhylogenyToGraphicsFile( final String file_name, final GraphicsExportType type ) {
+        _mainpanel.getCurrentTreePanel().setParametersForPainting( _mainpanel.getCurrentTreePanel().getWidth(),
+                                                                   _mainpanel.getCurrentTreePanel().getHeight(),
+                                                                   true );
+        String file_written_to = "";
+        boolean error = false;
+        try {
+            file_written_to = Util.writePhylogenyToGraphicsFile( file_name,
+                                                                 _mainpanel.getCurrentTreePanel().getWidth(),
+                                                                 _mainpanel.getCurrentTreePanel().getHeight(),
+                                                                 _mainpanel.getCurrentTreePanel(),
+                                                                 _mainpanel.getControlPanel(),
+                                                                 type,
+                                                                 getOptions() );
+        }
+        catch ( final IOException e ) {
+            error = true;
+            JOptionPane.showMessageDialog( this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE );
+        }
+        if ( !error ) {
+            if ( ( file_written_to != null ) && ( file_written_to.length() > 0 ) ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Wrote image to: " + file_written_to,
+                                               "Graphics Export",
+                                               JOptionPane.INFORMATION_MESSAGE );
+            }
+            else {
+                JOptionPane.showMessageDialog( this,
+                                               "There was an unknown problem when attempting to write to an image file: \""
+                                                       + file_name + "\"",
+                                               "Error",
+                                               JOptionPane.ERROR_MESSAGE );
+            }
+        }
+        _contentpane.repaint();
+    }
+
+    private void writeToFile( final Phylogeny t ) {
+        if ( t == null ) {
+            return;
+        }
+        String initial_filename = null;
+        if ( getMainPanel().getCurrentTreePanel().getTreeFile() != null ) {
+            try {
+                initial_filename = getMainPanel().getCurrentTreePanel().getTreeFile().getCanonicalPath();
+            }
+            catch ( final IOException e ) {
+                initial_filename = null;
+            }
+        }
+        if ( !ForesterUtil.isEmpty( initial_filename ) ) {
+            _save_filechooser.setSelectedFile( new File( initial_filename ) );
+        }
+        else {
+            _save_filechooser.setSelectedFile( new File( "" ) );
+        }
+        final File my_dir = getCurrentDir();
+        if ( my_dir != null ) {
+            _save_filechooser.setCurrentDirectory( my_dir );
+        }
+        final int result = _save_filechooser.showSaveDialog( _contentpane );
+        final File file = _save_filechooser.getSelectedFile();
+        setCurrentDir( _save_filechooser.getCurrentDirectory() );
+        boolean exception = false;
+        if ( ( file != null ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
+            if ( file.exists() ) {
+                final int i = JOptionPane.showConfirmDialog( this,
+                                                             file + " already exists.\nOverwrite?",
+                                                             "Overwrite?",
+                                                             JOptionPane.OK_CANCEL_OPTION,
+                                                             JOptionPane.QUESTION_MESSAGE );
+                if ( i != JOptionPane.OK_OPTION ) {
+                    return;
+                }
+                else {
+                    final File to = new File( file.getAbsoluteFile().toString() + Constants.BACKUP_FILE_SUFFIX );
+                    try {
+                        ForesterUtil.copyFile( file, to );
+                    }
+                    catch ( final Exception e ) {
+                        JOptionPane.showMessageDialog( this,
+                                                       "Failed to create backup copy " + to,
+                                                       "Failed to Create Backup Copy",
+                                                       JOptionPane.WARNING_MESSAGE );
+                    }
+                    try {
+                        file.delete();
+                    }
+                    catch ( final Exception e ) {
+                        JOptionPane.showMessageDialog( this,
+                                                       "Failed to delete: " + file,
+                                                       "Failed to Delete",
+                                                       JOptionPane.WARNING_MESSAGE );
+                    }
+                }
+            }
+            if ( _save_filechooser.getFileFilter() == MainFrameApplication.nhfilter ) {
+                exception = writeAsNewHampshire( t, exception, file );
+            }
+            else if ( _save_filechooser.getFileFilter() == MainFrameApplication.nhxfilter ) {
+                exception = writeAsNHX( t, exception, file );
+            }
+            else if ( _save_filechooser.getFileFilter() == MainFrameApplication.xmlfilter ) {
+                exception = writeAsPhyloXml( t, exception, file );
+            }
+            else if ( _save_filechooser.getFileFilter() == MainFrameApplication.nexusfilter ) {
+                exception = writeAsNexus( t, exception, file );
+            }
+            // "*.*":
+            else {
+                final String file_name = file.getName().trim().toLowerCase();
+                if ( file_name.endsWith( ".nh" ) || file_name.endsWith( ".newick" ) || file_name.endsWith( ".phy" )
+                        || file_name.endsWith( ".tree" ) ) {
+                    exception = writeAsNewHampshire( t, exception, file );
+                }
+                else if ( file_name.endsWith( ".nhx" ) ) {
+                    exception = writeAsNHX( t, exception, file );
+                }
+                else if ( file_name.endsWith( ".nex" ) || file_name.endsWith( ".nexus" ) ) {
+                    exception = writeAsNexus( t, exception, file );
+                }
+                // XML is default:
+                else {
+                    exception = writeAsPhyloXml( t, exception, file );
+                }
+            }
+            if ( !exception ) {
+                getMainPanel().getCurrentTreePanel().setTreeFile( file );
+                getMainPanel().getCurrentTreePanel().setEdited( false );
+            }
+        }
+    }
+
+    private void writeToGraphicsFile( final Phylogeny t, final GraphicsExportType type ) {
+        if ( ( t == null ) || t.isEmpty() ) {
+            return;
+        }
+        String initial_filename = "";
+        if ( getMainPanel().getCurrentTreePanel().getTreeFile() != null ) {
+            initial_filename = getMainPanel().getCurrentTreePanel().getTreeFile().toString();
+        }
+        if ( initial_filename.indexOf( '.' ) > 0 ) {
+            initial_filename = initial_filename.substring( 0, initial_filename.lastIndexOf( '.' ) );
+        }
+        initial_filename = initial_filename + "." + type;
+        _writetographics_filechooser.setSelectedFile( new File( initial_filename ) );
+        final File my_dir = getCurrentDir();
+        if ( my_dir != null ) {
+            _writetographics_filechooser.setCurrentDirectory( my_dir );
+        }
+        final int result = _writetographics_filechooser.showSaveDialog( _contentpane );
+        File file = _writetographics_filechooser.getSelectedFile();
+        setCurrentDir( _writetographics_filechooser.getCurrentDirectory() );
+        if ( ( file != null ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
+            if ( !file.toString().toLowerCase().endsWith( type.toString() ) ) {
+                file = new File( file.toString() + "." + type );
+            }
+            if ( file.exists() ) {
+                final int i = JOptionPane.showConfirmDialog( this,
+                                                             file + " already exists. Overwrite?",
+                                                             "Warning",
+                                                             JOptionPane.OK_CANCEL_OPTION,
+                                                             JOptionPane.WARNING_MESSAGE );
+                if ( i != JOptionPane.OK_OPTION ) {
+                    return;
+                }
+                else {
+                    try {
+                        file.delete();
+                    }
+                    catch ( final Exception e ) {
+                        JOptionPane.showMessageDialog( this,
+                                                       "Failed to delete: " + file,
+                                                       "Error",
+                                                       JOptionPane.WARNING_MESSAGE );
+                    }
+                }
+            }
+            writePhylogenyToGraphicsFile( file.toString(), type );
+        }
+    }
+
+    private void writeToPdf( final Phylogeny t ) {
+        if ( ( t == null ) || t.isEmpty() ) {
+            return;
+        }
+        String initial_filename = "";
+        if ( getMainPanel().getCurrentTreePanel().getTreeFile() != null ) {
+            initial_filename = getMainPanel().getCurrentTreePanel().getTreeFile().toString();
+        }
+        if ( initial_filename.indexOf( '.' ) > 0 ) {
+            initial_filename = initial_filename.substring( 0, initial_filename.lastIndexOf( '.' ) );
+        }
+        initial_filename = initial_filename + ".pdf";
+        _writetopdf_filechooser.setSelectedFile( new File( initial_filename ) );
+        final File my_dir = getCurrentDir();
+        if ( my_dir != null ) {
+            _writetopdf_filechooser.setCurrentDirectory( my_dir );
+        }
+        final int result = _writetopdf_filechooser.showSaveDialog( _contentpane );
+        File file = _writetopdf_filechooser.getSelectedFile();
+        setCurrentDir( _writetopdf_filechooser.getCurrentDirectory() );
+        if ( ( file != null ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
+            if ( !file.toString().toLowerCase().endsWith( ".pdf" ) ) {
+                file = new File( file.toString() + ".pdf" );
+            }
+            if ( file.exists() ) {
+                final int i = JOptionPane.showConfirmDialog( this,
+                                                             file + " already exists. Overwrite?",
+                                                             "WARNING",
+                                                             JOptionPane.OK_CANCEL_OPTION,
+                                                             JOptionPane.WARNING_MESSAGE );
+                if ( i != JOptionPane.OK_OPTION ) {
+                    return;
+                }
+            }
+            printPhylogenyToPdf( file.toString() );
+        }
+    }
+
+    static MainFrame createInstance( final Phylogeny[] phys, final Configuration config, final String title ) {
+        return new MainFrameApplication( phys, config, title );
+    }
+
+    static MainFrame createInstance( final Phylogeny[] phys, final String config_file_name, final String title ) {
+        return new MainFrameApplication( phys, config_file_name, title );
+    }
+
+    static void setTextForGraphicsSizeChooserMenuItem( final JMenuItem mi, final Options o ) {
+        mi.setText( "Enter Default Size for Graphics Export... (current: " + o.getPrintSizeX() + ", "
+                + o.getPrintSizeY() + ")" );
+    }
+
+    static void setTextForPdfLineWidthChooserMenuItem( final JMenuItem mi, final Options o ) {
+        mi.setText( "Enter Default Line Width for PDF Export... (current: " + o.getPrintLineWidth() + ")" );
+    }
+
+    static void warnIfNotPhyloXmlValidation( final Configuration c ) {
+        if ( !c.isValidatePhyloXmlAgainstSchema() ) {
+            JOptionPane
+                    .showMessageDialog( null,
+                                        ForesterUtil
+                                                .wordWrap( "phyloXML XSD-based validation is turned off [enable with line 'validate_against_phyloxml_xsd_schem: true' in configuration file]",
+                                                           80 ),
+                                        "Warning",
+                                        JOptionPane.WARNING_MESSAGE );
+        }
+    }
+
+    private void setPhylogeneticInferenceOptions( final PhylogeneticInferenceOptions phylogenetic_inference_options ) {
+        _phylogenetic_inference_options = phylogenetic_inference_options;
+    }
+
+    private PhylogeneticInferenceOptions getPhylogeneticInferenceOptions() {
+        if ( _phylogenetic_inference_options == null ) {
+            _phylogenetic_inference_options = new PhylogeneticInferenceOptions();
+        }
+        return _phylogenetic_inference_options;
+    }
+
+    Msa getMsa() {
+        return _msa;
+    }
+
+    void setMsa( final Msa msa ) {
+        _msa = msa;
+    }
+
+    void setMsaFile( final File msa_file ) {
+        _msa_file = msa_file;
+    }
+
+    File getMsaFile() {
+        return _msa_file;
+    }
+
+    List<Sequence> getSeqs() {
+        return _seqs;
+    }
+
+    void setSeqs( final List<Sequence> seqs ) {
+        _seqs = seqs;
+    }
+
+    void setSeqsFile( final File seqs_file ) {
+        _seqs_file = seqs_file;
+    }
+
+    File getSeqsFile() {
+        return _seqs_file;
+    }
+} // MainFrameApplication.
+
+class NexusFilter extends FileFilter {
+
+    @Override
+    public boolean accept( final File f ) {
+        final String file_name = f.getName().trim().toLowerCase();
+        return file_name.endsWith( ".nex" ) || file_name.endsWith( ".nexus" ) || file_name.endsWith( ".nx" )
+                || file_name.endsWith( ".tre" ) || f.isDirectory();
+    }
+
+    @Override
+    public String getDescription() {
+        return "Nexus files (*.nex, *.nexus, *.nx, *.tre)";
+    }
+} // NexusFilter
+
+class NHFilter extends FileFilter {
+
+    @Override
+    public boolean accept( final File f ) {
+        final String file_name = f.getName().trim().toLowerCase();
+        return file_name.endsWith( ".nh" ) || file_name.endsWith( ".newick" ) || file_name.endsWith( ".phy" )
+                || file_name.endsWith( ".tr" ) || file_name.endsWith( ".tree" ) || file_name.endsWith( ".dnd" )
+                || file_name.endsWith( ".ph" ) || file_name.endsWith( ".phb" ) || file_name.endsWith( ".nwk" )
+                || f.isDirectory();
+    }
+
+    @Override
+    public String getDescription() {
+        return "New Hampshire - Newick files (*.nh, *.newick, *.phy, *.tree, *.dnd, *.tr, *.ph, *.phb, *.nwk)";
+    }
+} // NHFilter
+
+class NHXFilter extends FileFilter {
+
+    @Override
+    public boolean accept( final File f ) {
+        final String file_name = f.getName().trim().toLowerCase();
+        return file_name.endsWith( ".nhx" ) || f.isDirectory();
+    }
+
+    @Override
+    public String getDescription() {
+        return "NHX files (*.nhx)";
+    }
+}
+
+class PdfFilter extends FileFilter {
+
+    @Override
+    public boolean accept( final File f ) {
+        return f.getName().trim().toLowerCase().endsWith( ".pdf" ) || f.isDirectory();
+    }
+
+    @Override
+    public String getDescription() {
+        return "PDF files (*.pdf)";
+    }
+} // PdfFilter
+
+class TolFilter extends FileFilter {
+
+    @Override
+    public boolean accept( final File f ) {
+        final String file_name = f.getName().trim().toLowerCase();
+        return ( file_name.endsWith( ".tol" ) || file_name.endsWith( ".tolxml" ) || file_name.endsWith( ".zip" ) || f
+                .isDirectory() )
+                && ( !file_name.endsWith( ".xml.zip" ) );
+    }
+
+    @Override
+    public String getDescription() {
+        return "Tree of Life files (*.tol, *.tolxml)";
+    }
+} // TolFilter
+
+class XMLFilter extends FileFilter {
+
+    @Override
+    public boolean accept( final File f ) {
+        final String file_name = f.getName().trim().toLowerCase();
+        return file_name.endsWith( ".xml" ) || file_name.endsWith( ".phyloxml" ) || file_name.endsWith( "phylo.xml" )
+                || file_name.endsWith( ".pxml" ) || file_name.endsWith( ".zip" ) || f.isDirectory();
+    }
+
+    @Override
+    public String getDescription() {
+        return "phyloXML files (*.xml, *.phyloxml, *phylo.xml, *.pxml, *.zip)";
+    }
+} // XMLFilter
diff --git a/forester/java/src/org/forester/archaeopteryx/MainPanel.java b/forester/java/src/org/forester/archaeopteryx/MainPanel.java
new file mode 100644 (file)
index 0000000..42332d4
--- /dev/null
@@ -0,0 +1,407 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// Copyright (C) 2000-2001 Washington University School of Medicine
+// and Howard Hughes Medical Institute
+// Copyright (C) 2003-2007 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.AdjustmentEvent;
+import java.awt.event.AdjustmentListener;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ComponentListener;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTabbedPane;
+import javax.swing.SwingConstants;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.forester.archaeopteryx.phylogeny.data.RenderableDomainArchitecture;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.util.ForesterUtil;
+
+public class MainPanel extends JPanel implements ComponentListener {
+
+    private static final long                serialVersionUID = -2682765312661416435L;
+    MainFrame                                _mainframe;
+    List<TreePanel>                          _treepanels;
+    ControlPanel                             _control_panel;
+    private List<JScrollPane>                _treegraphic_scroll_panes;
+    private List<JPanel>                     _treegraphic_scroll_pane_panels;
+    Configuration                            _configuration;
+    private JTabbedPane                      _tabbed_pane;
+    private TreeColorSet                     _colorset;
+    private TreeFontSet                      _fontset;
+    private Phylogeny                        _cut_or_copied_tree;
+    private Set<Integer>                     _copied_and_pasted_nodes;
+    private Hashtable<String, BufferedImage> _image_map;
+
+    MainPanel() {
+    }
+
+    MainPanel( final Configuration configuration, final MainFrame parent ) {
+        if ( configuration == null ) {
+            throw new IllegalArgumentException( "configuration is null" );
+        }
+        addComponentListener( this );
+        _configuration = configuration;
+        _mainframe = parent;
+        _treepanels = new ArrayList<TreePanel>();
+        initialize();
+        _control_panel = new ControlPanel( this, configuration );
+        add( _control_panel, BorderLayout.WEST );
+        setupTreeGraphic( configuration, getControlPanel() );
+        getControlPanel().showWhole();
+    }
+
+    void addPhylogenyInNewTab( final Phylogeny phy,
+                               final Configuration config,
+                               final String default_name,
+                               final String full_path ) {
+        final TreePanel treepanel = new TreePanel( phy, config, this );
+        getControlPanel().phylogenyAdded( config );
+        treepanel.setControlPanel( getControlPanel() );
+        _treepanels.add( treepanel );
+        String name = "";
+        if ( !ForesterUtil.isEmpty( phy.getName() ) ) {
+            name = phy.getName();
+        }
+        else if ( phy.getIdentifier() != null ) {
+            name = phy.getIdentifier().toString();
+        }
+        else if ( !ForesterUtil.isEmpty( default_name ) ) {
+            name = default_name;
+        }
+        else {
+            name = "[" + ( getTabbedPane().getTabCount() + 1 ) + "]";
+        }
+        final JScrollPane treegraphic_scroll_pane = new JScrollPane( treepanel );
+        treegraphic_scroll_pane.getHorizontalScrollBar().addAdjustmentListener( new AdjustmentListener() {
+
+            @Override
+            public void adjustmentValueChanged( final AdjustmentEvent e ) {
+                if ( treepanel.isOvOn() || getOptions().isShowScale() ) {
+                    treepanel.repaint();
+                }
+            }
+        } );
+        treegraphic_scroll_pane.getVerticalScrollBar().addAdjustmentListener( new AdjustmentListener() {
+
+            @Override
+            public void adjustmentValueChanged( final AdjustmentEvent e ) {
+                if ( treepanel.isOvOn() || getOptions().isShowScale() ) {
+                    treepanel.repaint();
+                    //System.out.println( e.getValue() );
+                }
+            }
+        } );
+        treegraphic_scroll_pane.getHorizontalScrollBar().setUnitIncrement( 10 );
+        treegraphic_scroll_pane.getHorizontalScrollBar().setBlockIncrement( 200 );
+        treegraphic_scroll_pane.getVerticalScrollBar().setUnitIncrement( 10 );
+        treegraphic_scroll_pane.getVerticalScrollBar().setBlockIncrement( 200 );
+        final JPanel treegraphic_scroll_pane_panel = new JPanel();
+        treegraphic_scroll_pane_panel.setLayout( new BorderLayout() );
+        treegraphic_scroll_pane_panel.add( treegraphic_scroll_pane, BorderLayout.CENTER );
+        _treegraphic_scroll_pane_panels.add( treegraphic_scroll_pane_panel );
+        _treegraphic_scroll_panes.add( treegraphic_scroll_pane );
+        getTabbedPane().addTab( name,
+                                null,
+                                treegraphic_scroll_pane_panel,
+                                Util.createDescriptionForTab( phy, full_path ) );
+        getTabbedPane().setSelectedIndex( getTabbedPane().getTabCount() - 1 );
+        getControlPanel().showWhole();
+    }
+
+    void addPhylogenyInPanel( final Phylogeny phy, final Configuration config ) {
+        final TreePanel treepanel = new TreePanel( phy, config, this );
+        getControlPanel().phylogenyAdded( config );
+        treepanel.setControlPanel( getControlPanel() );
+        _treepanels.add( treepanel );
+        final JScrollPane treegraphic_scroll_pane = new JScrollPane( treepanel );
+        treegraphic_scroll_pane.getHorizontalScrollBar().setUnitIncrement( 20 );
+        treegraphic_scroll_pane.getHorizontalScrollBar().setBlockIncrement( 50 );
+        treegraphic_scroll_pane.getVerticalScrollBar().setUnitIncrement( 20 );
+        treegraphic_scroll_pane.getVerticalScrollBar().setBlockIncrement( 50 );
+        final JPanel treegraphic_scroll_pane_panel = new JPanel();
+        treegraphic_scroll_pane_panel.setLayout( new BorderLayout() );
+        treegraphic_scroll_pane_panel.add( treegraphic_scroll_pane, BorderLayout.CENTER );
+        _treegraphic_scroll_pane_panels.add( treegraphic_scroll_pane_panel );
+        _treegraphic_scroll_panes.add( treegraphic_scroll_pane );
+        add( treegraphic_scroll_pane_panel, BorderLayout.CENTER );
+    }
+
+    void adjustJScrollPane() {
+        if ( getTabbedPane() != null ) {
+            getCurrentScrollPanePanel().remove( getCurrentScrollPane() );
+            getCurrentScrollPanePanel().add( getCurrentScrollPane(), BorderLayout.CENTER );
+        }
+        getCurrentScrollPane().revalidate();
+    }
+
+    void closeCurrentPane() {
+        final int index = getCurrentTabIndex();
+        if ( ( index >= 0 ) && ( getTabbedPane().getTabCount() > 0 ) ) {
+            getTabbedPane().remove( index );
+            getTreePanels().remove( index );
+            _treegraphic_scroll_panes.remove( index );
+            _treegraphic_scroll_pane_panels.remove( index );
+            getControlPanel().phylogenyRemoved( index );
+        }
+    }
+
+    @Override
+    public void componentHidden( final ComponentEvent e ) {
+        // Do nothing.
+    }
+
+    @Override
+    public void componentMoved( final ComponentEvent e ) {
+        // Do nothing.
+    }
+
+    @Override
+    public void componentResized( final ComponentEvent e ) {
+        if ( getCurrentTreePanel() != null ) {
+            getCurrentTreePanel().updateOvSettings();
+            getCurrentTreePanel().updateOvSizes();
+        }
+    }
+
+    @Override
+    public void componentShown( final ComponentEvent e ) {
+        // Do nothing.
+    }
+
+    private Configuration getConfiguration() {
+        return _configuration;
+    }
+
+    ControlPanel getControlPanel() {
+        return _control_panel;
+    }
+
+    public Set<Integer> getCopiedAndPastedNodes() {
+        return _copied_and_pasted_nodes;
+    }
+
+    Phylogeny getCurrentPhylogeny() {
+        if ( getCurrentTreePanel() == null ) {
+            return null;
+        }
+        return getCurrentTreePanel().getPhylogeny();
+    }
+
+    JScrollPane getCurrentScrollPane() {
+        if ( _treegraphic_scroll_panes.size() > 0 ) {
+            final int selected = _tabbed_pane.getSelectedIndex();
+            if ( selected >= 0 ) {
+                return _treegraphic_scroll_panes.get( selected );
+            }
+            else {
+                return _treegraphic_scroll_panes.get( 0 );
+            }
+        }
+        else {
+            return null;
+        }
+    }
+
+    JPanel getCurrentScrollPanePanel() {
+        final int selected = _tabbed_pane.getSelectedIndex();
+        if ( selected >= 0 ) {
+            return _treegraphic_scroll_pane_panels.get( selected );
+        }
+        else {
+            return _treegraphic_scroll_pane_panels.get( 0 );
+        }
+    }
+
+    int getCurrentTabIndex() {
+        final int selected = _tabbed_pane.getSelectedIndex();
+        if ( selected >= 0 ) {
+            return selected;
+        }
+        else {
+            return 0;
+        }
+    }
+
+    TreePanel getCurrentTreePanel() {
+        final int selected = getTabbedPane().getSelectedIndex();
+        if ( selected >= 0 ) {
+            return _treepanels.get( selected );
+        }
+        else {
+            if ( _treepanels.size() == 1 ) {
+                return _treepanels.get( 0 );
+            }
+            else {
+                return null;
+            }
+        }
+    }
+
+    Phylogeny getCutOrCopiedTree() {
+        return _cut_or_copied_tree;
+    }
+
+    MainFrame getMainFrame() {
+        return _mainframe;
+    }
+
+    public Options getOptions() {
+        return _mainframe.getOptions();
+    }
+
+    Phylogeny getPhylogeny( final int index ) {
+        if ( getCurrentTreePanel() == null ) {
+            return null;
+        }
+        return _treepanels.get( index ).getPhylogeny();
+    }
+
+    Dimension getSizeOfViewport() {
+        return getCurrentScrollPane().getViewport().getExtentSize();
+    }
+
+    JTabbedPane getTabbedPane() {
+        return _tabbed_pane;
+    }
+
+    TreeColorSet getTreeColorSet() {
+        return _colorset;
+    }
+
+    public TreeFontSet getTreeFontSet() {
+        return _fontset;
+    }
+
+    List<TreePanel> getTreePanels() {
+        return _treepanels;
+    }
+
+    void initialize() {
+        if ( !getConfiguration().isUseNativeUI() ) {
+            setBackground( getConfiguration().getGuiBackgroundColor() );
+        }
+        setTreeFontSet( new TreeFontSet( this ) );
+        getTreeFontSet().setBaseFont( getOptions().getBaseFont() );
+        setLayout( new BorderLayout() );
+        setTreeColorSet( TreeColorSet.createInstance( getConfiguration() ) );
+        _treegraphic_scroll_panes = new ArrayList<JScrollPane>();
+        _treegraphic_scroll_pane_panels = new ArrayList<JPanel>();
+        _tabbed_pane = new JTabbedPane( SwingConstants.TOP );
+        if ( !getConfiguration().isUseNativeUI() ) {
+            _tabbed_pane.setBackground( getConfiguration().getGuiBackgroundColor() );
+            _tabbed_pane.setForeground( getConfiguration().getGuiBackgroundColor() );
+        }
+        _tabbed_pane.addChangeListener( new ChangeListener() {
+
+            // This method is called whenever the selected tab changes
+            public void stateChanged( final ChangeEvent evt ) {
+                final JTabbedPane pane = ( JTabbedPane ) evt.getSource();
+                getControlPanel().tabChanged();
+                // Get current tab
+                final int sel = pane.getSelectedIndex();
+                if ( sel >= 0 ) {
+                    if ( !getConfiguration().isUseNativeUI() ) {
+                        if ( _tabbed_pane.getTabCount() > 0 ) {
+                            _tabbed_pane.setForegroundAt( sel, Constants.TAB_LABEL_FOREGROUND_COLOR_SELECTED );
+                            for( int i = 0; i < _tabbed_pane.getTabCount(); ++i ) {
+                                if ( i != sel ) {
+                                    _tabbed_pane.setBackgroundAt( i, getConfiguration().getGuiBackgroundColor() );
+                                    _tabbed_pane.setForegroundAt( i, getConfiguration().getGuiCheckboxTextColor() );
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } );
+        if ( !getConfiguration().isUseNativeUI() ) {
+            _tabbed_pane.setFont( ControlPanel.jcb_font );
+        }
+        _tabbed_pane.setTabLayoutPolicy( JTabbedPane.SCROLL_TAB_LAYOUT );
+        add( _tabbed_pane, BorderLayout.CENTER );
+    }
+
+    public void setArrowCursor() {
+        setCursor( TreePanel.ARROW_CURSOR );
+        repaint();
+    }
+
+    public void setCopiedAndPastedNodes( final Set<Integer> node_ids ) {
+        _copied_and_pasted_nodes = node_ids;
+    }
+
+    void setCutOrCopiedTree( final Phylogeny cut_or_copied_tree ) {
+        _cut_or_copied_tree = cut_or_copied_tree;
+    }
+
+    void setTreeColorSet( final TreeColorSet colorset ) {
+        _colorset = colorset;
+        for( final TreePanel p : getTreePanels() ) {
+            p.setBackground( colorset.getBackgroundColor() );
+        }
+    }
+
+    void setTreeFontSet( final TreeFontSet fontset ) {
+        _fontset = fontset;
+    }
+
+    void setupTreeGraphic( final Configuration config_settings, final ControlPanel control ) {
+        control.setSpeciesColors( config_settings.getSpeciesColors() );
+        control.setAnnotationColors( config_settings.getAnnotationColors() );
+        RenderableDomainArchitecture.setColorMap( config_settings.getDomainColors() );
+    }
+
+    public void setWaitCursor() {
+        setCursor( TreePanel.WAIT_CURSOR );
+        repaint();
+    }
+
+    void terminate() {
+        for( final TreePanel atvtreepanel : _treepanels ) {
+            atvtreepanel.removeAllEditNodeJFrames();
+        }
+    }
+
+    synchronized void setImageMap( final Hashtable<String, BufferedImage> image_map ) {
+        _image_map = image_map;
+    }
+
+    synchronized Hashtable<String, BufferedImage> getImageMap() {
+        return _image_map;
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/MainPanelApplets.java b/forester/java/src/org/forester/archaeopteryx/MainPanelApplets.java
new file mode 100644 (file)
index 0000000..226c2db
--- /dev/null
@@ -0,0 +1,90 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// Copyright (C) 2000-2001 Washington University School of Medicine
+// and Howard Hughes Medical Institute
+// Copyright (C) 2003-2007 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.BorderLayout;
+import java.util.ArrayList;
+
+import javax.swing.JApplet;
+
+final class MainPanelApplets extends MainPanel {
+
+    private static final long serialVersionUID = -7142615479464963140L;
+    private final JApplet     _applet;
+
+    public MainPanelApplets( final Configuration configuration, final ArchaeopteryxE em_applet ) {
+        if ( configuration == null ) {
+            throw new IllegalArgumentException( "configuration is null" );
+        }
+        addComponentListener( this );
+        _configuration = configuration;
+        _mainframe = null;
+        _treepanels = new ArrayList<TreePanel>();
+        _applet = em_applet;
+        initialize();
+        _control_panel = new ControlPanel( this, configuration );
+        if ( !configuration.isHideControlPanelAndMenubar() ) {
+            add( _control_panel, BorderLayout.WEST );
+        }
+        setupTreeGraphic( configuration, getControlPanel() );
+    }
+
+    public MainPanelApplets( final Configuration configuration, final MainFrameApplet aaf ) {
+        if ( configuration == null ) {
+            throw new IllegalArgumentException( "configuration is null" );
+        }
+        addComponentListener( this );
+        _configuration = configuration;
+        _mainframe = aaf;
+        _treepanels = new ArrayList<TreePanel>();
+        _applet = aaf.getApplet();
+        initialize();
+        _control_panel = new ControlPanel( this, configuration );
+        add( _control_panel, BorderLayout.WEST );
+        setupTreeGraphic( configuration, getControlPanel() );
+    }
+
+    JApplet getApplet() {
+        return _applet;
+    }
+
+    MainFrameApplet getAppletFrame() {
+        return ( MainFrameApplet ) _mainframe;
+    }
+
+    @Override
+    public Options getOptions() {
+        if ( _mainframe != null ) {
+            return _mainframe.getOptions();
+        }
+        else {
+            return ( ( ArchaeopteryxE ) _applet ).getOptions();
+        }
+    }
+}
\ No newline at end of file
diff --git a/forester/java/src/org/forester/archaeopteryx/MainPanelEdit.java b/forester/java/src/org/forester/archaeopteryx/MainPanelEdit.java
new file mode 100644 (file)
index 0000000..b2b7bdd
--- /dev/null
@@ -0,0 +1,136 @@
+// $Id:
+// forester -- software libraries and applications
+// for genomics and evolutionary biology research.
+//
+// Copyright (C) 2010 Christian M Zmasek
+// Copyright (C) 2010 Sanford-Burnham Medical Research Institute
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+
+import org.forester.phylogeny.Phylogeny;
+import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.Accession;
+import org.forester.phylogeny.data.Annotation;
+import org.forester.phylogeny.data.Sequence;
+import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
+import org.forester.util.ForesterUtil;
+
+public class MainPanelEdit implements Runnable {
+
+    private static final String        SYMBOL   = "Symbol";
+    private static final String        ASPECT   = "Aspect";
+    private static final String        DB       = "DB";
+    private static final String        EVIDENCE = "Evidence";
+    private static final String        GO_NAME  = "GO Name";
+    private static final String        GO_ID    = "GO ID";
+    private final Phylogeny            _phy;
+    private final MainFrameApplication _mf;
+    private final TreePanel            _treepanel;
+
+    MainPanelEdit( final MainFrameApplication mf, final TreePanel treepanel, final Phylogeny phy ) {
+        _phy = phy;
+        _mf = mf;
+        _treepanel = treepanel;
+    }
+
+    private void annotate() {
+        _mf.getMainPanel().getCurrentTreePanel().setWaitCursor();
+        for( final PhylogenyNodeIterator iter = _phy.iteratorPostorder(); iter.hasNext(); ) {
+            final PhylogenyNode node = iter.next();
+            if ( ( node.getNodeData().getSequences() != null ) && !node.getNodeData().getSequences().isEmpty() ) {
+                for( final Sequence seq : node.getNodeData().getSequences() ) {
+                    if ( ( ( seq.getAccession() != null ) && !ForesterUtil.isEmpty( seq.getAccession().getValue() ) && ( seq
+                            .getAnnotations() == null ) )
+                            || seq.getAnnotations().isEmpty() ) {
+                        final Accession acc = seq.getAccession();
+                        try {
+                            final URL url = new URL( "http://www.ebi.ac.uk/QuickGO/GAnnotation?protein="
+                                    + acc.getValue() + "&format=tsv" );
+                            final HttpURLConnection url_connection = ( HttpURLConnection ) url.openConnection();
+                            final BufferedReader br = new BufferedReader( new InputStreamReader( url_connection
+                                    .getInputStream() ) );
+                            final List<String> columns = Arrays.asList( br.readLine().split( "\t" ) );
+                            System.out.println( columns );
+                            final int db_index = columns.indexOf( DB );
+                            final int goid_index = columns.indexOf( GO_ID );
+                            final int name_index = columns.indexOf( GO_NAME );
+                            final int evidence_index = columns.indexOf( EVIDENCE );
+                            final int taxon_index = columns.indexOf( "Taxon" );
+                            final int qualifier_index = columns.indexOf( "Qualifier" );
+                            final int reference_index = columns.indexOf( "Reference" );
+                            final int symbol_index = columns.indexOf( SYMBOL );
+                            final int splice_index = columns.indexOf( "Splice" );
+                            final int with_index = columns.indexOf( "With" );
+                            final int aspect_index = columns.indexOf( ASPECT );
+                            final int source_index = columns.indexOf( "Source" );
+                            String line;
+                            while ( ( line = br.readLine() ) != null ) {
+                                final String[] fields = line.split( "\t" );
+                                final Annotation a = new Annotation( fields[ goid_index ] );
+                                a.setDesc( name_index >= 0 ? fields[ name_index ] : "" );
+                                a.setSource( db_index >= 0 ? fields[ db_index ] : "" );
+                                a.setEvidence( evidence_index >= 0 ? fields[ evidence_index ] : "" );
+                                a.setType( aspect_index >= 0 ? fields[ aspect_index ] : "" );
+                                seq.addAnnotation( a );
+                                if ( ForesterUtil.isEmpty( seq.getSymbol() ) && ( symbol_index >= 0 )
+                                        && !ForesterUtil.isEmpty( fields[ symbol_index ] ) ) {
+                                    seq.setSymbol( fields[ symbol_index ] );
+                                }
+                                System.out.println( DB + ": " + fields[ db_index ] );
+                                System.out.println( GO_ID + ": " + fields[ goid_index ] );
+                                System.out.println( GO_NAME + ": " + fields[ name_index ] );
+                                System.out.println( EVIDENCE + ": " + fields[ evidence_index ] );
+                                System.out.println( " taxon" + ": " + fields[ taxon_index ] );
+                                System.out.println( " qualifier" + ": " + fields[ qualifier_index ] );
+                                System.out.println( " reference" + ": " + fields[ reference_index ] );
+                                System.out.println( SYMBOL + ": " + fields[ symbol_index ] );
+                                System.out.println( " splice" + ": " + fields[ splice_index ] );
+                                System.out.println( " with" + ": " + fields[ with_index ] );
+                                System.out.println( ASPECT + ": " + fields[ aspect_index ] );
+                                System.out.println( " source" + ": " + fields[ source_index ] );
+                            }
+                            br.close();
+                        }
+                        catch ( final IOException e ) {
+                            // TODO Auto-generated catch block
+                            e.printStackTrace();
+                        }
+                    }
+                }
+            }
+        }
+        _treepanel.repaint();
+        _treepanel.setEdited( true );
+    }
+
+    @Override
+    public void run() {
+        annotate();
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/MouseListener.java b/forester/java/src/org/forester/archaeopteryx/MouseListener.java
new file mode 100644 (file)
index 0000000..628d0b6
--- /dev/null
@@ -0,0 +1,115 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// Copyright (C) 2000-2001 Washington University School of Medicine
+// and Howard Hughes Medical Institute
+// Copyright (C) 2003-2007 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.Point;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+
+/*
+ * @author Christian Zmasek
+ */
+final class MouseListener extends MouseAdapter implements MouseMotionListener {
+
+    private final TreePanel _treepanel;
+    private boolean         _being_dragged = false;
+    private final Point     _click_point   = new Point();
+
+    /**
+     * Constructor.
+     */
+    MouseListener( final TreePanel tp ) {
+        _treepanel = tp;
+    }
+
+    /**
+     * Mouse clicked.
+     */
+    @Override
+    public void mouseClicked( final MouseEvent e ) {
+        _click_point.setLocation( e.getX(), e.getY() );
+        _treepanel.mouseClicked( e );
+    }
+
+    @Override
+    public void mouseDragged( final MouseEvent e ) {
+        if ( ( e.getModifiersEx() == InputEvent.BUTTON1_DOWN_MASK )
+                || ( e.getModifiersEx() == InputEvent.BUTTON3_DOWN_MASK ) ) {
+            if ( !_treepanel.inOvRectangle( e ) ) {
+                if ( !_being_dragged ) {
+                    _being_dragged = true;
+                    _treepanel.setLastMouseDragPointX( e.getX() );
+                    _treepanel.setLastMouseDragPointY( e.getY() );
+                }
+                _treepanel.mouseDragInBrowserPanel( e );
+            }
+            else {
+                if ( !_being_dragged ) {
+                    _being_dragged = true;
+                    _treepanel.setLastMouseDragPointX( e.getX() );
+                    _treepanel.setLastMouseDragPointY( e.getY() );
+                }
+                _treepanel.mouseDragInOvRectangle( e );
+            }
+        }
+    }
+
+    @Override
+    public void mouseMoved( final MouseEvent e ) {
+        _treepanel.mouseMoved( e );
+    }
+
+    @Override
+    public void mousePressed( final MouseEvent e ) {
+        //TODO is this a good idea? It is certainly not NEEDED.
+        if ( e.getModifiersEx() == InputEvent.BUTTON1_DOWN_MASK ) {
+            if ( !_being_dragged ) {
+                _being_dragged = true;
+                _treepanel.setLastMouseDragPointX( e.getX() );
+                _treepanel.setLastMouseDragPointY( e.getY() );
+            }
+            if ( !_treepanel.inOvRectangle( e ) ) {
+                _treepanel.mouseDragInBrowserPanel( e );
+            }
+            else {
+                _treepanel.mouseDragInOvRectangle( e );
+            }
+        }
+    }
+
+    @Override
+    public void mouseReleased( final MouseEvent e ) {
+        if ( _being_dragged ) {
+            _being_dragged = false;
+        }
+        _treepanel.mouseReleasedInBrowserPanel( e );
+    }
+}
\ No newline at end of file
diff --git a/forester/java/src/org/forester/archaeopteryx/NodeEditPanel.java b/forester/java/src/org/forester/archaeopteryx/NodeEditPanel.java
new file mode 100644 (file)
index 0000000..beab4f2
--- /dev/null
@@ -0,0 +1,1061 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/
+
+package org.forester.archaeopteryx;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.JEditorPane;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTree;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.text.Position;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+
+import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
+import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.Accession;
+import org.forester.phylogeny.data.Confidence;
+import org.forester.phylogeny.data.Date;
+import org.forester.phylogeny.data.Distribution;
+import org.forester.phylogeny.data.Event;
+import org.forester.phylogeny.data.Identifier;
+import org.forester.phylogeny.data.MultipleUris;
+import org.forester.phylogeny.data.PhylogenyData;
+import org.forester.phylogeny.data.Point;
+import org.forester.phylogeny.data.Reference;
+import org.forester.phylogeny.data.Sequence;
+import org.forester.phylogeny.data.Taxonomy;
+import org.forester.phylogeny.data.Uri;
+import org.forester.util.FailedConditionCheckException;
+import org.forester.util.ForesterUtil;
+
+class NodeEditPanel extends JPanel {
+
+    private static final long                            serialVersionUID = 5120159904388100771L;
+    private final JTree                                  _tree;
+    private final JEditorPane                            _pane;
+    private final PhylogenyNode                          _my_node;
+    private final TreePanel                              _tree_panel;
+    private final Map<DefaultMutableTreeNode, TagNumber> _map;
+
+    public NodeEditPanel( final PhylogenyNode phylogeny_node, final TreePanel tree_panel ) {
+        _map = new HashMap<DefaultMutableTreeNode, TagNumber>();
+        _my_node = phylogeny_node;
+        _tree_panel = tree_panel;
+        String node_name = "";
+        if ( !ForesterUtil.isEmpty( phylogeny_node.getName() ) ) {
+            node_name = phylogeny_node.getName() + " ";
+        }
+        final DefaultMutableTreeNode top = new DefaultMutableTreeNode( "Node " + node_name );
+        createNodes( top, phylogeny_node );
+        _tree = new JTree( top );
+        getJTree().setEditable( true );
+        getJTree().setFocusable( true );
+        getJTree().setToggleClickCount( 1 );
+        getJTree().setInvokesStopCellEditing( true );
+        final JScrollPane tree_view = new JScrollPane( getJTree() );
+        _pane = new JEditorPane();
+        _pane.setEditable( true );
+        final JScrollPane data_view = new JScrollPane( _pane );
+        final JSplitPane split_pane = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
+        split_pane.setTopComponent( tree_view );
+        // split_pane.setBottomComponent( data_view );
+        data_view.setMinimumSize( Constants.NODE_PANEL_SPLIT_MINIMUM_SIZE );
+        tree_view.setMinimumSize( Constants.NODE_PANEL_SPLIT_MINIMUM_SIZE );
+        // split_pane.setDividerLocation( 400 );
+        split_pane.setPreferredSize( Constants.NODE_PANEL_SIZE );
+        add( split_pane );
+        getJTree().getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
+        getJTree().addKeyListener( new KeyListener() {
+
+            @Override
+            public void keyPressed( final KeyEvent e ) {
+                keyEvent( e );
+            }
+
+            @Override
+            public void keyReleased( final KeyEvent e ) {
+                keyEvent( e );
+            }
+
+            @Override
+            public void keyTyped( final KeyEvent e ) {
+                keyEvent( e );
+            }
+        } );
+        for( int i = 0; i < getJTree().getRowCount(); i++ ) {
+            getJTree().expandRow( i );
+        }
+        collapsePath( NodePanel.BASIC );
+        collapsePath( NodePanel.TAXONOMY );
+        collapsePath( NodePanel.SEQUENCE );
+        collapsePath( NodePanel.EVENTS );
+        collapsePath( NodePanel.DATE );
+        collapsePath( NodePanel.DISTRIBUTION );
+        collapsePath( NodePanel.LIT_REFERENCE );
+        getJTree().addTreeSelectionListener( new TreeSelectionListener() {
+
+            @Override
+            public void valueChanged( final TreeSelectionEvent e ) {
+                final TreePath new_path = e.getNewLeadSelectionPath();
+                final TreePath old_path = e.getOldLeadSelectionPath();
+                if ( new_path != null ) {
+                    writeBack( ( DefaultMutableTreeNode ) new_path.getLastPathComponent() );
+                }
+                if ( old_path != null ) {
+                    writeBack( ( DefaultMutableTreeNode ) old_path.getLastPathComponent() );
+                }
+            }
+        } );
+    }
+
+    private void addBasics( final DefaultMutableTreeNode top, final PhylogenyNode phylogeny_node, final String name ) {
+        final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        addSubelementEditable( category, NodePanel.NODE_NAME, phylogeny_node.getName(), PHYLOXML_TAG.NODE_NAME );
+        String bl = "";
+        if ( phylogeny_node.getDistanceToParent() != PhylogenyNode.DISTANCE_DEFAULT ) {
+            bl = ForesterUtil.FORMATTER_6.format( phylogeny_node.getDistanceToParent() );
+        }
+        addSubelementEditable( category, NodePanel.NODE_BRANCH_LENGTH, bl, PHYLOXML_TAG.NODE_BRANCH_LENGTH );
+        int counter = 0;
+        if ( phylogeny_node.getBranchData().isHasConfidences() ) {
+            for( int i = phylogeny_node.getBranchData().getConfidences().size() - 1; i >= 0; i-- ) {
+                if ( phylogeny_node.getBranchData().getConfidences().get( i ).getValue() == Confidence.CONFIDENCE_DEFAULT_VALUE ) {
+                    phylogeny_node.getBranchData().getConfidences().remove( i );
+                }
+            }
+            for( final PhylogenyData conf : phylogeny_node.getBranchData().getConfidences() ) {
+                final Confidence my_conf = ( Confidence ) ( conf );
+                addSubelementEditable( category,
+                                       NodePanel.CONFIDENCE + " [" + counter + "]",
+                                       ForesterUtil.FORMATTER_6.format( my_conf.getValue() ),
+                                       PHYLOXML_TAG.CONFIDENCE_VALUE,
+                                       NodePanel.CONFIDENCE_TYPE,
+                                       my_conf.getType(),
+                                       PHYLOXML_TAG.CONFIDENCE_TYPE,
+                                       counter++ );
+            }
+        }
+        addSubelementEditable( category,
+                               NodePanel.CONFIDENCE + " [" + counter + "]",
+                               "",
+                               PHYLOXML_TAG.CONFIDENCE_VALUE,
+                               NodePanel.CONFIDENCE_TYPE,
+                               "",
+                               PHYLOXML_TAG.CONFIDENCE_TYPE,
+                               counter );
+    }
+
+    //    private void addAnnotation( final DefaultMutableTreeNode top, final Annotation ann, final String name ) {
+    //        DefaultMutableTreeNode category;
+    //        category = new DefaultMutableTreeNode( name );
+    //        top.add( category );
+    //        addSubelementEditable( category, "Reference", ann.getRef() , PHYLOXML_TAG.);
+    //        addSubelementEditable( category, "Description", ann.getDesc() , PHYLOXML_TAG.);
+    //        addSubelementEditable( category, "Source", ann.getSource(), PHYLOXML_TAG. );
+    //        addSubelementEditable( category, "Type", ann.getType(), PHYLOXML_TAG. );
+    //        addSubelementEditable( category, "Evidence", ann.getEvidence() , PHYLOXML_TAG.);
+    //        if ( ann.getConfidence() != null ) {
+    //            addSubelementEditable( category, "Confidence", ann.getConfidence().asText().toString() , PHYLOXML_TAG.);
+    //        }
+    //        if ( ann.getProperties() != null ) {
+    //            addProperties( category, ann.getProperties(), "Properties", PHYLOXML_TAG. );
+    //        }
+    //    }
+    //    private void addAnnotations( final DefaultMutableTreeNode top,
+    //                                 final List<PhylogenyData> annotations,
+    //                                 final DefaultMutableTreeNode category ) {
+    //        if ( ( annotations != null ) && ( annotations.size() > 0 ) ) {
+    //            category.add( new DefaultMutableTreeNode( "Annotations" ) );
+    //            final DefaultMutableTreeNode last = top.getLastLeaf();
+    //            int i = 0;
+    //            for( final PhylogenyData ann : annotations ) {
+    //                addAnnotation( last, ( Annotation ) ann, "Annotation " + ( i++ ) );
+    //            }
+    //        }
+    //    }
+    private void addDate( final DefaultMutableTreeNode top, Date date, final String name ) {
+        if ( date == null ) {
+            date = new Date();
+        }
+        DefaultMutableTreeNode category;
+        category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        addSubelementEditable( category, NodePanel.DATE_DESCRIPTION, date.getDesc(), PHYLOXML_TAG.DATE_DESCRIPTION );
+        addSubelementEditable( category, NodePanel.DATE_VALUE, String.valueOf( date.getValue() != null ? date
+                .getValue() : "" ), PHYLOXML_TAG.DATE_VALUE );
+        addSubelementEditable( category, NodePanel.DATE_MIN, String
+                .valueOf( date.getMin() != null ? date.getMin() : "" ), PHYLOXML_TAG.DATE_MIN );
+        addSubelementEditable( category, NodePanel.DATE_MAX, String
+                .valueOf( date.getMax() != null ? date.getMax() : "" ), PHYLOXML_TAG.DATE_MAX );
+        addSubelementEditable( category, NodePanel.DATE_UNIT, date.getUnit(), PHYLOXML_TAG.DATE_UNIT );
+    }
+
+    private void addDistribution( final DefaultMutableTreeNode top, Distribution dist, final String name ) {
+        if ( dist == null ) {
+            dist = new Distribution( "" );
+        }
+        final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        Point p0 = null;
+        if ( ( dist.getPoints() != null ) && ( dist.getPoints().size() > 0 ) ) {
+            p0 = dist.getPoints().get( 0 );
+        }
+        else {
+            p0 = new Point();
+        }
+        addSubelementEditable( category, NodePanel.DIST_DESCRIPTION, dist.getDesc(), PHYLOXML_TAG.DIST_DESC );
+        addSubelementEditable( category,
+                               NodePanel.DIST_GEODETIC_DATUM,
+                               p0.getGeodeticDatum(),
+                               PHYLOXML_TAG.DIST_GEODETIC );
+        addSubelementEditable( category, NodePanel.DIST_LATITUDE, String.valueOf( p0.getLatitude() != null ? p0
+                .getLatitude() : "" ), PHYLOXML_TAG.DIST_LAT );
+        addSubelementEditable( category, NodePanel.DIST_LONGITUDE, String.valueOf( p0.getLongitude() != null ? p0
+                .getLongitude() : "" ), PHYLOXML_TAG.DIST_LONG );
+        addSubelementEditable( category, NodePanel.DIST_ALTITUDE, String.valueOf( p0.getAltitude() != null ? p0
+                .getAltitude() : "" ), PHYLOXML_TAG.DIST_ALT );
+        addSubelementEditable( category, NodePanel.DIST_ALT_UNIT, String.valueOf( p0.getAltiudeUnit() != null ? p0
+                .getAltiudeUnit() : "" ), PHYLOXML_TAG.DIST_ALT_UNIT );
+    }
+
+    private void addEvents( final DefaultMutableTreeNode top, Event events, final String name ) {
+        final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
+        if ( events == null ) {
+            events = new Event();
+        }
+        top.add( category );
+        addSubelementEditable( category,
+                               NodePanel.EVENTS_DUPLICATIONS,
+                               String.valueOf( events.getNumberOfDuplications() >= 0 ? events.getNumberOfDuplications()
+                                       : 0 ),
+                               PHYLOXML_TAG.EVENTS_DUPLICATIONS );
+        addSubelementEditable( category,
+                               NodePanel.EVENTS_SPECIATIONS,
+                               String.valueOf( events.getNumberOfSpeciations() >= 0 ? events.getNumberOfSpeciations()
+                                       : 0 ),
+                               PHYLOXML_TAG.EVENTS_SPECIATIONS );
+        addSubelementEditable( category,
+                               NodePanel.EVENTS_GENE_LOSSES,
+                               String
+                                       .valueOf( events.getNumberOfGeneLosses() >= 0 ? events.getNumberOfGeneLosses()
+                                               : 0 ),
+                               PHYLOXML_TAG.EVENTS_GENE_LOSSES );
+    }
+
+    private void addMapping( final DefaultMutableTreeNode mtn, final TagNumber tag ) {
+        if ( getMap().containsKey( mtn ) ) {
+            throw new IllegalArgumentException( "key " + mtn + " already present" );
+        }
+        if ( getMap().containsValue( tag ) ) {
+            throw new IllegalArgumentException( "value " + tag + " already present" );
+        }
+        getMap().put( mtn, tag );
+    }
+
+    private void addReference( final DefaultMutableTreeNode top, Reference ref, final String name ) {
+        if ( ref == null ) {
+            ref = new Reference( "" );
+        }
+        final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        addSubelementEditable( category,
+                               NodePanel.LIT_REFERENCE_DESC,
+                               ref.getDescription(),
+                               PHYLOXML_TAG.LIT_REFERENCE_DESC );
+        addSubelementEditable( category, NodePanel.LIT_REFERENCE_DOI, ref.getDoi(), PHYLOXML_TAG.LIT_REFERENCE_DOI );
+    }
+
+    private void addSequence( final DefaultMutableTreeNode top, Sequence seq, final String name ) {
+        if ( seq == null ) {
+            seq = new Sequence();
+        }
+        final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        Accession acc = seq.getAccession();
+        if ( acc == null ) {
+            acc = new Accession( "", "" );
+        }
+        addSubelementEditable( category, NodePanel.SEQ_NAME, seq.getName(), PHYLOXML_TAG.SEQ_NAME );
+        addSubelementEditable( category, NodePanel.SEQ_SYMBOL, seq.getSymbol(), PHYLOXML_TAG.SEQ_SYMBOL );
+        addSubelementEditable( category,
+                               NodePanel.SEQ_ACCESSION,
+                               acc.getValue(),
+                               PHYLOXML_TAG.SEQ_ACC_VALUE,
+                               "Source",
+                               acc.getSource(),
+                               PHYLOXML_TAG.SEQ_ACC_SOURCE );
+        addSubelementEditable( category, NodePanel.SEQ_LOCATION, seq.getLocation(), PHYLOXML_TAG.SEQ_LOCATION );
+        addSubelementEditable( category, NodePanel.SEQ_TYPE, seq.getType(), PHYLOXML_TAG.SEQ_TYPE );
+        addSubelementEditable( category, NodePanel.SEQ_MOL_SEQ, seq.getMolecularSequence(), PHYLOXML_TAG.SEQ_MOL_SEQ );
+        int uri_counter = 0;
+        if ( seq.getUris() != null ) {
+            for( final Uri uri : seq.getUris() ) {
+                if ( uri != null ) {
+                    addSubelementEditable( category, NodePanel.SEQ_URI + " [" + uri_counter + "]", uri.getValue()
+                            .toString(), PHYLOXML_TAG.SEQ_URI, uri_counter++ );
+                }
+            }
+        }
+        addSubelementEditable( category,
+                               NodePanel.SEQ_URI + " [" + uri_counter + "]",
+                               "",
+                               PHYLOXML_TAG.SEQ_URI,
+                               uri_counter );
+        //  addAnnotations( top, seq.getAnnotations(), category );
+    }
+
+    private void addSubelementEditable( final DefaultMutableTreeNode node,
+                                        final String name,
+                                        final String value,
+                                        final PHYLOXML_TAG phyloxml_tag ) {
+        addSubelementEditable( node, name, value, phyloxml_tag, 0 );
+    }
+
+    private void addSubelementEditable( final DefaultMutableTreeNode node,
+                                        final String name,
+                                        final String value,
+                                        final PHYLOXML_TAG phyloxml_tag,
+                                        final int number ) {
+        String my_value = value;
+        if ( ForesterUtil.isEmpty( my_value ) ) {
+            my_value = "";
+        }
+        final DefaultMutableTreeNode name_node = new DefaultMutableTreeNode( name );
+        final DefaultMutableTreeNode value_node = new DefaultMutableTreeNode( my_value );
+        name_node.add( value_node );
+        node.add( name_node );
+        addMapping( name_node, new TagNumber( phyloxml_tag, number ) );
+    }
+
+    private void addSubelementEditable( final DefaultMutableTreeNode node,
+                                        final String name,
+                                        final String value,
+                                        final PHYLOXML_TAG phyloxml_value_tag,
+                                        final String source_name,
+                                        final String source_value,
+                                        final PHYLOXML_TAG phyloxml_source_tag ) {
+        addSubelementEditable( node, name, value, phyloxml_value_tag, source_name, source_value, phyloxml_source_tag, 0 );
+    }
+
+    private void addSubelementEditable( final DefaultMutableTreeNode node,
+                                        final String name,
+                                        final String value,
+                                        final PHYLOXML_TAG phyloxml_value_tag,
+                                        final String source_name,
+                                        final String source_value,
+                                        final PHYLOXML_TAG phyloxml_source_tag,
+                                        final int number ) {
+        String my_value = value;
+        if ( ForesterUtil.isEmpty( my_value ) ) {
+            my_value = "";
+        }
+        String my_source_value = source_value;
+        if ( ForesterUtil.isEmpty( my_source_value ) ) {
+            my_source_value = "";
+        }
+        final DefaultMutableTreeNode name_node = new DefaultMutableTreeNode( name );
+        final DefaultMutableTreeNode source_name_node = new DefaultMutableTreeNode( source_name );
+        final DefaultMutableTreeNode source_value_node = new DefaultMutableTreeNode( my_source_value );
+        final DefaultMutableTreeNode value_node = new DefaultMutableTreeNode( my_value );
+        name_node.add( source_name_node );
+        source_name_node.add( source_value_node );
+        name_node.add( value_node );
+        node.add( name_node );
+        addMapping( name_node, new TagNumber( phyloxml_value_tag, number ) );
+        addMapping( source_name_node, new TagNumber( phyloxml_source_tag, number ) );
+    }
+
+    private void addTaxonomy( final DefaultMutableTreeNode top, Taxonomy tax, final String name ) {
+        if ( tax == null ) {
+            tax = new Taxonomy();
+        }
+        final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        Identifier id = tax.getIdentifier();
+        if ( id == null ) {
+            id = new Identifier();
+        }
+        addSubelementEditable( category,
+                               NodePanel.TAXONOMY_IDENTIFIER,
+                               id.getValue(),
+                               PHYLOXML_TAG.TAXONOMY_ID_VALUE,
+                               "Provider",
+                               id.getProvider(),
+                               PHYLOXML_TAG.TAXONOMY_ID_PROVIDER );
+        addSubelementEditable( category, NodePanel.TAXONOMY_CODE, tax.getTaxonomyCode(), PHYLOXML_TAG.TAXONOMY_CODE );
+        addSubelementEditable( category,
+                               NodePanel.TAXONOMY_SCIENTIFIC_NAME,
+                               tax.getScientificName(),
+                               PHYLOXML_TAG.TAXONOMY_SCIENTIFIC_NAME );
+        addSubelementEditable( category,
+                               NodePanel.TAXONOMY_AUTHORITY,
+                               tax.getAuthority(),
+                               PHYLOXML_TAG.TAXONOMY_AUTHORITY );
+        addSubelementEditable( category,
+                               NodePanel.TAXONOMY_COMMON_NAME,
+                               tax.getCommonName(),
+                               PHYLOXML_TAG.TAXONOMY_COMMON_NAME );
+        for( int i = tax.getSynonyms().size() - 1; i >= 0; i-- ) {
+            if ( ForesterUtil.isEmpty( tax.getSynonyms().get( i ) ) ) {
+                tax.getSynonyms().remove( i );
+            }
+        }
+        int syn_counter = 0;
+        for( final String syn : tax.getSynonyms() ) {
+            addSubelementEditable( category,
+                                   NodePanel.TAXONOMY_SYNONYM + " [" + syn_counter + "]",
+                                   syn,
+                                   PHYLOXML_TAG.TAXONOMY_SYNONYM,
+                                   syn_counter++ );
+        }
+        addSubelementEditable( category,
+                               NodePanel.TAXONOMY_SYNONYM + " [" + syn_counter + "]",
+                               "",
+                               PHYLOXML_TAG.TAXONOMY_SYNONYM,
+                               syn_counter );
+        addSubelementEditable( category, NodePanel.TAXONOMY_RANK, tax.getRank(), PHYLOXML_TAG.TAXONOMY_RANK );
+        int uri_counter = 0;
+        if ( tax.getUris() != null ) {
+            for( final Uri uri : tax.getUris() ) {
+                if ( uri != null ) {
+                    addSubelementEditable( category, NodePanel.TAXONOMY_URI + " [" + uri_counter + "]", uri.getValue()
+                            .toString(), PHYLOXML_TAG.TAXONOMY_URI, uri_counter++ );
+                }
+            }
+        }
+        addSubelementEditable( category,
+                               NodePanel.TAXONOMY_URI + " [" + uri_counter + "]",
+                               "",
+                               PHYLOXML_TAG.TAXONOMY_URI,
+                               uri_counter );
+    }
+
+    private void collapsePath( final String name ) {
+        final TreePath tp = getJTree().getNextMatch( name, 0, Position.Bias.Forward );
+        if ( tp != null ) {
+            getJTree().collapsePath( tp );
+        }
+    }
+
+    private void createNodes( final DefaultMutableTreeNode top, final PhylogenyNode phylogeny_node ) {
+        if ( !phylogeny_node.getNodeData().isHasTaxonomy() ) {
+            phylogeny_node.getNodeData().addTaxonomy( new Taxonomy() );
+        }
+        if ( !phylogeny_node.getNodeData().isHasSequence() ) {
+            phylogeny_node.getNodeData().addSequence( new Sequence() );
+        }
+        if ( !phylogeny_node.getNodeData().isHasDistribution() ) {
+            phylogeny_node.getNodeData().addDistribution( new Distribution( "" ) );
+        }
+        if ( !phylogeny_node.getNodeData().isHasReference() ) {
+            phylogeny_node.getNodeData().addReference( new Reference( "" ) );
+        }
+        addBasics( top, phylogeny_node, NodePanel.BASIC );
+        addTaxonomy( top, phylogeny_node.getNodeData().getTaxonomy(), NodePanel.TAXONOMY );
+        addSequence( top, phylogeny_node.getNodeData().getSequence(), NodePanel.SEQUENCE );
+        if ( !phylogeny_node.isExternal() ) {
+            addEvents( top, phylogeny_node.getNodeData().getEvent(), NodePanel.EVENTS );
+        }
+        addDate( top, phylogeny_node.getNodeData().getDate(), NodePanel.DATE );
+        addDistribution( top, phylogeny_node.getNodeData().getDistribution(), NodePanel.DISTRIBUTION );
+        addReference( top, phylogeny_node.getNodeData().getReference(), NodePanel.LIT_REFERENCE );
+        //  addProperties( top, phylogeny_node.getNodeData().getProperties(), "Properties" );
+    }
+
+    private void formatError( final DefaultMutableTreeNode mtn, final PhyloXmlDataFormatException e ) {
+        JOptionPane.showMessageDialog( this, e.getMessage(), "Format error", JOptionPane.ERROR_MESSAGE );
+        mtn.setUserObject( "" );
+        getJTree().repaint();
+    }
+
+    private JTree getJTree() {
+        return _tree;
+    }
+
+    private Map<DefaultMutableTreeNode, TagNumber> getMap() {
+        return _map;
+    }
+
+    private TagNumber getMapping( final DefaultMutableTreeNode mtn ) {
+        return getMap().get( mtn );
+    }
+
+    PhylogenyNode getMyNode() {
+        return _my_node;
+    }
+
+    private DefaultMutableTreeNode getSelectedTreeNode() {
+        final TreePath selectionPath = getJTree().getSelectionPath();
+        if ( selectionPath != null ) {
+            final Object[] path = selectionPath.getPath();
+            if ( path.length > 0 ) {
+                return ( DefaultMutableTreeNode ) path[ path.length - 1 ]; // Last node
+            }
+        }
+        return null;
+    }
+
+    private TreePanel getTreePanel() {
+        return _tree_panel;
+    }
+
+    private void keyEvent( final KeyEvent e ) {
+        if ( e.getKeyCode() == KeyEvent.VK_ENTER ) {
+            writeBack( getSelectedTreeNode() );
+        }
+    }
+
+    private List<Point> obtainPoints() {
+        ForesterUtil.ensurePresenceOfDistribution( getMyNode() );
+        Distribution d = getMyNode().getNodeData().getDistribution();
+        if ( d.getPoints() == null ) {
+            d = new Distribution( d.getDesc(), new ArrayList<Point>(), d.getPolygons() );
+            getMyNode().getNodeData().setDistribution( d );
+        }
+        final List<Point> ps = d.getPoints();
+        if ( ps.isEmpty() ) {
+            ps.add( new Point() );
+        }
+        else if ( ps.get( 0 ) == null ) {
+            ps.set( 0, new Point() );
+        }
+        return ps;
+    }
+
+    private BigDecimal parseBigDecimal( final DefaultMutableTreeNode mtn, final String value ) {
+        if ( ForesterUtil.isEmpty( value ) ) {
+            return new BigDecimal( 0 );
+        }
+        BigDecimal i = null;
+        try {
+            i = new BigDecimal( value );
+        }
+        catch ( final NumberFormatException e ) {
+            JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
+            mtn.setUserObject( "" );
+        }
+        return i;
+    }
+
+    private int parsePositiveInt( final DefaultMutableTreeNode mtn, final String value ) {
+        if ( ForesterUtil.isEmpty( value ) ) {
+            return 0;
+        }
+        int i = -1;
+        try {
+            i = ForesterUtil.parseInt( value );
+        }
+        catch ( final ParseException e ) {
+            JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
+            mtn.setUserObject( "" );
+        }
+        if ( i < 0 ) {
+            JOptionPane.showMessageDialog( this, "illegal value: " + value, "Error", JOptionPane.ERROR_MESSAGE );
+            mtn.setUserObject( "" );
+        }
+        return i;
+    }
+
+    void writeAll() {
+        for( int i = 0; i < getJTree().getRowCount(); i++ ) {
+            final TreePath p = getJTree().getPathForRow( i );
+            writeBack( ( DefaultMutableTreeNode ) p.getLastPathComponent() );
+        }
+    }
+
+    private void writeBack( final DefaultMutableTreeNode mtn ) {
+        if ( !getMap().containsKey( mtn ) ) {
+            final DefaultMutableTreeNode parent = ( DefaultMutableTreeNode ) mtn.getParent();
+            if ( getMap().containsKey( parent ) ) {
+                writeBack( mtn, getMapping( parent ) );
+            }
+        }
+    }
+
+    private void writeBack( final DefaultMutableTreeNode mtn, final TagNumber tag_number ) {
+        if ( tag_number == null ) {
+            return;
+        }
+        String value = mtn.toString();
+        if ( value == null ) {
+            value = "";
+        }
+        value = value.replaceAll( "\\s+", " " );
+        value = value.trim();
+        mtn.setUserObject( value );
+        getJTree().repaint();
+        final PHYLOXML_TAG tag = tag_number.getTag();
+        final int number = tag_number.getNumber();
+        switch ( tag ) {
+            case NODE_NAME:
+                getMyNode().setName( value );
+                break;
+            case NODE_BRANCH_LENGTH:
+                if ( ForesterUtil.isEmpty( value ) ) {
+                    getMyNode().setDistanceToParent( PhylogenyNode.DISTANCE_DEFAULT );
+                }
+                else {
+                    try {
+                        getMyNode().setDistanceToParent( ForesterUtil.parseDouble( value ) );
+                    }
+                    catch ( final ParseException e ) {
+                        JOptionPane.showMessageDialog( this,
+                                                       "failed to parse branch length from: " + value,
+                                                       "Error",
+                                                       JOptionPane.ERROR_MESSAGE );
+                        mtn.setUserObject( "" );
+                    }
+                }
+                break;
+            case CONFIDENCE_VALUE:
+                double confidence = Confidence.CONFIDENCE_DEFAULT_VALUE;
+                if ( !ForesterUtil.isEmpty( value ) ) {
+                    try {
+                        confidence = ForesterUtil.parseDouble( value );
+                    }
+                    catch ( final ParseException e ) {
+                        JOptionPane.showMessageDialog( this,
+                                                       "failed to parse confidence value from: " + value,
+                                                       "Error",
+                                                       JOptionPane.ERROR_MESSAGE );
+                        mtn.setUserObject( "" );
+                        break;
+                    }
+                }
+                if ( getMyNode().getBranchData().getConfidences().size() < number ) {
+                    throw new FailedConditionCheckException();
+                }
+                else if ( getMyNode().getBranchData().getConfidences().size() == number ) {
+                    if ( confidence >= 0 ) {
+                        getMyNode().getBranchData().getConfidences().add( new Confidence( confidence, "unknown" ) );
+                    }
+                }
+                else {
+                    final String type = getMyNode().getBranchData().getConfidences().get( number ).getType();
+                    getMyNode().getBranchData().getConfidences().set( number, new Confidence( confidence, type ) );
+                }
+                break;
+            case CONFIDENCE_TYPE:
+                if ( getMyNode().getBranchData().getConfidences().size() < number ) {
+                    throw new FailedConditionCheckException();
+                }
+                else if ( getMyNode().getBranchData().getConfidences().size() == number ) {
+                    if ( !ForesterUtil.isEmpty( value ) ) {
+                        getMyNode().getBranchData().getConfidences().add( new Confidence( 0, value ) );
+                    }
+                }
+                else {
+                    final double v = getMyNode().getBranchData().getConfidences().get( number ).getValue();
+                    getMyNode().getBranchData().getConfidences().set( number, new Confidence( v, value ) );
+                }
+                break;
+            case TAXONOMY_CODE:
+                ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
+                try {
+                    getMyNode().getNodeData().getTaxonomy().setTaxonomyCode( value );
+                }
+                catch ( final PhyloXmlDataFormatException e ) {
+                    formatError( mtn, e );
+                    break;
+                }
+                break;
+            case TAXONOMY_SCIENTIFIC_NAME:
+                ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
+                getMyNode().getNodeData().getTaxonomy().setScientificName( value );
+                break;
+            case TAXONOMY_COMMON_NAME:
+                ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
+                getMyNode().getNodeData().getTaxonomy().setCommonName( value );
+                break;
+            case TAXONOMY_RANK:
+                ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
+                try {
+                    getMyNode().getNodeData().getTaxonomy().setRank( value.toLowerCase() );
+                }
+                catch ( final PhyloXmlDataFormatException e ) {
+                    formatError( mtn, e );
+                    break;
+                }
+                break;
+            case TAXONOMY_AUTHORITY:
+                ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
+                getMyNode().getNodeData().getTaxonomy().setAuthority( value );
+                break;
+            case TAXONOMY_URI: {
+                Uri uri = null;
+                if ( !ForesterUtil.isEmpty( value ) ) {
+                    try {
+                        uri = new Uri( new URL( value ).toURI() );
+                    }
+                    catch ( final Exception e ) {
+                        JOptionPane.showMessageDialog( this,
+                                                       "failed to parse URL from: " + value,
+                                                       "Error",
+                                                       JOptionPane.ERROR_MESSAGE );
+                        mtn.setUserObject( "" );
+                    }
+                }
+                if ( uri != null ) {
+                    ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
+                }
+                addUri( mtn, uri, number, getMyNode().getNodeData().getTaxonomy() );
+                break;
+            }
+            case TAXONOMY_SYNONYM:
+                if ( getMyNode().getNodeData().getTaxonomy().getSynonyms().size() < number ) {
+                    throw new FailedConditionCheckException();
+                }
+                else if ( getMyNode().getNodeData().getTaxonomy().getSynonyms().size() == number ) {
+                    if ( !ForesterUtil.isEmpty( value ) ) {
+                        ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
+                        getMyNode().getNodeData().getTaxonomy().getSynonyms().add( value );
+                    }
+                }
+                else {
+                    getMyNode().getNodeData().getTaxonomy().getSynonyms().set( number, value );
+                }
+                break;
+            case TAXONOMY_ID_VALUE:
+                ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
+                if ( getMyNode().getNodeData().getTaxonomy().getIdentifier() == null ) {
+                    getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( value ) );
+                }
+                else {
+                    final String provider = getMyNode().getNodeData().getTaxonomy().getIdentifier().getProvider();
+                    getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( value, provider ) );
+                }
+                break;
+            case TAXONOMY_ID_PROVIDER:
+                ForesterUtil.ensurePresenceOfTaxonomy( getMyNode() );
+                if ( getMyNode().getNodeData().getTaxonomy().getIdentifier() == null ) {
+                    getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( "", value ) );
+                }
+                else {
+                    final String v = getMyNode().getNodeData().getTaxonomy().getIdentifier().getValue();
+                    getMyNode().getNodeData().getTaxonomy().setIdentifier( new Identifier( v, value ) );
+                }
+                break;
+            case SEQ_LOCATION:
+                ForesterUtil.ensurePresenceOfSequence( getMyNode() );
+                getMyNode().getNodeData().getSequence().setLocation( value );
+                break;
+            case SEQ_MOL_SEQ:
+                ForesterUtil.ensurePresenceOfSequence( getMyNode() );
+                getMyNode().getNodeData().getSequence().setMolecularSequence( value );
+                break;
+            case SEQ_NAME:
+                ForesterUtil.ensurePresenceOfSequence( getMyNode() );
+                getMyNode().getNodeData().getSequence().setName( value );
+                break;
+            case SEQ_SYMBOL:
+                ForesterUtil.ensurePresenceOfSequence( getMyNode() );
+                try {
+                    getMyNode().getNodeData().getSequence().setSymbol( value );
+                }
+                catch ( final PhyloXmlDataFormatException e ) {
+                    formatError( mtn, e );
+                    break;
+                }
+                break;
+            case SEQ_TYPE:
+                ForesterUtil.ensurePresenceOfSequence( getMyNode() );
+                try {
+                    getMyNode().getNodeData().getSequence().setType( value.toLowerCase() );
+                }
+                catch ( final PhyloXmlDataFormatException e ) {
+                    formatError( mtn, e );
+                    break;
+                }
+                break;
+            case SEQ_ACC_SOURCE:
+                ForesterUtil.ensurePresenceOfSequence( getMyNode() );
+                if ( getMyNode().getNodeData().getSequence().getAccession() == null ) {
+                    getMyNode().getNodeData().getSequence().setAccession( new Accession( "", value ) );
+                }
+                else {
+                    final String v = getMyNode().getNodeData().getSequence().getAccession().getValue();
+                    getMyNode().getNodeData().getSequence().setAccession( new Accession( v, value ) );
+                }
+                break;
+            case SEQ_ACC_VALUE:
+                ForesterUtil.ensurePresenceOfSequence( getMyNode() );
+                if ( getMyNode().getNodeData().getSequence().getAccession() == null ) {
+                    getMyNode().getNodeData().getSequence().setAccession( new Accession( value, "" ) );
+                }
+                else {
+                    final String source = getMyNode().getNodeData().getSequence().getAccession().getSource();
+                    getMyNode().getNodeData().getSequence().setAccession( new Accession( value, source ) );
+                }
+                break;
+            case SEQ_URI: {
+                Uri uri = null;
+                if ( !ForesterUtil.isEmpty( value ) ) {
+                    try {
+                        uri = new Uri( new URL( value ).toURI() );
+                    }
+                    catch ( final Exception e ) {
+                        JOptionPane.showMessageDialog( this,
+                                                       "failed to parse URL from: " + value,
+                                                       "Error",
+                                                       JOptionPane.ERROR_MESSAGE );
+                        mtn.setUserObject( "" );
+                    }
+                }
+                if ( uri != null ) {
+                    ForesterUtil.ensurePresenceOfSequence( getMyNode() );
+                }
+                addUri( mtn, uri, number, getMyNode().getNodeData().getSequence() );
+                break;
+            }
+            case LIT_REFERENCE_DESC:
+                if ( !getMyNode().getNodeData().isHasReference() ) {
+                    getMyNode().getNodeData().setReference( new Reference( "" ) );
+                }
+                getMyNode().getNodeData().getReference().setValue( value );
+                break;
+            case LIT_REFERENCE_DOI:
+                if ( !getMyNode().getNodeData().isHasReference() ) {
+                    getMyNode().getNodeData().setReference( new Reference( "" ) );
+                }
+                try {
+                    getMyNode().getNodeData().getReference().setDoi( value );
+                }
+                catch ( final PhyloXmlDataFormatException e ) {
+                    formatError( mtn, e );
+                    break;
+                }
+                break;
+            case EVENTS_DUPLICATIONS:
+                if ( !getMyNode().getNodeData().isHasEvent() ) {
+                    getMyNode().getNodeData().setEvent( new Event() );
+                }
+                getMyNode().getNodeData().getEvent().setDuplications( parsePositiveInt( mtn, value ) );
+                break;
+            case EVENTS_SPECIATIONS:
+                if ( !getMyNode().getNodeData().isHasEvent() ) {
+                    getMyNode().getNodeData().setEvent( new Event() );
+                }
+                getMyNode().getNodeData().getEvent().setSpeciations( parsePositiveInt( mtn, value ) );
+                break;
+            case EVENTS_GENE_LOSSES:
+                if ( !getMyNode().getNodeData().isHasEvent() ) {
+                    getMyNode().getNodeData().setEvent( new Event() );
+                }
+                getMyNode().getNodeData().getEvent().setGeneLosses( parsePositiveInt( mtn, value ) );
+                break;
+            case DATE_DESCRIPTION:
+                ForesterUtil.ensurePresenceOfDate( getMyNode() );
+                getMyNode().getNodeData().getDate().setDesc( value );
+                break;
+            case DATE_MAX:
+                ForesterUtil.ensurePresenceOfDate( getMyNode() );
+                getMyNode().getNodeData().getDate().setMax( parseBigDecimal( mtn, value ) );
+                break;
+            case DATE_MIN:
+                ForesterUtil.ensurePresenceOfDate( getMyNode() );
+                getMyNode().getNodeData().getDate().setMin( parseBigDecimal( mtn, value ) );
+                break;
+            case DATE_UNIT:
+                ForesterUtil.ensurePresenceOfDate( getMyNode() );
+                getMyNode().getNodeData().getDate().setUnit( value );
+                break;
+            case DATE_VALUE:
+                ForesterUtil.ensurePresenceOfDate( getMyNode() );
+                getMyNode().getNodeData().getDate().setValue( parseBigDecimal( mtn, value ) );
+                break;
+            case DIST_ALT: {
+                final BigDecimal new_value = parseBigDecimal( mtn, value );
+                if ( new_value != null ) {
+                    final List<Point> ps = obtainPoints();
+                    final Point p = ps.get( 0 );
+                    final Point p_new = new Point( p.getGeodeticDatum(),
+                                                   p.getLatitude(),
+                                                   p.getLongitude(),
+                                                   new_value,
+                                                   ForesterUtil.isEmpty( p.getAltiudeUnit() ) ? "?" : p
+                                                           .getAltiudeUnit() );
+                    ps.set( 0, p_new );
+                }
+                break;
+            }
+            case DIST_DESC: {
+                ForesterUtil.ensurePresenceOfDistribution( getMyNode() );
+                final Distribution d = getMyNode().getNodeData().getDistribution();
+                getMyNode().getNodeData().setDistribution( new Distribution( value, d.getPoints(), d.getPolygons() ) );
+                break;
+            }
+            case DIST_GEODETIC: {
+                if ( !ForesterUtil.isEmpty( value ) ) {
+                    final List<Point> ps = obtainPoints();
+                    final Point p = ps.get( 0 );
+                    final Point p_new = new Point( value, p.getLatitude(), p.getLongitude(), p.getAltitude(), p
+                            .getAltiudeUnit() );
+                    ps.set( 0, p_new );
+                }
+                break;
+            }
+            case DIST_ALT_UNIT: {
+                if ( !ForesterUtil.isEmpty( value ) ) {
+                    final List<Point> ps = obtainPoints();
+                    final Point p = ps.get( 0 );
+                    final Point p_new = new Point( p.getGeodeticDatum(), p.getLatitude(), p.getLongitude(), p
+                            .getAltitude(), value );
+                    ps.set( 0, p_new );
+                }
+                break;
+            }
+            case DIST_LAT: {
+                final BigDecimal new_value = parseBigDecimal( mtn, value );
+                if ( new_value != null ) {
+                    final List<Point> ps = obtainPoints();
+                    final Point p = ps.get( 0 );
+                    final Point p_new = new Point( p.getGeodeticDatum(),
+                                                   new_value,
+                                                   p.getLongitude(),
+                                                   p.getAltitude(),
+                                                   p.getAltiudeUnit() );
+                    ps.set( 0, p_new );
+                }
+                break;
+            }
+            case DIST_LONG: {
+                final BigDecimal new_value = parseBigDecimal( mtn, value );
+                if ( new_value != null ) {
+                    final List<Point> ps = obtainPoints();
+                    final Point p = ps.get( 0 );
+                    final Point p_new = new Point( p.getGeodeticDatum(), p.getLatitude(), new_value, p.getAltitude(), p
+                            .getAltiudeUnit() );
+                    ps.set( 0, p_new );
+                }
+                break;
+            }
+            default:
+                throw new IllegalArgumentException( "unknown: " + tag );
+        }
+        getJTree().repaint();
+        getTreePanel().setEdited( true );
+        getTreePanel().repaint();
+    }
+
+    private void addUri( final DefaultMutableTreeNode mtn, final Uri uri, final int number, final MultipleUris mu ) {
+        if ( uri != null ) {
+            if ( mu.getUris() == null ) {
+                mu.setUris( new ArrayList<Uri>() );
+            }
+        }
+        if ( ( uri != null ) && ( mu.getUris() == null ) ) {
+            mu.setUris( new ArrayList<Uri>() );
+        }
+        if ( ( uri != null ) && ( mu.getUris().size() == number ) ) {
+            mu.getUris().add( uri );
+        }
+        if ( ( mu.getUris() != null ) && ( mu.getUris().size() != number ) ) {
+            mu.getUris().set( number, uri );
+        }
+        final ImageLoader il = new ImageLoader( getTreePanel() );
+        new Thread( il ).start();
+    }
+
+    private enum PHYLOXML_TAG {
+        NODE_NAME,
+        NODE_BRANCH_LENGTH,
+        TAXONOMY_CODE,
+        TAXONOMY_SCIENTIFIC_NAME,
+        TAXONOMY_AUTHORITY,
+        TAXONOMY_COMMON_NAME,
+        TAXONOMY_SYNONYM,
+        TAXONOMY_RANK,
+        TAXONOMY_URI,
+        SEQ_SYMBOL,
+        SEQ_NAME,
+        SEQ_LOCATION,
+        SEQ_TYPE,
+        SEQ_MOL_SEQ,
+        SEQ_URI,
+        DATE_DESCRIPTION,
+        DATE_VALUE,
+        DATE_MIN,
+        DATE_MAX,
+        DATE_UNIT,
+        TAXONOMY_ID_VALUE,
+        TAXONOMY_ID_PROVIDER,
+        SEQ_ACC_VALUE,
+        SEQ_ACC_SOURCE,
+        CONFIDENCE_VALUE,
+        CONFIDENCE_TYPE,
+        LIT_REFERENCE_DESC,
+        LIT_REFERENCE_DOI,
+        EVENTS_DUPLICATIONS,
+        EVENTS_SPECIATIONS,
+        EVENTS_GENE_LOSSES,
+        DIST_DESC,
+        DIST_GEODETIC,
+        DIST_LAT,
+        DIST_LONG,
+        DIST_ALT,
+        DIST_ALT_UNIT
+    }
+
+    private class TagNumber {
+
+        final private PHYLOXML_TAG _tag;
+        final private int          _number;
+
+        TagNumber( final PHYLOXML_TAG tag, final int number ) {
+            _tag = tag;
+            _number = number;
+        }
+
+        int getNumber() {
+            return _number;
+        }
+
+        PHYLOXML_TAG getTag() {
+            return _tag;
+        }
+
+        @Override
+        public String toString() {
+            return getTag() + "_" + getNumber();
+        }
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/NodeFrame.java b/forester/java/src/org/forester/archaeopteryx/NodeFrame.java
new file mode 100644 (file)
index 0000000..64236f4
--- /dev/null
@@ -0,0 +1,103 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// Copyright (C) 2000-2001 Washington University School of Medicine
+// and Howard Hughes Medical Institute
+// Copyright (C) 2003-2007 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import org.forester.phylogeny.Phylogeny;
+import org.forester.phylogeny.PhylogenyNode;
+import org.forester.util.ForesterUtil;
+
+final class NodeFrame extends javax.swing.JFrame {
+
+    private static final long serialVersionUID = -6943510233968557246L;
+    private final TreePanel   _reepanel;
+    private int               _index           = -1;
+
+    NodeFrame( final PhylogenyNode n, final Phylogeny tree, final TreePanel tp, final int x ) {
+        super( "Node " + ( ForesterUtil.isEmpty( n.getName() ) ? n.getId() : n.getName() ) );
+        _reepanel = tp;
+        setSize( Constants.NODE_FRAME_SIZE );
+        _index = x;
+        final Container contentPane = getContentPane();
+        final NodePanel nodepanel = new NodePanel( n );
+        contentPane.add( nodepanel, BorderLayout.CENTER );
+        addWindowListener( new WindowAdapter() {
+
+            @Override
+            public void windowClosing( final WindowEvent e ) {
+                remove(); // to release slot in array
+                dispose();
+            }
+        } );
+        setResizable( false );
+        nodepanel.setVisible( true );
+        setVisible( true );
+    }
+
+    NodeFrame( final PhylogenyNode n, final Phylogeny tree, final TreePanel tp, final int x, final String dummy ) {
+        super( "Editable Node " + ( ForesterUtil.isEmpty( n.getName() ) ? n.getId() : n.getName() ) );
+        _reepanel = tp;
+        setSize( Constants.NODE_FRAME_SIZE );
+        _index = x;
+        final Container contentPane = getContentPane();
+        final NodeEditPanel nodepanel = new NodeEditPanel( n, tp );
+        contentPane.add( nodepanel, BorderLayout.CENTER );
+        addWindowListener( new WindowAdapter() {
+
+            @Override
+            public void windowClosing( final WindowEvent e ) {
+                try {
+                    nodepanel.writeAll();
+                }
+                catch ( final Exception ex ) {
+                    // Do nothing.
+                }
+                remove(); // to release slot in array
+                dispose();
+            }
+        } );
+        setResizable( false );
+        nodepanel.setVisible( true );
+        setVisible( true );
+    }
+
+    TreePanel getTreePanel() {
+        return _reepanel;
+    }
+
+    void remove() {
+        if ( _index > -1 ) {
+            _reepanel.removeEditNodeFrame( _index ); // to release slot in array
+        }
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/NodePanel.java b/forester/java/src/org/forester/archaeopteryx/NodePanel.java
new file mode 100644 (file)
index 0000000..ff6e275
--- /dev/null
@@ -0,0 +1,415 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/
+
+package org.forester.archaeopteryx;
+
+import java.util.List;
+import java.util.SortedMap;
+import java.util.SortedSet;
+
+import javax.swing.JEditorPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTree;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.text.Position;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+
+import org.forester.phylogeny.PhylogenyMethods;
+import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.Annotation;
+import org.forester.phylogeny.data.BinaryCharacters;
+import org.forester.phylogeny.data.Date;
+import org.forester.phylogeny.data.Distribution;
+import org.forester.phylogeny.data.Event;
+import org.forester.phylogeny.data.PhylogenyData;
+import org.forester.phylogeny.data.Point;
+import org.forester.phylogeny.data.PropertiesMap;
+import org.forester.phylogeny.data.Property;
+import org.forester.phylogeny.data.Reference;
+import org.forester.phylogeny.data.Sequence;
+import org.forester.phylogeny.data.Taxonomy;
+import org.forester.phylogeny.data.Uri;
+import org.forester.util.ForesterUtil;
+
+class NodePanel extends JPanel implements TreeSelectionListener {
+
+    static final String       DIST_ALTITUDE            = "Altitude";
+    static final String       DIST_ALT_UNIT            = "Altitude unit";
+    static final String       DIST_LONGITUDE           = "Longitude";
+    static final String       DIST_LATITUDE            = "Latitude";
+    static final String       DIST_GEODETIC_DATUM      = "Geodetic datum";
+    static final String       DIST_DESCRIPTION         = "Description";
+    static final String       DATE_UNIT                = "Unit";
+    static final String       DATE_MAX                 = "Max";
+    static final String       DATE_MIN                 = "Min";
+    static final String       DATE_VALUE               = "Value";
+    static final String       DATE_DESCRIPTION         = "Description";
+    static final String       TAXONOMY_IDENTIFIER      = "Identifier";
+    static final String       SEQ_ACCESSION            = "Accession";
+    static final String       CONFIDENCE               = "Confidence";
+    static final String       PROP                     = "Properties";
+    static final String       BINARY_CHARACTERS        = "Binary characters";
+    static final String       REFERENCE                = "Reference";
+    static final String       LIT_REFERENCE            = "Reference";
+    static final String       LIT_REFERENCE_DESC       = "Description";
+    static final String       LIT_REFERENCE_DOI        = "DOI";
+    static final String       DISTRIBUTION             = "Distribution";
+    static final String       DATE                     = "Date";
+    static final String       EVENTS                   = "Events";
+    static final String       SEQUENCE                 = "Sequence";
+    static final String       TAXONOMY                 = "Taxonomy";
+    static final String       BASIC                    = "Basic";
+    static final String       TAXONOMY_SCIENTIFIC_NAME = "Scientific name";
+    static final String       SEQ_MOL_SEQ              = "Mol seq";
+    static final String       SEQ_TYPE                 = "Type";
+    static final String       SEQ_LOCATION             = "Location";
+    static final String       SEQ_SYMBOL               = "Symbol";
+    static final String       SEQ_URI                  = "URI";
+    static final String       NODE_BRANCH_LENGTH       = "Branch length";
+    static final String       NODE_NAME                = "Name";
+    static final String       TAXONOMY_URI             = "URI";
+    static final String       TAXONOMY_RANK            = "Rank";
+    static final String       TAXONOMY_SYNONYM         = "Synonym";
+    static final String       TAXONOMY_COMMON_NAME     = "Common name";
+    static final String       TAXONOMY_AUTHORITY       = "Authority";
+    static final String       TAXONOMY_CODE            = "Code";
+    static final String       SEQ_NAME                 = "Name";
+    static final String       EVENTS_GENE_LOSSES       = "Gene losses";
+    static final String       EVENTS_SPECIATIONS       = "Speciations";
+    static final String       EVENTS_DUPLICATIONS      = "Duplications";
+    private static final long serialVersionUID         = 5120159904388100771L;
+    static final String       CONFIDENCE_TYPE          = "type";
+    private final JTree       _tree;
+    private final JEditorPane _pane;
+
+    public NodePanel( final PhylogenyNode phylogeny_node ) {
+        String node_name = "";
+        if ( !ForesterUtil.isEmpty( phylogeny_node.getName() ) ) {
+            node_name = phylogeny_node.getName() + " ";
+        }
+        final DefaultMutableTreeNode top = new DefaultMutableTreeNode( "Node " + node_name );
+        createNodes( top, phylogeny_node );
+        _tree = new JTree( top );
+        _tree.setEditable( false );
+        getJTree().setToggleClickCount( 1 );
+        expandPath( BASIC );
+        expandPath( TAXONOMY );
+        expandPath( SEQUENCE );
+        expandPath( EVENTS );
+        final JScrollPane tree_view = new JScrollPane( getJTree() );
+        _pane = new JEditorPane();
+        _pane.setEditable( false );
+        final JScrollPane data_view = new JScrollPane( _pane );
+        final JSplitPane split_pane = new JSplitPane( JSplitPane.VERTICAL_SPLIT );
+        split_pane.setTopComponent( tree_view );
+        split_pane.setBottomComponent( data_view );
+        data_view.setMinimumSize( Constants.NODE_PANEL_SPLIT_MINIMUM_SIZE );
+        tree_view.setMinimumSize( Constants.NODE_PANEL_SPLIT_MINIMUM_SIZE );
+        split_pane.setDividerLocation( 400 );
+        split_pane.setPreferredSize( Constants.NODE_PANEL_SIZE );
+        add( split_pane );
+    }
+
+    private void expandPath( final String name ) {
+        final TreePath tp = getJTree().getNextMatch( name, 0, Position.Bias.Forward );
+        if ( tp != null ) {
+            getJTree().expandPath( tp );
+        }
+    }
+
+    private JTree getJTree() {
+        return _tree;
+    }
+
+    @Override
+    public void valueChanged( final TreeSelectionEvent e ) {
+        // Do nothing.
+    }
+
+    private static void addAnnotation( final DefaultMutableTreeNode top, final Annotation ann, final String name ) {
+        DefaultMutableTreeNode category;
+        category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        addSubelement( category, REFERENCE, ann.getRef() );
+        addSubelement( category, "Description", ann.getDesc() );
+        addSubelement( category, "Source", ann.getSource() );
+        addSubelement( category, "Type", ann.getType() );
+        addSubelement( category, "Evidence", ann.getEvidence() );
+        if ( ann.getConfidence() != null ) {
+            addSubelement( category, CONFIDENCE, ann.getConfidence().asText().toString() );
+        }
+        if ( ann.getProperties() != null ) {
+            addProperties( category, ann.getProperties(), PROP );
+        }
+    }
+
+    private static void addUri( final DefaultMutableTreeNode top, final Uri uri, final String name ) {
+        DefaultMutableTreeNode category;
+        category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        addSubelement( category, "Description", uri.getDescription() );
+        addSubelement( category, "Type", uri.getType() );
+        addSubelement( category, "URI", uri.getValue().toString() );
+    }
+
+    private static void addAnnotations( final DefaultMutableTreeNode top,
+                                        final SortedSet<Annotation> annotations,
+                                        final DefaultMutableTreeNode category ) {
+        if ( ( annotations != null ) && ( annotations.size() > 0 ) ) {
+            category.add( new DefaultMutableTreeNode( "Annotations" ) );
+            final DefaultMutableTreeNode last = top.getLastLeaf();
+            int i = 0;
+            for( final PhylogenyData ann : annotations ) {
+                addAnnotation( last, ( Annotation ) ann, "Annotation " + ( i++ ) );
+            }
+        }
+    }
+
+    private static void addUris( final DefaultMutableTreeNode top,
+                                 final List<Uri> uris,
+                                 final DefaultMutableTreeNode category ) {
+        if ( ( uris != null ) && ( uris.size() > 0 ) ) {
+            category.add( new DefaultMutableTreeNode( "URIs" ) );
+            final DefaultMutableTreeNode last = top.getLastLeaf();
+            int i = 0;
+            for( final Uri uri : uris ) {
+                if ( uri != null ) {
+                    addUri( last, uri, "URI " + ( i++ ) );
+                }
+            }
+        }
+    }
+
+    private static void addBasics( final DefaultMutableTreeNode top,
+                                   final PhylogenyNode phylogeny_node,
+                                   final String name ) {
+        final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        addSubelement( category, NODE_NAME, phylogeny_node.getName() );
+        if ( phylogeny_node.getDistanceToParent() != PhylogenyNode.DISTANCE_DEFAULT ) {
+            addSubelement( category, NODE_BRANCH_LENGTH, ForesterUtil.FORMATTER_6.format( phylogeny_node
+                    .getDistanceToParent() ) );
+        }
+        if ( phylogeny_node.getBranchData().isHasConfidences() ) {
+            for( final PhylogenyData conf : phylogeny_node.getBranchData().getConfidences() ) {
+                addSubelement( category, CONFIDENCE, conf.asText().toString() );
+            }
+        }
+        if ( !phylogeny_node.isExternal() ) {
+            addSubelement( category, "Children", String.valueOf( phylogeny_node.getNumberOfDescendants() ) );
+            addSubelement( category, "External children", String.valueOf( phylogeny_node.getAllExternalDescendants()
+                    .size() ) );
+            final SortedMap<Taxonomy, Integer> distinct_tax = PhylogenyMethods
+                    .obtainDistinctTaxonomyCounts( phylogeny_node );
+            if ( distinct_tax != null ) {
+                final int no_tax = PhylogenyMethods.calculateNumberOfExternalNodesWithoutTaxonomy( phylogeny_node );
+                final int tax_count = distinct_tax.size();
+                addSubelement( category, "Distinct external taxonomies", String.valueOf( tax_count ) );
+                if ( no_tax > 0 ) {
+                    addSubelement( category, "External nodes without taxonomy", String.valueOf( no_tax ) );
+                }
+                //TODO remove me...
+                for( final Taxonomy taxonomy : distinct_tax.keySet() ) {
+                    System.out.println( taxonomy + ": " + distinct_tax.get( taxonomy ) );
+                }
+            }
+        }
+        if ( !phylogeny_node.isRoot() ) {
+            addSubelement( category, "Depth", String.valueOf( PhylogenyMethods.calculateDepth( phylogeny_node ) ) );
+            final double d = PhylogenyMethods.calculateDistanceToRoot( phylogeny_node );
+            if ( d > 0 ) {
+                addSubelement( category, "Distance to root", String.valueOf( ForesterUtil.FORMATTER_6.format( d ) ) );
+            }
+        }
+    }
+
+    private static void addBinaryCharacters( final DefaultMutableTreeNode top,
+                                             final BinaryCharacters bc,
+                                             final String name ) {
+        DefaultMutableTreeNode category;
+        category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        addSubelement( category, "Gained", String.valueOf( bc.getGainedCount() ) );
+        addSubelement( category, "Lost", String.valueOf( bc.getLostCount() ) );
+        addSubelement( category, "Present", String.valueOf( bc.getPresentCount() ) );
+        final DefaultMutableTreeNode chars = new DefaultMutableTreeNode( "Lists" );
+        category.add( chars );
+        addSubelement( chars, "Gained", bc.getGainedCharactersAsStringBuffer().toString() );
+        addSubelement( chars, "Lost", bc.getLostCharactersAsStringBuffer().toString() );
+        addSubelement( chars, "Present", bc.getPresentCharactersAsStringBuffer().toString() );
+    }
+
+    private static void addDate( final DefaultMutableTreeNode top, final Date date, final String name ) {
+        DefaultMutableTreeNode category;
+        category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        addSubelement( category, DATE_DESCRIPTION, date.getDesc() );
+        addSubelement( category, DATE_VALUE, String.valueOf( date.getValue() ) );
+        addSubelement( category, DATE_MIN, String.valueOf( date.getMin() ) );
+        addSubelement( category, DATE_MAX, String.valueOf( date.getMax() ) );
+        addSubelement( category, DATE_UNIT, date.getUnit() );
+    }
+
+    private static void addDistribution( final DefaultMutableTreeNode top, final Distribution dist, final String name ) {
+        DefaultMutableTreeNode category;
+        category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        addSubelement( category, DIST_DESCRIPTION, dist.getDesc() );
+        if ( ( dist.getPoints() != null ) && ( dist.getPoints().size() > 0 ) ) {
+            final Point p0 = dist.getPoints().get( 0 );
+            if ( p0 != null ) {
+                addSubelement( category, DIST_GEODETIC_DATUM, p0.getGeodeticDatum() );
+                addSubelement( category, DIST_LATITUDE, String.valueOf( p0.getLatitude() ) );
+                addSubelement( category, DIST_LONGITUDE, String.valueOf( p0.getLongitude() ) );
+                String alt_unit = p0.getAltiudeUnit();
+                if ( ForesterUtil.isEmpty( alt_unit ) ) {
+                    alt_unit = "?";
+                }
+                addSubelement( category, DIST_ALTITUDE, String.valueOf( p0.getAltitude() ) + alt_unit );
+            }
+        }
+    }
+
+    private static void addEvents( final DefaultMutableTreeNode top, final Event events, final String name ) {
+        DefaultMutableTreeNode category;
+        category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        if ( events.getNumberOfDuplications() > 0 ) {
+            addSubelement( category, EVENTS_DUPLICATIONS, String.valueOf( events.getNumberOfDuplications() ) );
+        }
+        if ( events.getNumberOfSpeciations() > 0 ) {
+            addSubelement( category, EVENTS_SPECIATIONS, String.valueOf( events.getNumberOfSpeciations() ) );
+        }
+        if ( events.getNumberOfGeneLosses() > 0 ) {
+            addSubelement( category, EVENTS_GENE_LOSSES, String.valueOf( events.getNumberOfGeneLosses() ) );
+        }
+        addSubelement( category, "Type", events.getEventType().toString() );
+        if ( events.getConfidence() != null ) {
+            addSubelement( category, CONFIDENCE, events.getConfidence().asText().toString() );
+        }
+    }
+
+    private static void addProperties( final DefaultMutableTreeNode top,
+                                       final PropertiesMap properties,
+                                       final String string ) {
+        final SortedMap<String, Property> properties_map = properties.getProperties();
+        final DefaultMutableTreeNode category = new DefaultMutableTreeNode( "Properties " );
+        top.add( category );
+        for( final String key : properties_map.keySet() ) {
+            final Property prop = properties_map.get( key );
+            category.add( new DefaultMutableTreeNode( prop.getRef() + " " + prop.getValue() + " " + prop.getUnit()
+                    + " [" + prop.getAppliesTo().toString() + "]" ) );
+        }
+    }
+
+    private static void addReference( final DefaultMutableTreeNode top, final Reference ref, final String name ) {
+        final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        addSubelement( category, LIT_REFERENCE_DOI, ref.getDoi() );
+        addSubelement( category, LIT_REFERENCE_DESC, ref.getDescription() );
+    }
+
+    private static void addSequence( final DefaultMutableTreeNode top, final Sequence seq, final String name ) {
+        final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        addSubelement( category, SEQ_NAME, seq.getName() );
+        addSubelement( category, SEQ_SYMBOL, seq.getSymbol() );
+        if ( seq.getAccession() != null ) {
+            addSubelement( category, SEQ_ACCESSION, seq.getAccession().asText().toString() );
+        }
+        addSubelement( category, SEQ_LOCATION, seq.getLocation() );
+        addSubelement( category, SEQ_TYPE, seq.getType() );
+        addSubelement( category, SEQ_MOL_SEQ, seq.getMolecularSequence() );
+        if ( ( seq.getUris() != null ) && !seq.getUris().isEmpty() ) {
+            addUris( top, seq.getUris(), category );
+        }
+        addAnnotations( top, seq.getAnnotations(), category );
+    }
+
+    private static void addSubelement( final DefaultMutableTreeNode node, final String name, final String value ) {
+        if ( !ForesterUtil.isEmpty( value ) ) {
+            node.add( new DefaultMutableTreeNode( name + ": " + value ) );
+        }
+    }
+
+    private static void addTaxonomy( final DefaultMutableTreeNode top, final Taxonomy tax, final String name ) {
+        final DefaultMutableTreeNode category = new DefaultMutableTreeNode( name );
+        top.add( category );
+        if ( tax.getIdentifier() != null ) {
+            addSubelement( category, TAXONOMY_IDENTIFIER, tax.getIdentifier().asText().toString() );
+        }
+        addSubelement( category, TAXONOMY_CODE, tax.getTaxonomyCode() );
+        addSubelement( category, TAXONOMY_SCIENTIFIC_NAME, tax.getScientificName() );
+        addSubelement( category, TAXONOMY_AUTHORITY, tax.getAuthority() );
+        addSubelement( category, TAXONOMY_COMMON_NAME, tax.getCommonName() );
+        for( final String syn : tax.getSynonyms() ) {
+            addSubelement( category, TAXONOMY_SYNONYM, syn );
+        }
+        addSubelement( category, TAXONOMY_RANK, tax.getRank() );
+        if ( ( tax.getUris() != null ) && !tax.getUris().isEmpty() ) {
+            addUris( top, tax.getUris(), category );
+        }
+    }
+
+    private static void createNodes( final DefaultMutableTreeNode top, final PhylogenyNode phylogeny_node ) {
+        addBasics( top, phylogeny_node, BASIC );
+        // Taxonomy
+        if ( phylogeny_node.getNodeData().isHasTaxonomy() ) {
+            addTaxonomy( top, phylogeny_node.getNodeData().getTaxonomy(), TAXONOMY );
+        }
+        // Sequence
+        if ( phylogeny_node.getNodeData().isHasSequence() ) {
+            addSequence( top, phylogeny_node.getNodeData().getSequence(), SEQUENCE );
+        }
+        // Events
+        if ( phylogeny_node.getNodeData().isHasEvent() ) {
+            addEvents( top, phylogeny_node.getNodeData().getEvent(), EVENTS );
+        }
+        // Date
+        if ( phylogeny_node.getNodeData().isHasDate() ) {
+            addDate( top, phylogeny_node.getNodeData().getDate(), DATE );
+        }
+        // Distribution
+        if ( phylogeny_node.getNodeData().isHasDistribution() ) {
+            addDistribution( top, phylogeny_node.getNodeData().getDistribution(), DISTRIBUTION );
+        }
+        // Reference
+        if ( phylogeny_node.getNodeData().isHasReference() ) {
+            addReference( top, phylogeny_node.getNodeData().getReference(), LIT_REFERENCE );
+        }
+        // BinaryCharacters
+        if ( phylogeny_node.getNodeData().isHasBinaryCharacters() ) {
+            addBinaryCharacters( top, phylogeny_node.getNodeData().getBinaryCharacters(), BINARY_CHARACTERS );
+        }
+        // Properties
+        if ( phylogeny_node.getNodeData().isHasProperties() ) {
+            addProperties( top, phylogeny_node.getNodeData().getProperties(), PROP );
+        }
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/Options.java b/forester/java/src/org/forester/archaeopteryx/Options.java
new file mode 100644 (file)
index 0000000..d0c6c92
--- /dev/null
@@ -0,0 +1,481 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2009 Christian M. Zmasek
+// Copyright (C) 2009 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.Font;
+
+import org.forester.util.ForesterUtil;
+
+/*
+ * This is to hold changeable options.
+ */
+final public class Options {
+
+    static final double             MIN_CONFIDENCE_DEFAULT = 0.0;
+    private boolean                 _show_node_boxes;
+    private boolean                 _show_branch_length_values;
+    private boolean                 _internal_number_are_confidence_for_nh_parsing;
+    private boolean                 _show_scale;
+    private boolean                 _show_overview;
+    private boolean                 _antialias_screen;
+    private boolean                 _antialias_print;
+    private boolean                 _graphics_export_visible_only;
+    private int                     _print_size_x;
+    private int                     _print_size_y;
+    private double                  _min_confidence_value;
+    private boolean                 _print_black_and_white;
+    private boolean                 _print_using_actual_size;
+    private boolean                 _graphics_export_using_actual_size;
+    private PHYLOGENY_GRAPHICS_TYPE _phylogeny_graphics_type;
+    private CLADOGRAM_TYPE          _cladogram_type;
+    private OVERVIEW_PLACEMENT_TYPE _ov_placement;
+    private NODE_LABEL_DIRECTION    _node_label_direction;
+    private Font                    _base_font;
+    private boolean                 _match_whole_terms_only;
+    private boolean                 _search_case_sensitive;
+    private float                   _print_line_width;
+    private boolean                 _inverse_search_result;
+    private double                  _scale_bar_length;
+    private short                   _number_of_digits_after_comma_for_confidence_values;
+    private short                   _number_of_digits_after_comma_for_branch_length_values;
+    private boolean                 _nh_parsing_replace_underscores;
+    private boolean                 _nh_parsing_extract_pfam_taxonomy_codes;
+    private boolean                 _editable;
+    private boolean                 _background_color_gradient;
+    private boolean                 _show_domain_labels;
+    private boolean                 _color_labels_same_as_parent_branch;
+    private boolean                 _abbreviate_scientific_names;
+
+    private Options() {
+        init();
+    }
+
+    final Font getBaseFont() {
+        return _base_font;
+    }
+
+    final CLADOGRAM_TYPE getCladogramType() {
+        return _cladogram_type;
+    }
+
+    final double getMinConfidenceValue() {
+        return _min_confidence_value;
+    }
+
+    final NODE_LABEL_DIRECTION getNodeLabelDirection() {
+        return _node_label_direction;
+    }
+
+    final short getNumberOfDigitsAfterCommaForBranchLengthValues() {
+        return _number_of_digits_after_comma_for_branch_length_values;
+    }
+
+    final short getNumberOfDigitsAfterCommaForConfidenceValues() {
+        return _number_of_digits_after_comma_for_confidence_values;
+    }
+
+    final OVERVIEW_PLACEMENT_TYPE getOvPlacement() {
+        return _ov_placement;
+    }
+
+    final PHYLOGENY_GRAPHICS_TYPE getPhylogenyGraphicsType() {
+        return _phylogeny_graphics_type;
+    }
+
+    final float getPrintLineWidth() {
+        return _print_line_width;
+    }
+
+    final int getPrintSizeX() {
+        return _print_size_x;
+    }
+
+    final int getPrintSizeY() {
+        return _print_size_y;
+    }
+
+    final double getScaleBarLength() {
+        return _scale_bar_length;
+    }
+
+    final private void init() {
+        _show_node_boxes = false;
+        _show_branch_length_values = false;
+        _internal_number_are_confidence_for_nh_parsing = false;
+        _show_scale = false;
+        _antialias_screen = true;
+        _antialias_print = true;
+        _graphics_export_visible_only = false;
+        _editable = true;
+        _background_color_gradient = false;
+        if ( Util.isUsOrCanada() ) {
+            _print_size_x = Constants.US_LETTER_SIZE_X;
+            _print_size_y = Constants.US_LETTER_SIZE_Y;
+        }
+        else {
+            _print_size_x = Constants.A4_SIZE_X;
+            _print_size_y = Constants.A4_SIZE_Y;
+        }
+        _min_confidence_value = MIN_CONFIDENCE_DEFAULT;
+        _print_black_and_white = false;
+        _print_using_actual_size = false;
+        _graphics_export_using_actual_size = true;
+        _phylogeny_graphics_type = PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR;
+        _base_font = new Font( Configuration.getDefaultFontFamilyName(), Font.PLAIN, 10 );
+        _match_whole_terms_only = false;
+        _search_case_sensitive = false;
+        _print_line_width = Constants.PDF_LINE_WIDTH_DEFAULT;
+        _show_overview = true;
+        _ov_placement = OVERVIEW_PLACEMENT_TYPE.UPPER_LEFT;
+        _node_label_direction = NODE_LABEL_DIRECTION.HORIZONTAL;
+        _inverse_search_result = false;
+        _scale_bar_length = 0.0;
+        _number_of_digits_after_comma_for_branch_length_values = Constants.NUMBER_OF_DIGITS_AFTER_COMMA_FOR_BRANCH_LENGTH_VALUES_DEFAULT;
+        _number_of_digits_after_comma_for_confidence_values = Constants.NUMBER_OF_DIGITS_AFTER_COMMA_FOR_CONFIDENCE_VALUES_DEFAULT;
+        _nh_parsing_replace_underscores = false;
+        _nh_parsing_extract_pfam_taxonomy_codes = false;
+        _cladogram_type = Constants.CLADOGRAM_TYPE_DEFAULT;
+        _show_domain_labels = true;
+        setAbbreviateScientificTaxonNames( false );
+        _color_labels_same_as_parent_branch = false;
+    }
+
+    final boolean isAntialiasPrint() {
+        return _antialias_print;
+    }
+
+    final boolean isAntialiasScreen() {
+        return _antialias_screen;
+    }
+
+    final boolean isBackgroundColorGradient() {
+        return _background_color_gradient;
+    }
+
+    public final boolean isShowDomainLabels() {
+        return _show_domain_labels;
+    }
+
+    final boolean isColorLabelsSameAsParentBranch() {
+        return _color_labels_same_as_parent_branch;
+    }
+
+    final boolean isEditable() {
+        return _editable;
+    }
+
+    final boolean isExtractPfamTaxonomyCodesInNhParsing() {
+        return _nh_parsing_extract_pfam_taxonomy_codes;
+    }
+
+    final boolean isGraphicsExportUsingActualSize() {
+        return _graphics_export_using_actual_size;
+    }
+
+    final boolean isGraphicsExportVisibleOnly() {
+        return _graphics_export_visible_only;
+    }
+
+    final boolean isInternalNumberAreConfidenceForNhParsing() {
+        return _internal_number_are_confidence_for_nh_parsing;
+    }
+
+    final boolean isInverseSearchResult() {
+        return _inverse_search_result;
+    }
+
+    final boolean isMatchWholeTermsOnly() {
+        return _match_whole_terms_only;
+    }
+
+    final boolean isPrintBlackAndWhite() {
+        return _print_black_and_white;
+    }
+
+    final boolean isPrintUsingActualSize() {
+        return _print_using_actual_size;
+    }
+
+    final boolean isReplaceUnderscoresInNhParsing() {
+        return _nh_parsing_replace_underscores;
+    }
+
+    final boolean isSearchCaseSensitive() {
+        return _search_case_sensitive;
+    }
+
+    final boolean isShowBranchLengthValues() {
+        return _show_branch_length_values;
+    }
+
+    final boolean isShowNodeBoxes() {
+        return _show_node_boxes;
+    }
+
+    final boolean isShowOverview() {
+        return _show_overview;
+    }
+
+    final boolean isShowScale() {
+        return _show_scale;
+    }
+
+    final void setAntialiasPrint( final boolean antialias_print ) {
+        _antialias_print = antialias_print;
+    }
+
+    final void setAntialiasScreen( final boolean antialias_screen ) {
+        _antialias_screen = antialias_screen;
+    }
+
+    public void setBackgroundColorGradient( final boolean background_color_gradient ) {
+        _background_color_gradient = background_color_gradient;
+    }
+
+    public void setShowDomainLabels( final boolean show_domain_labels ) {
+        _show_domain_labels = show_domain_labels;
+    }
+
+    public void setColorLabelsSameAsParentBranch( final boolean color_labels_same_as_parent_branch ) {
+        _color_labels_same_as_parent_branch = color_labels_same_as_parent_branch;
+    }
+
+    final void setBaseFont( final Font base_font ) {
+        _base_font = base_font;
+    }
+
+    final void setCladogramType( final CLADOGRAM_TYPE cladogram_type ) {
+        _cladogram_type = cladogram_type;
+    }
+
+    final void setEditable( final boolean editable ) {
+        _editable = editable;
+    }
+
+    final void setExtractPfamTaxonomyCodesInNhParsing( final boolean nh_parsing_extract_pfam_taxonomy_codes ) {
+        _nh_parsing_extract_pfam_taxonomy_codes = nh_parsing_extract_pfam_taxonomy_codes;
+    }
+
+    final void setGraphicsExportUsingActualSize( final boolean graphics_export_using_actual_size ) {
+        _graphics_export_using_actual_size = graphics_export_using_actual_size;
+        if ( !graphics_export_using_actual_size ) {
+            setGraphicsExportVisibleOnly( false );
+        }
+    }
+
+    final void setGraphicsExportVisibleOnly( final boolean graphics_export_visible_only ) {
+        _graphics_export_visible_only = graphics_export_visible_only;
+        if ( graphics_export_visible_only ) {
+            setGraphicsExportUsingActualSize( true );
+        }
+    }
+
+    final void setInternalNumberAreConfidenceForNhParsing( final boolean internal_number_are_confidence_for_nh_parsing ) {
+        _internal_number_are_confidence_for_nh_parsing = internal_number_are_confidence_for_nh_parsing;
+    }
+
+    final void setInverseSearchResult( final boolean inverse_search_result ) {
+        _inverse_search_result = inverse_search_result;
+    }
+
+    final void setMatchWholeTermsOnly( final boolean search_whole_words_only ) {
+        _match_whole_terms_only = search_whole_words_only;
+    }
+
+    final void setMinConfidenceValue( final double min_confidence_value ) {
+        _min_confidence_value = min_confidence_value;
+    }
+
+    final void setNodeLabelDirection( final NODE_LABEL_DIRECTION node_label_direction ) {
+        _node_label_direction = node_label_direction;
+    }
+
+    final private void setNumberOfDigitsAfterCommaForBranchLength( final short number_of_digits_after_comma_for_branch_length_values ) {
+        _number_of_digits_after_comma_for_branch_length_values = number_of_digits_after_comma_for_branch_length_values;
+    }
+
+    final private void setNumberOfDigitsAfterCommaForConfidenceValues( final short number_of_digits_after_comma_for_confidence_values ) {
+        _number_of_digits_after_comma_for_confidence_values = number_of_digits_after_comma_for_confidence_values;
+    }
+
+    final void setOvPlacement( final OVERVIEW_PLACEMENT_TYPE ov_placement ) {
+        _ov_placement = ov_placement;
+    }
+
+    final void setPhylogenyGraphicsType( final PHYLOGENY_GRAPHICS_TYPE phylogeny_graphics_type ) {
+        _phylogeny_graphics_type = phylogeny_graphics_type;
+    }
+
+    final void setPrintBlackAndWhite( final boolean print_black_and_white ) {
+        _print_black_and_white = print_black_and_white;
+    }
+
+    final void setPrintLineWidth( final float print_line_width ) {
+        _print_line_width = print_line_width;
+    }
+
+    final void setPrintSizeX( final int print_size_x ) {
+        _print_size_x = print_size_x;
+    }
+
+    final void setPrintSizeY( final int print_size_y ) {
+        _print_size_y = print_size_y;
+    }
+
+    final void setPrintUsingActualSize( final boolean print_using_actual_size ) {
+        _print_using_actual_size = print_using_actual_size;
+    }
+
+    final void setReplaceUnderscoresInNhParsing( final boolean nh_parsing_replace_underscores ) {
+        _nh_parsing_replace_underscores = nh_parsing_replace_underscores;
+    }
+
+    final void setScaleBarLength( final double scale_bar_length ) {
+        _scale_bar_length = scale_bar_length;
+    }
+
+    final void setSearchCaseSensitive( final boolean search_case_sensitive ) {
+        _search_case_sensitive = search_case_sensitive;
+    }
+
+    final void setShowBranchLengthValues( final boolean show_branch_length_values ) {
+        _show_branch_length_values = show_branch_length_values;
+    }
+
+    final void setShowNodeBoxes( final boolean show_node_boxes ) {
+        _show_node_boxes = show_node_boxes;
+    }
+
+    final void setShowOverview( final boolean show_overview ) {
+        _show_overview = show_overview;
+    }
+
+    final void setShowScale( final boolean show_scale ) {
+        _show_scale = show_scale;
+    }
+
+    final static Options createDefaultInstance() {
+        return new Options();
+    }
+
+    final static Options createInstance( final Configuration configuration ) {
+        final Options instance = createDefaultInstance();
+        if ( configuration != null ) {
+            instance.setAntialiasScreen( configuration.isAntialiasScreen() );
+            instance.setShowScale( configuration.isShowScale() );
+            instance.setShowBranchLengthValues( configuration.isShowBranchLengthValues() );
+            instance.setShowOverview( configuration.isShowOverview() );
+            instance.setCladogramType( configuration.getCladogramType() );
+            instance.setOvPlacement( configuration.getOvPlacement() );
+            instance.setPrintLineWidth( configuration.getPrintLineWidth() );
+            instance.setNodeLabelDirection( configuration.getNodeLabelDirection() );
+            instance.setBackgroundColorGradient( configuration.isBackgroundColorGradient() );
+            if ( configuration.getNumberOfDigitsAfterCommaForBranchLengthValues() >= 0 ) {
+                instance.setNumberOfDigitsAfterCommaForBranchLength( configuration
+                        .getNumberOfDigitsAfterCommaForBranchLengthValues() );
+            }
+            if ( configuration.getNumberOfDigitsAfterCommaForConfidenceValues() >= 0 ) {
+                instance.setNumberOfDigitsAfterCommaForConfidenceValues( configuration
+                        .getNumberOfDigitsAfterCommaForConfidenceValues() );
+            }
+            instance.setExtractPfamTaxonomyCodesInNhParsing( configuration.isExtractPfamTaxonomyCodesInNhParsing() );
+            instance.setReplaceUnderscoresInNhParsing( configuration.isReplaceUnderscoresInNhParsing() );
+            instance.setInternalNumberAreConfidenceForNhParsing( configuration
+                    .isInternalNumberAreConfidenceForNhParsing() );
+            instance.setEditable( configuration.isEditable() );
+            instance.setColorLabelsSameAsParentBranch( configuration.isColorLabelsSameAsParentBranch() );
+            instance.setShowDomainLabels( configuration.isShowDomainLabels() );
+            instance.setAbbreviateScientificTaxonNames( configuration.isAbbreviateScientificTaxonNames() );
+            if ( configuration.getMinConfidenceValue() != MIN_CONFIDENCE_DEFAULT ) {
+                instance.setMinConfidenceValue( configuration.getMinConfidenceValue() );
+            }
+            if ( configuration.getGraphicsExportX() > 0 ) {
+                instance.setPrintSizeX( configuration.getGraphicsExportX() );
+            }
+            if ( configuration.getGraphicsExportY() > 0 ) {
+                instance.setPrintSizeY( configuration.getGraphicsExportY() );
+            }
+            if ( configuration.getBaseFontSize() > 0 ) {
+                instance.setBaseFont( instance.getBaseFont().deriveFont( ( float ) configuration.getBaseFontSize() ) );
+            }
+            if ( !ForesterUtil.isEmpty( configuration.getBaseFontFamilyName() ) ) {
+                instance.setBaseFont( new Font( configuration.getBaseFontFamilyName(), Font.PLAIN, instance
+                        .getBaseFont().getSize() ) );
+            }
+            if ( configuration.getPhylogenyGraphicsType() != null ) {
+                instance.setPhylogenyGraphicsType( configuration.getPhylogenyGraphicsType() );
+            }
+        }
+        return instance;
+    }
+
+    final void setAbbreviateScientificTaxonNames( final boolean abbreviate_scientific_names ) {
+        _abbreviate_scientific_names = abbreviate_scientific_names;
+    }
+
+    final boolean isAbbreviateScientificTaxonNames() {
+        return _abbreviate_scientific_names;
+    }
+
+    static enum CLADOGRAM_TYPE {
+        NON_LINED_UP, EXT_NODE_SUM_DEP, TOTAL_NODE_SUM_DEP;
+    }
+
+    static enum NODE_LABEL_DIRECTION {
+        HORIZONTAL, RADIAL;
+    }
+
+    static enum OVERVIEW_PLACEMENT_TYPE {
+        UPPER_LEFT( "upper left" ),
+        UPPER_RIGHT( "upper right" ),
+        LOWER_LEFT( "lower left" ),
+        LOWER_RIGHT( "lower right" );
+
+        private final String _name;
+
+        private OVERVIEW_PLACEMENT_TYPE( final String name ) {
+            _name = name;
+        }
+
+        @Override
+        public String toString() {
+            return _name;
+        }
+
+        public String toTag() {
+            return toString().replaceAll( " ", "_" );
+        }
+    }
+
+    static enum PHYLOGENY_GRAPHICS_TYPE {
+        RECTANGULAR, TRIANGULAR, EURO_STYLE, ROUNDED, CONVEX, CURVED, UNROOTED, CIRCULAR;
+    }
+
+    boolean isAllowMagnificationOfTaxonomyImages() {
+        // TODO Auto-generated method stub
+        return true;
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/PdfExporter.java b/forester/java/src/org/forester/archaeopteryx/PdfExporter.java
new file mode 100644 (file)
index 0000000..5b524e9
--- /dev/null
@@ -0,0 +1,131 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// Copyright (C) 2000-2001 Washington University School of Medicine
+// and Howard Hughes Medical Institute
+// Copyright (C) 2003-2007 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.Graphics2D;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.forester.phylogeny.Phylogeny;
+
+import com.lowagie.text.Document;
+import com.lowagie.text.DocumentException;
+import com.lowagie.text.FontFactory;
+import com.lowagie.text.Rectangle;
+import com.lowagie.text.pdf.DefaultFontMapper;
+import com.lowagie.text.pdf.PdfContentByte;
+import com.lowagie.text.pdf.PdfWriter;
+
+/*
+ * 
+ * This uses iText.
+ * 
+ * See: http://www.lowagie.com/iText/
+ * 
+ * Current version: iText-2.1.7
+ */
+final class PdfExporter {
+
+    private static final int HEIGHT_LIMIT = 100;
+    private static final int WIDTH_LIMIT  = 60;
+
+    private PdfExporter() {
+        // Empty constructor.
+    }
+
+    static String writePhylogenyToPdf( final String file_name, final TreePanel tree_panel, int width, int height )
+            throws IOException {
+        if ( height < HEIGHT_LIMIT ) {
+            height = HEIGHT_LIMIT;
+        }
+        if ( width < WIDTH_LIMIT ) {
+            width = WIDTH_LIMIT;
+        }
+        final Phylogeny phylogeny = tree_panel.getPhylogeny();
+        if ( ( phylogeny == null ) || phylogeny.isEmpty() ) {
+            return "";
+        }
+        if ( tree_panel.getMainPanel().getTreeFontSet().getSmallFont().getSize() < 1 ) {
+            throw new IOException( "fonts are too small for PDF export" );
+        }
+        final File file = new File( file_name );
+        if ( file.isDirectory() ) {
+            throw new IOException( "[" + file_name + "] is a directory" );
+        }
+        final Document document = new Document();
+        document.setPageSize( new Rectangle( width, height ) );
+        document.setMargins( WIDTH_LIMIT / 2, WIDTH_LIMIT / 2, HEIGHT_LIMIT / 2, HEIGHT_LIMIT / 2 );
+        PdfWriter writer = null;
+        try {
+            writer = PdfWriter.getInstance( document, new FileOutputStream( file_name ) );
+        }
+        catch ( final DocumentException e ) {
+            throw new IOException( e );
+        }
+        document.open();
+        final DefaultFontMapper mapper = new DefaultFontMapper();
+        FontFactory.registerDirectories();
+        if ( Util.isWindows() ) {
+            mapper.insertDirectory( "C:\\WINDOWS\\Fonts\\" );
+        }
+        else if ( Util.isMac() ) {
+            mapper.insertDirectory( "/Library/Fonts/" );
+            mapper.insertDirectory( "/System/Library/Fonts/" );
+        }
+        else {
+            mapper.insertDirectory( "/usr/X/lib/X11/fonts/TrueType/" );
+            mapper.insertDirectory( "/usr/X/lib/X11/fonts/Type1/" );
+            mapper.insertDirectory( "/usr/share/fonts/default/TrueType/" );
+            mapper.insertDirectory( "/usr/share/fonts/default/Type1/" );
+        }
+        final PdfContentByte cb = writer.getDirectContent();
+        final Graphics2D g2 = cb.createGraphics( width, height, mapper );
+        try {
+            tree_panel.paintPhylogeny( g2, true, false, width, height, 0, 0 );
+        }
+        catch ( final Exception e ) {
+            Util.unexpectedException( e );
+        }
+        finally {
+            try {
+                g2.dispose();
+                document.close();
+            }
+            catch ( final Exception e ) {
+                //Do nothing.
+            }
+        }
+        String msg = file.toString();
+        if ( ( width > 0 ) && ( height > 0 ) ) {
+            msg += " [size: " + width + ", " + height + "]";
+        }
+        return msg;
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/PhyloInferenceDialog.java b/forester/java/src/org/forester/archaeopteryx/PhyloInferenceDialog.java
new file mode 100644 (file)
index 0000000..bfc937d
--- /dev/null
@@ -0,0 +1,485 @@
+// $Id:
+// forester -- software libraries and applications
+// for genomics and evolutionary biology research.
+//
+// Copyright (C) 2010 Christian M Zmasek
+// Copyright (C) 2010 Sanford-Burnham Medical Research Institute
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.Color;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
+
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JFormattedTextField;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+import javax.swing.border.Border;
+import javax.swing.border.LineBorder;
+
+import org.forester.evoinference.distance.PairwiseDistanceCalculator.PWD_DISTANCE_METHOD;
+import org.forester.sequence.Sequence;
+import org.forester.util.BasicDescriptiveStatistics;
+import org.forester.util.DescriptiveStatistics;
+
+public class PhyloInferenceDialog extends JDialog implements ActionListener {
+
+    private static final long                  serialVersionUID = 8337543508238133614L;
+    private final JPanel                       _pnl;
+    private final JButton                      _launch_btn;
+    private final JButton                      _cancel_btn;
+    private final JFormattedTextField          _bootstrap_tf;
+    private final JCheckBox                    _bootstrap_cb;
+    private final PhylogeneticInferenceOptions _opts;
+    private JTextField                         _input_msa_file_tf;
+    private JButton                            _select_input_msa_btn;
+    private final MainFrameApplication         _parent_frame;
+    private JTextField                         _msa_length_tf;
+    private JTextField                         _msa_size_tf;
+    private JTextField                         _msa_type_tf;
+    private final JRadioButton                 _distance_calc_kimura_rb;
+    private final JRadioButton                 _distance_calc_poisson_rb;
+    private final JRadioButton                 _distance_calc_fract_dissimilarity_rb;
+    private int                                _value           = JOptionPane.CANCEL_OPTION;
+    private JTextField                         _input_seqs_tf;
+    private JButton                            _select_input_seqs_btn;
+    private JTextField                         _input_seqs_number_tf;
+    private JTextField                         _input_seqs_median_length_tf;
+    private JTextField                         _input_seqs_min_length_tf;
+    private JTextField                         _input_seqs_max_length_tf;
+    private JTextField                         _input_seqs_type_tf;
+    private JTextField                         _input_seqs_msa_program_name_tf;
+    private JTextField                         _input_seqs_msa_paramenters_tf;
+    private JTextField                         _msa_processing_max_allowed_gap_ratio_tf;
+    private JTextField                         _msa_processing_min_allowed_length_tf;
+    private JTextField                         _random_seed_tf;
+    private JCheckBox                          _execute_msa_processing_cb;
+    private JCheckBox                          _msa_processing_remove_all_gap_columns_cb;
+    private JCheckBox                          _save_pwd_file_cb;
+    private JCheckBox                          _save_processed_msa_cb;
+    private JCheckBox                          _save_original_msa_cb;
+    private JTextField                         _pwd_outfile_tf;
+    private JTextField                         _processed_msa_outfile_tf;
+    private JTextField                         _original_msa_outfile_tf;
+
+    public PhyloInferenceDialog( final MainFrameApplication frame,
+                                 final PhylogeneticInferenceOptions options,
+                                 final boolean from_unaligned_seqs ) {
+        super( frame, true );
+        setVisible( false );
+        _parent_frame = frame;
+        _opts = options;
+        _pnl = new JPanel();
+        getContentPane().add( _pnl );
+        final BoxLayout box_layout = new BoxLayout( _pnl, BoxLayout.PAGE_AXIS );
+        _pnl.setLayout( box_layout );
+        if ( from_unaligned_seqs ) {
+            setTitle( "Phylogenetic Inference (including multiple sequence alignment)" );
+            final JPanel inputfile_pnl_1 = new JPanel();
+            final JPanel inputfile_pnl_2 = new JPanel();
+            final JPanel inputfile_pnl_3 = new JPanel();
+            inputfile_pnl_1.setLayout( new FlowLayout() );
+            inputfile_pnl_2.setLayout( new FlowLayout() );
+            inputfile_pnl_3.setLayout( new FlowLayout() );
+            inputfile_pnl_1.add( new JLabel( "Input Sequence File:" ) );
+            inputfile_pnl_1.add( _input_seqs_tf = new JTextField() );
+            inputfile_pnl_1.add( _select_input_seqs_btn = new JButton( "Select Input File" ) );
+            inputfile_pnl_2.add( new JLabel( "Sequences: " ) );
+            inputfile_pnl_2.add( new JLabel( "Number of Sequences:" ) );
+            inputfile_pnl_2.add( _input_seqs_number_tf = new JTextField() );
+            inputfile_pnl_2.add( new JLabel( "Length: median:" ) );
+            inputfile_pnl_2.add( _input_seqs_median_length_tf = new JTextField() );
+            inputfile_pnl_2.add( new JLabel( "min:" ) );
+            inputfile_pnl_2.add( _input_seqs_min_length_tf = new JTextField() );
+            inputfile_pnl_2.add( new JLabel( "max:" ) );
+            inputfile_pnl_2.add( _input_seqs_max_length_tf = new JTextField() );
+            inputfile_pnl_2.add( new JLabel( "Type:" ) );
+            inputfile_pnl_2.add( _input_seqs_type_tf = new JTextField() );
+            inputfile_pnl_3.add( new JLabel( "Mutiple Sequence Alignment: " ) );
+            inputfile_pnl_3.add( new JLabel( "Program: " ) );
+            inputfile_pnl_3.add( _input_seqs_msa_program_name_tf = new JTextField() );
+            inputfile_pnl_3.add( new JLabel( "Parameters: " ) );
+            inputfile_pnl_3.add( _input_seqs_msa_paramenters_tf = new JTextField() );
+            _input_seqs_median_length_tf.setColumns( 4 );
+            _input_seqs_min_length_tf.setColumns( 4 );
+            _input_seqs_max_length_tf.setColumns( 4 );
+            _input_seqs_number_tf.setColumns( 4 );
+            _input_seqs_type_tf.setColumns( 2 );
+            _input_seqs_tf.setColumns( 20 );
+            _input_seqs_tf.setEditable( false );
+            _input_seqs_median_length_tf.setEditable( false );
+            _input_seqs_min_length_tf.setEditable( false );
+            _input_seqs_max_length_tf.setEditable( false );
+            _input_seqs_number_tf.setEditable( false );
+            _input_seqs_type_tf.setEditable( false );
+            _input_seqs_msa_program_name_tf.setEditable( false );
+            _input_seqs_msa_paramenters_tf.setColumns( 26 );
+            _select_input_seqs_btn.addActionListener( this );
+            _pnl.add( inputfile_pnl_1 );
+            _pnl.add( inputfile_pnl_2 );
+            _pnl.add( inputfile_pnl_3 );
+        }
+        else {
+            setTitle( "Phylogenetic Inference (from already aligned sequences) " );
+            // Inputfile (MSA):
+            final JPanel inputfile_pnl_1 = new JPanel();
+            final JPanel inputfile_pnl_2 = new JPanel();
+            inputfile_pnl_1.setLayout( new FlowLayout() );
+            inputfile_pnl_2.setLayout( new FlowLayout() );
+            inputfile_pnl_1.add( new JLabel( "Input MSA File:" ) );
+            inputfile_pnl_1.add( _input_msa_file_tf = new JTextField() );
+            inputfile_pnl_1.add( _select_input_msa_btn = new JButton( "Select Input File" ) );
+            inputfile_pnl_2.add( new JLabel( "MSA: " ) );
+            inputfile_pnl_2.add( new JLabel( "Number of Sequences:" ) );
+            inputfile_pnl_2.add( _msa_size_tf = new JTextField() );
+            inputfile_pnl_2.add( new JLabel( "Length:" ) );
+            inputfile_pnl_2.add( _msa_length_tf = new JTextField() );
+            inputfile_pnl_2.add( new JLabel( "Type:" ) );
+            inputfile_pnl_2.add( _msa_type_tf = new JTextField() );
+            _msa_length_tf.setColumns( 4 );
+            _msa_size_tf.setColumns( 4 );
+            _msa_type_tf.setColumns( 2 );
+            _input_msa_file_tf.setColumns( 20 );
+            _input_msa_file_tf.setEditable( false );
+            _msa_length_tf.setEditable( false );
+            _msa_size_tf.setEditable( false );
+            _msa_type_tf.setEditable( false );
+            _select_input_msa_btn.addActionListener( this );
+            _pnl.add( inputfile_pnl_1 );
+            _pnl.add( inputfile_pnl_2 );
+        }
+        //
+        final JPanel inputfile_pnl_4 = new JPanel();
+        inputfile_pnl_4.setLayout( new FlowLayout() );
+        inputfile_pnl_4.add( new JLabel( "MSA Processing: " ) );
+        inputfile_pnl_4.add( _execute_msa_processing_cb = new JCheckBox( "Process MSA" ) );
+        inputfile_pnl_4.add( _msa_processing_remove_all_gap_columns_cb = new JCheckBox( "Remove all gap columns" ) );
+        inputfile_pnl_4.add( new JLabel( "Max allowed gap ratio: " ) );
+        inputfile_pnl_4.add( _msa_processing_max_allowed_gap_ratio_tf = new JTextField() );
+        inputfile_pnl_4.add( new JLabel( "Min allowed non-gap sequence length: " ) );
+        inputfile_pnl_4.add( _msa_processing_min_allowed_length_tf = new JTextField() );
+        _msa_processing_max_allowed_gap_ratio_tf.setColumns( 4 );
+        _msa_processing_min_allowed_length_tf.setColumns( 4 );
+        final Border b = new LineBorder( Color.DARK_GRAY );
+        inputfile_pnl_4.setBorder( b );
+        _pnl.add( inputfile_pnl_4 );
+        //
+        // Distance calculation:
+        // TODO if type==AA...
+        final JPanel distance_calc_pnl_1 = new JPanel();
+        distance_calc_pnl_1.setLayout( new FlowLayout() );
+        distance_calc_pnl_1.add( new JLabel( "Distance calculation:" ) );
+        distance_calc_pnl_1.add( _distance_calc_kimura_rb = new JRadioButton( "Kimura correction" ) );
+        distance_calc_pnl_1.add( _distance_calc_poisson_rb = new JRadioButton( "Poisson" ) );
+        distance_calc_pnl_1
+                .add( _distance_calc_fract_dissimilarity_rb = new JRadioButton( "Fractional dissimilarity" ) );
+        final ButtonGroup distance_calc_group_1 = new ButtonGroup();
+        distance_calc_group_1.add( _distance_calc_kimura_rb );
+        distance_calc_group_1.add( _distance_calc_poisson_rb );
+        distance_calc_group_1.add( _distance_calc_fract_dissimilarity_rb );
+        _pnl.add( distance_calc_pnl_1 );
+        // Bootstrap resampling:
+        final JPanel bootstrap_pnl = new JPanel();
+        bootstrap_pnl.setLayout( new FlowLayout() );
+        bootstrap_pnl.add( _bootstrap_cb = new JCheckBox( "Perform Bootstrap Resampling" ) );
+        bootstrap_pnl.add( new JLabel( "Number of Bootstrap Samples:" ) );
+        bootstrap_pnl.add( _bootstrap_tf = new JFormattedTextField( Util.createMaskFormatter( "###" ) ) );
+        _bootstrap_tf.setColumns( 4 );
+        // TODO see
+        // http://download.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html
+        // _bootstrap_tf.setColumns( 4 );
+        bootstrap_pnl.add( new JLabel( "Random Seed:" ) );
+        bootstrap_pnl.add( _random_seed_tf = new JTextField() );
+        _random_seed_tf.setColumns( 4 );
+        _pnl.add( bootstrap_pnl );
+        final JPanel launch_pnl = new JPanel();
+        launch_pnl.setLayout( new FlowLayout() );
+        _launch_btn = new JButton( "Go!" );
+        _launch_btn.addActionListener( this );
+        launch_pnl.add( _launch_btn );
+        _cancel_btn = new JButton( "Cancel" );
+        _cancel_btn.addActionListener( this );
+        launch_pnl.add( _cancel_btn );
+        _pnl.add( launch_pnl );
+        initializeValues( from_unaligned_seqs );
+        pack();
+        setLocationRelativeTo( getParentFrame() );
+        setResizable( false );
+    }
+
+    public void actionPerformed( final ActionEvent e ) {
+        if ( e.getSource() == _select_input_msa_btn ) {
+            readInputFile();
+        }
+        else if ( e.getSource() == _select_input_seqs_btn ) {
+            readInputSeqsFile();
+        }
+        else if ( e.getSource() == _launch_btn ) {
+            launch();
+        }
+        else if ( e.getSource() == _cancel_btn ) {
+            cancel();
+        }
+    }
+
+    public void activate() {
+        setVisible( true );
+    }
+
+    private MainFrameApplication getParentFrame() {
+        return _parent_frame;
+    }
+
+    public PhylogeneticInferenceOptions getPhylogeneticInferenceOptions() {
+        return _opts;
+    }
+
+    public int getValue() {
+        return _value;
+    }
+
+    private void initializeValues( final boolean from_unaligned_seqs ) {
+        _value = JOptionPane.CANCEL_OPTION;
+        if ( from_unaligned_seqs ) {
+            updateSeqsItems();
+            _input_seqs_msa_program_name_tf.setText( getPhylogeneticInferenceOptions().getMsaPrg() );
+            _input_seqs_msa_paramenters_tf.setText( getPhylogeneticInferenceOptions().getMsaPrgParameters() );
+        }
+        else {
+            updateMsaItems();
+        }
+        updateMsaProcessingItem();
+        updateDistanceCalcMethod();
+        _bootstrap_tf.setText( getPhylogeneticInferenceOptions().getBootstrapSamples() + "" );
+        _random_seed_tf.setText( getPhylogeneticInferenceOptions().getRandomNumberGeneratorSeed() + "" );
+    }
+
+    private void launch() {
+        processPerformBootstrapResampling();
+        if ( _bootstrap_cb.isSelected() ) {
+            processBootstrapSamplesNumber();
+            processRandomNumberGeneratorSeed();
+        }
+        if ( true ) {
+            //TODO
+            processMsaProcessing();
+        }
+        processDistanceCalcMethod();
+        processMsaPrgParameters();
+        setVisible( false );
+        _value = JOptionPane.OK_OPTION;
+    }
+
+    private void cancel() {
+        setVisible( false );
+        _value = JOptionPane.CANCEL_OPTION;
+    }
+
+    private void processBootstrapSamplesNumber() {
+        int bootstrap_samples = 0;
+        try {
+            bootstrap_samples = Integer.parseInt( _bootstrap_tf.getText().trim() );
+        }
+        catch ( final NumberFormatException e ) {
+            // JOptionPane.showMessageDialog( this, "Could not parse number of bootstrap resamplings from: " +  _bootstrap_tf.getText().trim(), "User Error", JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        if ( bootstrap_samples >= 0 ) {
+            getPhylogeneticInferenceOptions().setBootstrapSamples( bootstrap_samples );
+        }
+    }
+
+    private void processRandomNumberGeneratorSeed() {
+        long seed = PhylogeneticInferenceOptions.RANDOM_NUMBER_SEED_DEFAULT;
+        try {
+            seed = Long.parseLong( _random_seed_tf.getText().trim() );
+        }
+        catch ( final NumberFormatException e ) {
+            return;
+        }
+        getPhylogeneticInferenceOptions().setRandomNumberGeneratorSeed( seed );
+    }
+
+    private void processMsaProcessing() {
+        getPhylogeneticInferenceOptions().setExecuteMsaProcessing( _execute_msa_processing_cb.isSelected() );
+        getPhylogeneticInferenceOptions()
+                .setMsaProcessingRemoveAllGapColumns( _msa_processing_remove_all_gap_columns_cb.isSelected() );
+        int min_length = -1;
+        try {
+            min_length = Integer.parseInt( _msa_processing_min_allowed_length_tf.getText().trim() );
+        }
+        catch ( final NumberFormatException e ) {
+            min_length = -1;
+        }
+        if ( min_length > 0 ) {
+            getPhylogeneticInferenceOptions().setMsaProcessingMinAllowedLength( min_length );
+        }
+        double msa_processing_max_allowed_gap_ratio = -1.0;
+        try {
+            msa_processing_max_allowed_gap_ratio = Double.parseDouble( _msa_processing_max_allowed_gap_ratio_tf
+                    .getText().trim() );
+        }
+        catch ( final NumberFormatException e ) {
+            msa_processing_max_allowed_gap_ratio = -1.0;
+        }
+        if ( ( msa_processing_max_allowed_gap_ratio >= 0.0 ) && ( msa_processing_max_allowed_gap_ratio <= 1.0 ) ) {
+            getPhylogeneticInferenceOptions().setMsaProcessingMaxAllowedGapRatio( msa_processing_max_allowed_gap_ratio );
+        }
+    }
+
+    private void processDistanceCalcMethod() {
+        if ( ( _distance_calc_kimura_rb != null ) && _distance_calc_kimura_rb.isSelected() ) {
+            getPhylogeneticInferenceOptions().setPwdDistanceMethod( PWD_DISTANCE_METHOD.KIMURA_DISTANCE );
+        }
+        else if ( ( _distance_calc_poisson_rb != null ) && _distance_calc_poisson_rb.isSelected() ) {
+            getPhylogeneticInferenceOptions().setPwdDistanceMethod( PWD_DISTANCE_METHOD.POISSON_DISTANCE );
+        }
+        else if ( ( _distance_calc_fract_dissimilarity_rb != null )
+                && _distance_calc_fract_dissimilarity_rb.isSelected() ) {
+            getPhylogeneticInferenceOptions().setPwdDistanceMethod( PWD_DISTANCE_METHOD.FRACTIONAL_DISSIMILARITY );
+        }
+    }
+
+    private void processPerformBootstrapResampling() {
+        getPhylogeneticInferenceOptions().setPerformBootstrapResampling( _bootstrap_cb.isSelected() );
+    }
+
+    private void processMsaPrgParameters() {
+        if ( _input_seqs_msa_paramenters_tf != null ) {
+            getPhylogeneticInferenceOptions().setMsaPrgParameters( _input_seqs_msa_paramenters_tf.getText() );
+        }
+    }
+
+    private void readInputFile() {
+        getParentFrame().readMsaFromFile();
+        updateMsaItems();
+    }
+
+    private void readInputSeqsFile() {
+        getParentFrame().readSeqsFromFile();
+        updateSeqsItems();
+    }
+
+    private void updateDistanceCalcMethod() {
+        switch ( getPhylogeneticInferenceOptions().getPwdDistanceMethod() ) {
+            case KIMURA_DISTANCE:
+                _distance_calc_kimura_rb.setSelected( true );
+                break;
+            case POISSON_DISTANCE:
+                _distance_calc_poisson_rb.setSelected( true );
+                break;
+            case FRACTIONAL_DISSIMILARITY:
+                _distance_calc_fract_dissimilarity_rb.setSelected( true );
+                break;
+            default:
+                throw new RuntimeException( "invalid distance calc method" );
+        }
+    }
+
+    private void updateMsaProcessingItem() {
+        _execute_msa_processing_cb.setSelected( getPhylogeneticInferenceOptions().isExecuteMsaProcessing() );
+        _msa_processing_remove_all_gap_columns_cb.setSelected( getPhylogeneticInferenceOptions()
+                .isMsaProcessingRemoveAllGapColumns() );
+        if ( _opts.getMsaProcessingMaxAllowedGapRatio() > 0 ) {
+            _msa_processing_max_allowed_gap_ratio_tf.setText( _opts.getMsaProcessingMaxAllowedGapRatio() + "" );
+        }
+        if ( _opts.getMsaProcessingMinAllowedLength() > 0 ) {
+            _msa_processing_min_allowed_length_tf.setText( _opts.getMsaProcessingMinAllowedLength() + "" );
+        }
+    }
+
+    private void updateMsaItems() {
+        if ( getParentFrame().getMsa() != null ) {
+            _input_msa_file_tf.setText( getParentFrame().getMsaFile().toString() );
+            _msa_length_tf.setText( getParentFrame().getMsa().getLength() + "" );
+            _msa_size_tf.setText( getParentFrame().getMsa().getNumberOfSequences() + "" );
+            _msa_type_tf.setText( getParentFrame().getMsa().getType() + "" );
+            _input_msa_file_tf.setEnabled( true );
+            _msa_length_tf.setEnabled( true );
+            _msa_size_tf.setEnabled( true );
+            _msa_type_tf.setEnabled( true );
+            _launch_btn.setEnabled( true );
+        }
+        else {
+            _input_msa_file_tf.setText( "" );
+            _msa_length_tf.setText( "" );
+            _msa_size_tf.setText( "" );
+            _msa_type_tf.setText( "" );
+            _input_msa_file_tf.setEnabled( false );
+            _msa_length_tf.setEnabled( false );
+            _msa_size_tf.setEnabled( false );
+            _msa_type_tf.setEnabled( false );
+            _launch_btn.setEnabled( false );
+        }
+    }
+
+    private void updateSeqsItems() {
+        if ( getParentFrame().getSeqs() != null ) {
+            final DescriptiveStatistics stats = calcSequenceStats( getParentFrame().getSeqs() );
+            _input_seqs_tf.setText( getParentFrame().getSeqsFile().toString() );
+            _input_seqs_median_length_tf.setText( ( int ) stats.median() + "" );
+            _input_seqs_min_length_tf.setText( ( int ) stats.getMin() + "" );
+            _input_seqs_max_length_tf.setText( ( int ) stats.getMax() + "" );
+            _input_seqs_number_tf.setText( getParentFrame().getSeqs().size() + "" );
+            _input_seqs_type_tf.setText( getParentFrame().getSeqs().get( 0 ).getType() + "" );
+            _input_seqs_tf.setEnabled( true );
+            _input_seqs_median_length_tf.setEnabled( true );
+            _input_seqs_min_length_tf.setEnabled( true );
+            _input_seqs_max_length_tf.setEnabled( true );
+            _input_seqs_number_tf.setEnabled( true );
+            _input_seqs_type_tf.setEnabled( true );
+            _launch_btn.setEnabled( true );
+        }
+        else {
+            _input_seqs_tf.setText( "" );
+            _input_seqs_median_length_tf.setText( "" );
+            _input_seqs_min_length_tf.setText( "" );
+            _input_seqs_max_length_tf.setText( "" );
+            _input_seqs_number_tf.setText( "" );
+            _input_seqs_type_tf.setText( "" );
+            _input_seqs_tf.setEnabled( false );
+            _input_seqs_median_length_tf.setEnabled( false );
+            _input_seqs_min_length_tf.setEnabled( false );
+            _input_seqs_max_length_tf.setEnabled( false );
+            _input_seqs_number_tf.setEnabled( false );
+            _input_seqs_type_tf.setEnabled( false );
+            _launch_btn.setEnabled( false );
+        }
+    }
+
+    DescriptiveStatistics calcSequenceStats( final List<Sequence> seqs ) {
+        final DescriptiveStatistics stats = new BasicDescriptiveStatistics();
+        for( final Sequence s : seqs ) {
+            stats.addValue( s.getLength() );
+        }
+        return stats;
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/PhylogeneticInferenceOptions.java b/forester/java/src/org/forester/archaeopteryx/PhylogeneticInferenceOptions.java
new file mode 100644 (file)
index 0000000..3bd36d0
--- /dev/null
@@ -0,0 +1,254 @@
+// $Id:
+// $
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.io.File;
+
+import org.forester.evoinference.distance.PairwiseDistanceCalculator.PWD_DISTANCE_METHOD;
+import org.forester.msa.Mafft;
+
+public final class PhylogeneticInferenceOptions {
+
+    private static final int                 BOOTSTRAP_RESAMPLES_DEFAULT                  = 100;
+    private static final PWD_DISTANCE_METHOD PWD_DISTANCE_METHOD_DEFAULT                  = PWD_DISTANCE_METHOD.KIMURA_DISTANCE;
+    public static final long                 RANDOM_NUMBER_SEED_DEFAULT                   = 42L;
+    private static final boolean             PERFORM_BOOTSTRAP_RESAMPLING_DEFAULT         = false;
+    private static final double              msa_processing_max_allowed_gap_ratio_default = 0.5;
+    private static final int                 msa_processing_min_allowed_length_default    = 50;
+    private int                              _bootstrap_samples;
+    private PWD_DISTANCE_METHOD              _pwd_distance_method;
+    private long                             _random_number_generator_seed;
+    private boolean                          _perform_bootstrap_resampling;
+    private String                           _intermediate_files_base;
+    private String                           _msa_prg_parameters;
+    private boolean                          _execute_msa_processing;
+    private boolean                          _msa_processing_remove_all_gap_columns;
+    private double                           _msa_processing_max_allowed_gap_ratio;
+    private int                              _msa_processing_min_allowed_length;
+    private boolean                          _save_pwd_file;
+    private boolean                          _save_processed_msa;
+    private boolean                          _save_original_msa;
+    private File                             _pwd_outfile;
+    private File                             _processed_msa_outfile;
+    private File                             _original_msa_outfile;
+
+    public synchronized String getMsaPrgParameters() {
+        return _msa_prg_parameters;
+    }
+
+    public synchronized void setMsaPrgParameters( final String msa_prg_parameters ) {
+        _msa_prg_parameters = new String( msa_prg_parameters );
+    }
+
+    public synchronized String getIntermediateFilesBase() {
+        return _intermediate_files_base;
+    }
+
+    public synchronized String getMsaPrg() {
+        return "MAFFT";
+    }
+
+    public synchronized void setIntermediateFilesBase( final String intermediate_files_base ) {
+        _intermediate_files_base = new String( intermediate_files_base );
+    }
+
+    public PhylogeneticInferenceOptions() {
+        init();
+    }
+
+    // Deep copy.
+    public synchronized PhylogeneticInferenceOptions copy() {
+        final PhylogeneticInferenceOptions o = new PhylogeneticInferenceOptions();
+        o._bootstrap_samples = _bootstrap_samples;
+        o._pwd_distance_method = _pwd_distance_method;
+        o._random_number_generator_seed = _random_number_generator_seed;
+        o._perform_bootstrap_resampling = _perform_bootstrap_resampling;
+        o._intermediate_files_base = new String( _intermediate_files_base );
+        o._msa_prg_parameters = new String( _msa_prg_parameters );
+        o._msa_processing_max_allowed_gap_ratio = _msa_processing_max_allowed_gap_ratio;
+        o._msa_processing_min_allowed_length = _msa_processing_min_allowed_length;
+        o._execute_msa_processing = _execute_msa_processing;
+        o._msa_processing_remove_all_gap_columns = _msa_processing_remove_all_gap_columns;
+        o._save_pwd_file = _save_pwd_file;
+        o._save_processed_msa = _save_processed_msa;
+        o._save_original_msa = _save_original_msa;
+        if ( _pwd_outfile != null ) {
+            o._pwd_outfile = new File( _pwd_outfile.toString() );
+        }
+        if ( _processed_msa_outfile != null ) {
+            o._processed_msa_outfile = new File( _processed_msa_outfile.toString() );
+        }
+        if ( _original_msa_outfile != null ) {
+            o._original_msa_outfile = new File( _original_msa_outfile.toString() );
+        }
+        return o;
+    }
+
+    private synchronized void init() {
+        _bootstrap_samples = BOOTSTRAP_RESAMPLES_DEFAULT;
+        _pwd_distance_method = PWD_DISTANCE_METHOD_DEFAULT;
+        _random_number_generator_seed = RANDOM_NUMBER_SEED_DEFAULT;
+        _perform_bootstrap_resampling = PERFORM_BOOTSTRAP_RESAMPLING_DEFAULT;
+        _intermediate_files_base = "";
+        _msa_prg_parameters = Mafft.getDefaultParameters();
+        _msa_processing_max_allowed_gap_ratio = msa_processing_max_allowed_gap_ratio_default;
+        _msa_processing_min_allowed_length = msa_processing_min_allowed_length_default;
+        _execute_msa_processing = false;
+        _msa_processing_remove_all_gap_columns = false;
+        _save_pwd_file = false;
+        _save_processed_msa = false;
+        _save_original_msa = false;
+        _pwd_outfile = null;
+        _processed_msa_outfile = null;
+        _original_msa_outfile = null;
+    }
+
+    public synchronized void setBootstrapSamples( final int bootstrap_samples ) {
+        _bootstrap_samples = bootstrap_samples;
+    }
+
+    public synchronized int getBootstrapSamples() {
+        return _bootstrap_samples;
+    }
+
+    public synchronized void setPwdDistanceMethod( final PWD_DISTANCE_METHOD pwd_distance_method ) {
+        _pwd_distance_method = pwd_distance_method;
+    }
+
+    public synchronized PWD_DISTANCE_METHOD getPwdDistanceMethod() {
+        return _pwd_distance_method;
+    }
+
+    public synchronized void setRandomNumberGeneratorSeed( final long random_number_generator_seed ) {
+        _random_number_generator_seed = random_number_generator_seed;
+    }
+
+    public synchronized long getRandomNumberGeneratorSeed() {
+        return _random_number_generator_seed;
+    }
+
+    public synchronized void setPerformBootstrapResampling( final boolean perform_bootstrap_resampling ) {
+        _perform_bootstrap_resampling = perform_bootstrap_resampling;
+    }
+
+    public synchronized boolean isPerformBootstrapResampling() {
+        return _perform_bootstrap_resampling;
+    }
+
+    public static PhylogeneticInferenceOptions createInstance( final Configuration configuration ) {
+        final PhylogeneticInferenceOptions o = new PhylogeneticInferenceOptions();
+        if ( configuration.getDefaultBootstrapSamples() >= 0 ) {
+            o.setBootstrapSamples( configuration.getDefaultBootstrapSamples() );
+        }
+        return o;
+    }
+
+    public File getTempDir() {
+        //TODO
+        return new File( "/Users/zma/Desktop/tmp/" );
+    }
+
+    public void setMsaProcessingMaxAllowedGapRatio( final double msa_processing_max_allowed_gap_ratio ) {
+        _msa_processing_max_allowed_gap_ratio = msa_processing_max_allowed_gap_ratio;
+    }
+
+    public double getMsaProcessingMaxAllowedGapRatio() {
+        return _msa_processing_max_allowed_gap_ratio;
+    }
+
+    public void setMsaProcessingMinAllowedLength( final int msa_processing_min_allowed_length ) {
+        _msa_processing_min_allowed_length = msa_processing_min_allowed_length;
+    }
+
+    public int getMsaProcessingMinAllowedLength() {
+        return _msa_processing_min_allowed_length;
+    }
+
+    boolean isExecuteMsaProcessing() {
+        return _execute_msa_processing;
+    }
+
+    void setExecuteMsaProcessing( final boolean execute_msa_processing ) {
+        _execute_msa_processing = execute_msa_processing;
+    }
+
+    boolean isMsaProcessingRemoveAllGapColumns() {
+        return _msa_processing_remove_all_gap_columns;
+    }
+
+    void setMsaProcessingRemoveAllGapColumns( final boolean msa_processing_remove_all_gap_columns ) {
+        _msa_processing_remove_all_gap_columns = msa_processing_remove_all_gap_columns;
+    }
+
+    boolean isSavePwdFile() {
+        return _save_pwd_file;
+    }
+
+    void setSavePwdFile( final boolean save_pwd_file ) {
+        _save_pwd_file = save_pwd_file;
+    }
+
+    boolean isSaveProcessedMsa() {
+        return _save_processed_msa;
+    }
+
+    void setSaveProcessedMsa( final boolean save_processed_msa ) {
+        _save_processed_msa = save_processed_msa;
+    }
+
+    boolean isSaveOriginalMsa() {
+        return _save_original_msa;
+    }
+
+    void setSaveOriginalMsa( final boolean save_original_msa ) {
+        _save_original_msa = save_original_msa;
+    }
+
+    File getPwdOutfile() {
+        return _pwd_outfile;
+    }
+
+    void setPwdOutfile( final File pwd_outfile ) {
+        _pwd_outfile = pwd_outfile;
+    }
+
+    File getProcesseMsaOutfile() {
+        return _processed_msa_outfile;
+    }
+
+    void setProcesseMsaOutfile( final File processed_msa_outfile ) {
+        _processed_msa_outfile = processed_msa_outfile;
+    }
+
+    File getOriginalMsaOutfile() {
+        return _original_msa_outfile;
+    }
+
+    void setOriginalMsaOutfile( final File original_msa_outfile ) {
+        _original_msa_outfile = original_msa_outfile;
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/PhylogeneticInferrer.java b/forester/java/src/org/forester/archaeopteryx/PhylogeneticInferrer.java
new file mode 100644 (file)
index 0000000..822c65f
--- /dev/null
@@ -0,0 +1,254 @@
+// $Id:
+// forester -- software libraries and applications
+// for genomics and evolutionary biology research.
+//
+// Copyright (C) 2010 Christian M Zmasek
+// Copyright (C) 2010 Sanford-Burnham Medical Research Institute
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JOptionPane;
+
+import org.forester.evoinference.distance.NeighborJoining;
+import org.forester.evoinference.distance.PairwiseDistanceCalculator;
+import org.forester.evoinference.matrix.distance.BasicSymmetricalDistanceMatrix;
+import org.forester.evoinference.tools.BootstrapResampler;
+import org.forester.io.parsers.FastaParser;
+import org.forester.io.writers.SequenceWriter;
+import org.forester.io.writers.SequenceWriter.SEQ_FORMAT;
+import org.forester.msa.BasicMsa;
+import org.forester.msa.Mafft;
+import org.forester.msa.Msa;
+import org.forester.msa.MsaInferrer;
+import org.forester.msa.MsaTools;
+import org.forester.msa.ResampleableMsa;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.sequence.Sequence;
+import org.forester.tools.ConfidenceAssessor;
+import org.forester.util.ForesterUtil;
+
+public class PhylogeneticInferrer implements Runnable {
+
+    private Msa                                _msa;
+    private final MainFrameApplication         _mf;
+    private final PhylogeneticInferenceOptions _options;
+    private final List<Sequence>               _seqs;
+    public final static String                 MSA_FILE_SUFFIX = ".aln";
+    public final static String                 PWD_FILE_SUFFIX = ".pwd";
+
+    public PhylogeneticInferrer( final List<Sequence> seqs,
+                                 final PhylogeneticInferenceOptions options,
+                                 final MainFrameApplication mf ) {
+        _msa = null;
+        _seqs = seqs;
+        _mf = mf;
+        _options = options;
+    }
+
+    public PhylogeneticInferrer( final Msa msa,
+                                 final PhylogeneticInferenceOptions options,
+                                 final MainFrameApplication mf ) {
+        _msa = msa;
+        _seqs = null;
+        _mf = mf;
+        _options = options;
+    }
+
+    private Msa inferMsa() throws IOException {
+        final File temp_seqs_file = File.createTempFile( "aptx", ".fasta" );
+        System.out.println( "temp file: " + temp_seqs_file );
+        //final File temp_seqs_file = new File( _options.getTempDir() + ForesterUtil.FILE_SEPARATOR + "s.fasta" );
+        final BufferedWriter writer = new BufferedWriter( new FileWriter( temp_seqs_file ) );
+        SequenceWriter.writeSeqs( _seqs, writer, SEQ_FORMAT.FASTA, 100 );
+        writer.close();
+        final List<String> opts = processMafftOptions();
+        Msa msa = null;
+        try {
+            msa = runMAFFT( temp_seqs_file, opts );
+        }
+        catch ( final InterruptedException e ) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        // copy aln file to intermediate dir file
+        // delete temp seqs file
+        return msa;
+    }
+
+    private List<String> processMafftOptions() {
+        final String opts_str = _options.getMsaPrgParameters().trim().toLowerCase();
+        final String[] opts_ary = opts_str.split( " " );
+        final List<String> opts = new ArrayList<String>();
+        boolean saw_quiet = false;
+        for( final String opt : opts_ary ) {
+            opts.add( opt );
+            if ( opt.equals( "--quiet" ) ) {
+                saw_quiet = true;
+            }
+        }
+        if ( !saw_quiet ) {
+            opts.add( "--quiet" );
+        }
+        return opts;
+    }
+
+    private Phylogeny inferPhylogeny( final Msa msa ) {
+        BasicSymmetricalDistanceMatrix m = null;
+        switch ( _options.getPwdDistanceMethod() ) {
+            case KIMURA_DISTANCE:
+                m = PairwiseDistanceCalculator.calcKimuraDistances( msa );
+                break;
+            case POISSON_DISTANCE:
+                m = PairwiseDistanceCalculator.calcPoissonDistances( msa );
+                break;
+            case FRACTIONAL_DISSIMILARITY:
+                m = PairwiseDistanceCalculator.calcFractionalDissimilarities( msa );
+                break;
+            default:
+                throw new RuntimeException( "invalid pwd method" );
+        }
+        if ( !ForesterUtil.isEmpty( _options.getIntermediateFilesBase() ) ) {
+            BufferedWriter pwd_writer;
+            try {
+                pwd_writer = new BufferedWriter( new FileWriter( _options.getIntermediateFilesBase() + PWD_FILE_SUFFIX ) );
+                m.write( pwd_writer );
+                pwd_writer.close();
+            }
+            catch ( final IOException e ) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+        }
+        final NeighborJoining nj = new NeighborJoining();
+        final Phylogeny phy = nj.execute( m );
+        FastaParser.extractFastaInformation( phy );
+        return phy;
+    }
+
+    private void infer() {
+        //_mf.getMainPanel().getCurrentTreePanel().setWaitCursor();
+        if ( ( _msa == null ) && ( _seqs == null ) ) {
+            throw new IllegalArgumentException( "cannot run phylogenetic analysis with null msa and seq array" );
+        }
+        if ( _msa == null ) {
+            Msa msa = null;
+            try {
+                msa = inferMsa();
+            }
+            catch ( final IOException e ) {
+                JOptionPane.showMessageDialog( _mf, "Could not create multiple sequence alignment with "
+                        + _options.getMsaPrg() + "\nand the following parameters:\n\"" + _options.getMsaPrgParameters()
+                        + "\"\nError:" + e.getLocalizedMessage(), "Failed to Calculate MSA", JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            if ( msa == null ) {
+                JOptionPane.showMessageDialog( _mf, "Could not create multiple sequence alignment with "
+                        + _options.getMsaPrg() + "\nand the following parameters:\n\"" + _options.getMsaPrgParameters()
+                        + "\"", "Failed to Calculate MSA", JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            System.out.println( msa.toString() );
+            System.out.println( MsaTools.calcBasicGapinessStatistics( msa ).toString() );
+            final MsaTools msa_tools = MsaTools.createInstance();
+            if ( _options.isExecuteMsaProcessing() ) {
+                msa = msa_tools.removeGapColumns( _options.getMsaProcessingMaxAllowedGapRatio(), _options
+                        .getMsaProcessingMinAllowedLength(), msa );
+                if ( msa == null ) {
+                    JOptionPane.showMessageDialog( _mf,
+                                                   "Less than two sequences longer than "
+                                                           + _options.getMsaProcessingMinAllowedLength()
+                                                           + " residues left after MSA processing",
+                                                   "MSA Processing Settings Too Stringent",
+                                                   JOptionPane.ERROR_MESSAGE );
+                    return;
+                }
+            }
+            System.out.println( msa_tools.getIgnoredSequenceIds() );
+            System.out.println( msa.toString() );
+            System.out.println( MsaTools.calcBasicGapinessStatistics( msa ).toString() );
+            _msa = msa;
+        }
+        final int n = _options.getBootstrapSamples();
+        final long seed = _options.getRandomNumberGeneratorSeed();
+        final Phylogeny master_phy = inferPhylogeny( _msa );
+        if ( _options.isPerformBootstrapResampling() && ( n > 0 ) ) {
+            final ResampleableMsa resampleable_msa = new ResampleableMsa( ( BasicMsa ) _msa );
+            final int[][] resampled_column_positions = BootstrapResampler.createResampledColumnPositions( _msa
+                    .getLength(), n, seed );
+            final Phylogeny[] eval_phys = new Phylogeny[ n ];
+            for( int i = 0; i < n; ++i ) {
+                resampleable_msa.resample( resampled_column_positions[ i ] );
+                eval_phys[ i ] = inferPhylogeny( resampleable_msa );
+            }
+            ConfidenceAssessor.evaluate( "bootstrap", eval_phys, master_phy, true, 1 );
+        }
+        _mf.getMainPanel().addPhylogenyInNewTab( master_phy, _mf.getConfiguration(), "nj", "njpath" );
+        _mf.getMainPanel().getCurrentTreePanel().setArrowCursor();
+        JOptionPane.showMessageDialog( _mf,
+                                       "Inference successfully completed",
+                                       "Inference Completed",
+                                       JOptionPane.INFORMATION_MESSAGE );
+    }
+
+    @Override
+    public void run() {
+        infer();
+    }
+
+    private Msa runMAFFT( final File input_seqs, final List<String> opts ) throws IOException, InterruptedException {
+        Msa msa = null;
+        final MsaInferrer mafft = Mafft.createInstance();
+        try {
+            msa = mafft.infer( input_seqs, opts );
+        }
+        catch ( final IOException e ) {
+            System.out.println( mafft.getErrorDescription() );
+        }
+        return msa;
+    }
+
+    private void writeToFiles( final BasicSymmetricalDistanceMatrix m ) {
+        if ( !ForesterUtil.isEmpty( _options.getIntermediateFilesBase() ) ) {
+            try {
+                final BufferedWriter msa_writer = new BufferedWriter( new FileWriter( _options
+                        .getIntermediateFilesBase()
+                        + MSA_FILE_SUFFIX ) );
+                _msa.write( msa_writer );
+                msa_writer.close();
+                final BufferedWriter pwd_writer = new BufferedWriter( new FileWriter( _options
+                        .getIntermediateFilesBase()
+                        + PWD_FILE_SUFFIX ) );
+                m.write( pwd_writer );
+                pwd_writer.close();
+            }
+            catch ( final Exception e ) {
+                System.out.println( "Error: " + e.getMessage() );
+            }
+        }
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/Printer.java b/forester/java/src/org/forester/archaeopteryx/Printer.java
new file mode 100644 (file)
index 0000000..de5e41d
--- /dev/null
@@ -0,0 +1,77 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2009-2010 Christian M. Zmasek
+// Copyright (C) 2009-2010 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.print.PrinterException;
+import java.awt.print.PrinterJob;
+
+import org.forester.util.ForesterUtil;
+
+final class Printer {
+
+    private Printer() {
+        // Hidden constructor.
+    }
+
+    /**
+     * Returns null if printing has been aborted by the user,
+     * a String otherwise -- if a printer name was obtained this String is 
+     * the printer name, an empty String otherwise.
+     * 
+     * @param tree_panel
+     * @param job_name
+     * @return
+     * @throws PrinterException
+     */
+    static String print( final TreePanel tree_panel, final String job_name ) throws PrinterException {
+        if ( ( tree_panel == null ) || ( tree_panel.getPhylogeny() == null ) ) {
+            throw new IllegalArgumentException( "attempt to print null" );
+        }
+        if ( ForesterUtil.isEmpty( job_name ) ) {
+            throw new IllegalArgumentException( "attempt use null or empty print job name" );
+        }
+        final PrinterJob printer_job = PrinterJob.getPrinterJob();
+        if ( printer_job != null ) {
+            printer_job.setJobName( job_name );
+            printer_job.setPrintable( tree_panel );
+            final boolean ok = printer_job.printDialog();
+            if ( ok ) {
+                printer_job.print();
+                final String print_service_name = printer_job.getPrintService().getName();
+                if ( !ForesterUtil.isEmpty( print_service_name ) ) {
+                    return print_service_name;
+                }
+                return "";
+            }
+            else {
+                return null;
+            }
+        }
+        else {
+            throw new PrinterException( "failed to access printer job" );
+        }
+    }
+}
\ No newline at end of file
diff --git a/forester/java/src/org/forester/archaeopteryx/TaxonomyDataObtainer.java b/forester/java/src/org/forester/archaeopteryx/TaxonomyDataObtainer.java
new file mode 100644 (file)
index 0000000..9277823
--- /dev/null
@@ -0,0 +1,138 @@
+// $Id:
+//
+// forester -- software libraries and applications
+// for genomics and evolutionary biology research.
+//
+// Copyright (C) 2010 Christian M Zmasek
+// Copyright (C) 2010 Sanford-Burnham Medical Research Institute
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.io.IOException;
+import java.net.UnknownHostException;
+import java.util.SortedSet;
+
+import javax.swing.JOptionPane;
+
+import org.forester.analysis.AncestralTaxonomyInference;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.ws.uniprot.UniProtWsTools;
+
+public class TaxonomyDataObtainer implements Runnable {
+
+    private final Phylogeny            _phy;
+    private final MainFrameApplication _mf;
+    private final TreePanel            _treepanel;
+
+    TaxonomyDataObtainer( final MainFrameApplication mf, final TreePanel treepanel, final Phylogeny phy ) {
+        _phy = phy;
+        _mf = mf;
+        _treepanel = treepanel;
+    }
+
+    private String getBaseUrl() {
+        return UniProtWsTools.BASE_URL;
+    }
+
+    private void execute() {
+        _mf.getMainPanel().getCurrentTreePanel().setWaitCursor();
+        SortedSet<String> not_found = null;
+        try {
+            not_found = AncestralTaxonomyInference.obtainDetailedTaxonomicInformation( _phy );
+        }
+        catch ( final UnknownHostException e ) {
+            _mf.getMainPanel().getCurrentTreePanel().setArrowCursor();
+            JOptionPane.showMessageDialog( _mf,
+                                           "Could not connect to \"" + getBaseUrl() + "\"",
+                                           "Network error during taxonomic information gathering",
+                                           JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        catch ( final IOException e ) {
+            _mf.getMainPanel().getCurrentTreePanel().setArrowCursor();
+            e.printStackTrace();
+            JOptionPane.showMessageDialog( _mf,
+                                           e.toString(),
+                                           "Failed to obtain taxonomic information",
+                                           JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        finally {
+            _mf.getMainPanel().getCurrentTreePanel().setArrowCursor();
+        }
+        _treepanel.setTree( _phy );
+        _mf.showWhole();
+        _treepanel.setEdited( true );
+        if ( ( not_found != null ) && ( not_found.size() > 0 ) ) {
+            int max = not_found.size();
+            boolean more = false;
+            if ( max > 20 ) {
+                more = true;
+                max = 20;
+            }
+            final StringBuffer sb = new StringBuffer();
+            sb.append( "Not all taxonomies could be resolved.\n" );
+            if ( not_found.size() == 1 ) {
+                sb.append( "The following taxonomy was not found:\n" );
+            }
+            else {
+                sb.append( "The following taxonomies were not found (total: " + not_found.size() + "):\n" );
+            }
+            int i = 0;
+            for( final String string : not_found ) {
+                if ( i > 19 ) {
+                    break;
+                }
+                sb.append( string );
+                sb.append( "\n" );
+                ++i;
+            }
+            if ( more ) {
+                sb.append( "..." );
+            }
+            try {
+                JOptionPane.showMessageDialog( _mf,
+                                               sb.toString(),
+                                               "Taxonomy Tool Completed",
+                                               JOptionPane.WARNING_MESSAGE );
+            }
+            catch ( final Exception e ) {
+                // Not important if this fails, do nothing. 
+            }
+        }
+        else {
+            try {
+                JOptionPane.showMessageDialog( _mf,
+                                               "Taxonomy tool successfully completed",
+                                               "Taxonomy Tool Completed",
+                                               JOptionPane.INFORMATION_MESSAGE );
+            }
+            catch ( final Exception e ) {
+                // Not important if this fails, do nothing.
+            }
+        }
+    }
+
+    @Override
+    public void run() {
+        execute();
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/TextFrame.java b/forester/java/src/org/forester/archaeopteryx/TextFrame.java
new file mode 100644 (file)
index 0000000..54c6f80
--- /dev/null
@@ -0,0 +1,158 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// Copyright (C) 2000-2001 Washington University School of Medicine
+// and Howard Hughes Medical Institute
+// Copyright (C) 2003-2007 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Container;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.ClipboardOwner;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+final class TextFrame extends JFrame implements ActionListener, ClipboardOwner {
+
+    /**
+     * 
+     */
+    private static final long serialVersionUID = -5012834229705518363L;
+    private static Color      ta_text_color    = new Color( 0, 0, 0 ),
+            ta_background_color = new Color( 240, 240, 240 ), background_color = new Color( 215, 215, 215 ),
+            button_background_color = new Color( 215, 215, 215 ), button_text_color = new Color( 0, 0, 0 );
+    private final static Font button_font      = new Font( "Helvetica", Font.PLAIN, 10 ),
+            ta_font = new Font( "Helvetica", Font.PLAIN, 10 );
+    private boolean           can_use_clipboard;
+    private final String      text;
+    private final JTextArea   jtextarea;
+    private final JButton     close_button;
+    private JButton           copy_button;
+    private final JPanel      buttonjpanel;
+    private final Container   contentpane;
+
+    private TextFrame( final String s ) {
+        // first things first
+        setTitle( Constants.PRG_NAME );
+        text = s;
+        // check to see if we have permission to use the clipboard:
+        can_use_clipboard = true;
+        final SecurityManager sm = System.getSecurityManager();
+        if ( sm != null ) {
+            try {
+                sm.checkSystemClipboardAccess();
+            }
+            catch ( final Exception e ) {
+                //nope!
+                can_use_clipboard = false;
+            }
+        }
+        // set up the frame
+        setBackground( background_color );
+        buttonjpanel = new JPanel();
+        buttonjpanel.setBackground( background_color );
+        close_button = new JButton( "          Close          " );
+        close_button.setBackground( button_background_color );
+        close_button.setForeground( button_text_color );
+        close_button.setFont( button_font );
+        close_button.addActionListener( this );
+        buttonjpanel.add( close_button );
+        if ( can_use_clipboard ) {
+            copy_button = new JButton( "Copy to clipboard" );
+            copy_button.setBackground( button_background_color );
+            copy_button.setForeground( button_text_color );
+            copy_button.setFont( button_font );
+            copy_button.addActionListener( this );
+            buttonjpanel.add( copy_button );
+        }
+        contentpane = getContentPane();
+        contentpane.setLayout( new BorderLayout() );
+        jtextarea = new JTextArea( text );
+        jtextarea.setBackground( ta_background_color );
+        jtextarea.setForeground( ta_text_color );
+        jtextarea.setFont( ta_font );
+        jtextarea.setEditable( false );
+        jtextarea.setWrapStyleWord( true );
+        jtextarea.setLineWrap( true );
+        contentpane.add( new JScrollPane( jtextarea ), BorderLayout.CENTER );
+        buttonjpanel.setLayout( new FlowLayout( FlowLayout.CENTER, 20, 5 ) );
+        contentpane.add( buttonjpanel, BorderLayout.SOUTH );
+        setSize( 500, 400 );
+        addWindowListener( new WindowAdapter() {
+
+            @Override
+            public void windowClosing( final WindowEvent e ) {
+                close();
+            }
+        } );
+        setVisible( true );
+    }
+
+    public void actionPerformed( final ActionEvent e ) {
+        final Object o = e.getSource();
+        if ( o == close_button ) {
+            close();
+        }
+        else if ( o == copy_button ) {
+            copy();
+        }
+    }
+
+    void close() {
+        setVisible( false );
+        dispose();
+    }
+
+    private void copy() {
+        if ( !can_use_clipboard ) {
+            // can't do this!
+            return;
+        }
+        final Clipboard sys_clipboard = getToolkit().getSystemClipboard();
+        final StringSelection contents = new StringSelection( jtextarea.getText() );
+        sys_clipboard.setContents( contents, this );
+    }
+
+    public void lostOwnership( final Clipboard clipboard, final Transferable contents ) {
+    }
+
+    static TextFrame instantiate( final String s ) {
+        return new TextFrame( s );
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/TreeColorSet.java b/forester/java/src/org/forester/archaeopteryx/TreeColorSet.java
new file mode 100644 (file)
index 0000000..b99a27b
--- /dev/null
@@ -0,0 +1,435 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2010 Christian M. Zmasek
+// Copyright (C) 2008-2010 Burnham Institute for Medical Research
+// Copyright (C) 2003-2010 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.Color;
+import java.util.Map;
+
+import org.forester.util.ForesterUtil;
+
+/*
+ * Maintains the color schemes and a set of colors for drawing a tree.
+ */
+final class TreeColorSet {
+
+    static final String[]   SCHEME_NAMES   = { "Default", "Black", "Black & White", "Silver", "The Matrix",
+            "White & Blue", "Cyan", "Clockwork", "Blue", "Blue & White", "Neon" };
+    static final String[]   COLOR_FIELDS   = { "Background", "Background Gradient Bottom", "Sequence", "Taxonomy",
+            "Confidence", "Branch Length", "Branch", "Node Box", "Collapsed", "Matching Nodes", "Duplication",
+            "Speciation", "Duplication or Specation", "Domains", "Binary Domain Combinations", "Annotation", "Overview" };
+    // All the color sets; better be the same # of sets as there are names!
+    private final Color[][] _color_schemes = { { new Color( 0, 0, 0 ), // background_color
+            new Color( 0, 100, 100 ), // background_color_gradient_bottom
+            new Color( 220, 220, 220 ), // sequence  __ Default (same as Black)
+            new Color( 180, 180, 180 ), // taxonomy
+            new Color( 56, 176, 222 ), // support  
+            new Color( 140, 140, 140 ), // branch_length_color
+            new Color( 255, 255, 255 ), // branch_color
+            new Color( 255, 255, 255 ), // box_color
+            new Color( 255, 255, 0 ), // collapesed_fill_color
+            new Color( 0, 255, 0 ), // found_color
+            new Color( 255, 0, 0 ), // duplication_box_color
+            new Color( 0, 255, 0 ), // speciation_box_color
+            new Color( 255, 255, 0 ), // duplication_speciation_color
+            new Color( 123, 104, 238 ), // domains_color  
+            new Color( 65, 105, 255 ), // binary_domain_combinations_color  
+            new Color( 173, 255, 47 ) // annotation
+            , new Color( 130, 130, 130 )  // overview
+            }, { new Color( 0, 0, 0 ), // background_color
+            new Color( 0, 255, 255 ), // background_color_gradient_bottom    
+            new Color( 220, 220, 220 ), // sequence  __ Black
+            new Color( 180, 180, 180 ), // taxonomy
+            new Color( 56, 176, 222 ), // support  
+            new Color( 140, 140, 140 ), // branch_length_color
+            new Color( 255, 255, 255 ), // branch_color
+            new Color( 255, 255, 255 ), // box_color
+            new Color( 255, 255, 0 ), // collapesed_fill_color
+            new Color( 0, 255, 0 ), // found_color
+            new Color( 255, 0, 0 ), // duplication_box_color
+            new Color( 0, 255, 0 ), // speciation_box_color
+            new Color( 255, 255, 0 ), // duplication_speciation_color
+            new Color( 123, 104, 238 ), // domains_color
+            new Color( 65, 105, 255 ), // binary_domain_combinations_color
+            new Color( 173, 255, 47 ) // annotation
+            , new Color( 130, 130, 130 ) // ov
+            }, { new Color( 255, 255, 255 ), // background_color
+            new Color( 0, 255, 255 ), // background_color_gradient_bottom
+            new Color( 0, 0, 0 ), // sequence  __ Black & White
+            new Color( 0, 0, 0 ), // taxonomy
+            new Color( 0, 0, 0 ), // support 
+            new Color( 0, 0, 0 ), // branch_length_color
+            new Color( 0, 0, 0 ), // branch_color
+            new Color( 0, 0, 0 ), // box_color
+            new Color( 0, 0, 0 ), // collapesed_fill_color
+            new Color( 255, 0, 0 ), // found_color
+            new Color( 0, 0, 0 ), // duplication_box_color
+            new Color( 200, 200, 200 ), // speciation_box_color
+            new Color( 0, 0, 0 ), // duplication_speciation_color
+            new Color( 0, 0, 0 ), // domains_color
+            new Color( 0, 0, 0 ), // binary_domain_combinations_color
+            new Color( 0, 0, 0 ) // annotation
+            , new Color( 220, 220, 220 ) // ov
+            }, { new Color( 0, 0, 0 ), // background_color
+            new Color( 0, 255, 255 ), // background_color_gradient_bottom
+            new Color( 220, 220, 220 ), // sequence __ Silver
+            new Color( 180, 180, 180 ), // taxonomy
+            new Color( 140, 140, 140 ), // support 
+            new Color( 140, 140, 140 ), // branch_length_color
+            new Color( 240, 240, 240 ), // branch_color
+            new Color( 140, 140, 140 ), // box_color
+            new Color( 140, 140, 140 ), // collapesed_fill_color
+            new Color( 255, 0, 0 ), // found_color
+            new Color( 255, 0, 0 ), // duplication_box_color
+            new Color( 200, 200, 200 ), // speciation_box_color
+            new Color( 140, 140, 140 ), // duplication_speciation_color
+            new Color( 180, 180, 180 ), // domains_color
+            new Color( 180, 180, 180 ), // binary_domain_combinations_color
+            new Color( 140, 140, 140 ) // annotation
+            , new Color( 40, 40, 40 ) // ov
+            }, { new Color( 0, 10, 0 ), // background_color
+            new Color( 0, 255, 255 ), // background_color_gradient_bottom
+            new Color( 0, 255, 0 ), // sequence __ the Matrix
+            new Color( 30, 200, 30 ), // taxonomy
+            new Color( 0, 155, 0 ), // support 
+            new Color( 0, 100, 0 ), // branch_length_color
+            new Color( 0, 155, 0 ), // branch_color
+            new Color( 0, 255, 0 ), // box_color
+            new Color( 0, 255, 0 ), // collapesed_fill_color
+            new Color( 255, 255, 255 ), // found_color
+            new Color( 255, 255, 255 ), // duplication_box_color
+            new Color( 0, 255, 0 ), // speciation_box_color
+            new Color( 120, 120, 120 ), // duplication_speciation_color
+            new Color( 0, 235, 0 ), // domains_color
+            new Color( 0, 235, 0 ), // binary_domain_combinations_color
+            new Color( 0, 235, 0 ) // annotation
+            , new Color( 40, 40, 40 ) // ov
+            }, { new Color( 255, 255, 255 ), // background_color
+            new Color( 0, 255, 255 ), // background_color_gradient_bottom
+            new Color( 0, 0, 0 ), //sequence __ White & Blue
+            new Color( 40, 40, 40 ), // taxonomy
+            new Color( 0, 125, 0 ), // support 
+            new Color( 70, 70, 0 ), // branch_length_color
+            new Color( 0, 20, 200 ), // branch_color
+            new Color( 0, 20, 200 ), // box_color
+            new Color( 255, 255, 0 ), // collapesed_fill_color
+            new Color( 0, 255, 0 ), // found_color
+            new Color( 255, 0, 0 ), // duplication_box_color
+            new Color( 0, 255, 0 ), // speciation_box_color
+            new Color( 255, 255, 0 ), // duplication_speciation_color
+            new Color( 123, 104, 238 ), // domains_color
+            new Color( 65, 105, 225 ), // binary_domain_combinations_color
+            new Color( 173, 255, 47 ) // annotation
+            , new Color( 220, 220, 220 ) // ov
+            }, { new Color( 0, 0, 0 ), // background_color
+            new Color( 0, 255, 255 ), // background_color_gradient_bottom
+            new Color( 255, 255, 255 ), // sequence __ Cyan
+            new Color( 200, 200, 200 ), // taxonomy
+            new Color( 255, 255, 255 ), // support 
+            new Color( 200, 200, 200 ), // branch_length_color
+            new Color( 0, 255, 255 ), // branch_color
+            new Color( 0, 255, 255 ), // box_color
+            new Color( 255, 255, 0 ), // collapesed_fill_color
+            new Color( 0, 255, 0 ), // found_color
+            new Color( 255, 0, 0 ), // duplication_box_color
+            new Color( 0, 255, 0 ), // speciation_box_color
+            new Color( 255, 255, 0 ), // duplication_speciation_color
+            new Color( 123, 104, 238 ), // domains_color
+            new Color( 65, 105, 225 ), // binary_domain_combinations_color
+            new Color( 173, 255, 47 ) // annotation
+            , new Color( 0, 120, 120 ) // ov
+            }, { new Color( 0, 0, 0 ), // background_color
+            new Color( 0, 255, 255 ), // background_color_gradient_bottom
+            new Color( 255, 200, 0 ), // sequence __ Clockwork
+            new Color( 255, 200, 0 ), // taxonomy
+            new Color( 255, 200, 0 ), // support 
+            new Color( 255, 200, 0 ), // branch_length_color
+            new Color( 255, 200, 0 ), // branch_color
+            new Color( 255, 200, 0 ), // box_color
+            new Color( 255, 255, 255 ), // collapesed_fill_color
+            new Color( 255, 255, 255 ), // found_color
+            new Color( 255, 0, 0 ), // duplication_box_color
+            new Color( 0, 255, 0 ), // speciation_box_color
+            new Color( 255, 255, 0 ), // duplication_speciation_color
+            new Color( 150, 150, 150 ), // domains_color
+            new Color( 150, 150, 150 ), // binary_domain_combinations_color
+            new Color( 150, 150, 150 ) // annotation
+            , new Color( 150, 150, 150 ) // ov
+            }, { new Color( 0, 0, 100 ), // background_color
+            new Color( 0, 255, 255 ), // background_color_gradient_bottom
+            new Color( 255, 255, 255 ), // sequence __ Blue
+            new Color( 255, 255, 255 ), // taxonomy
+            new Color( 255, 0, 0 ), // support 
+            new Color( 255, 0, 0 ), // branch_length_color
+            new Color( 255, 0, 0 ), // branch_color
+            new Color( 255, 0, 0 ), // box_color
+            new Color( 0, 0, 0 ), // collapesed_fill_color
+            new Color( 0, 255, 0 ), // found_color
+            new Color( 255, 0, 255 ), // duplication_box_color
+            new Color( 255, 255, 255 ), // speciation_box_color
+            new Color( 100, 100, 100 ), // duplication_speciation_color
+            new Color( 255, 255, 255 ), // domains_color
+            new Color( 255, 255, 255 ), // binary_domain_combinations_color
+            new Color( 255, 255, 255 ) // annotation
+            , new Color( 77, 77, 255 ) // ov
+            }, { new Color( 0, 0, 0 ), // background_color
+            new Color( 0, 255, 255 ), // background_color_gradient_bottom
+            new Color( 255, 255, 255 ), // sequence __ blue &  white
+            new Color( 255, 255, 255 ), // taxonomy
+            new Color( 255, 255, 255 ), // support 
+            new Color( 0, 191, 255 ), // branch_length_color
+            new Color( 0, 191, 255 ), // branch_color
+            new Color( 0, 191, 255 ), // box_color
+            new Color( 255, 255, 255 ), // collapesed_fill_color
+            new Color( 255, 0, 0 ), // found_color
+            new Color( 255, 0, 0 ), // duplication_box_color
+            new Color( 0, 255, 0 ), // speciation_box_color
+            new Color( 255, 255, 0 ), // duplication_speciation_color
+            new Color( 255, 255, 255 ), // domains_color
+            new Color( 255, 255, 255 ), // binary_domain_combinations_color
+            new Color( 255, 255, 255 ) // annotation
+            , new Color( 170, 187, 204 ) // ov
+            }, { new Color( 0, 0, 0 ), // background_color
+            new Color( 255, 255, 0 ), // background_color_gradient_bottom
+            new Color( 127, 255, 0 ), // sequence __ Neon
+            new Color( 255, 110, 199 ), // taxonomy
+            new Color( 234, 173, 234 ), // support 
+            new Color( 77, 77, 255 ), // branch_length_color
+            new Color( 234, 173, 234 ), // branch_color
+            new Color( 77, 77, 255 ), // box_color
+            new Color( 77, 77, 255 ), // collapesed_fill_color
+            new Color( 243, 243, 21 ), // found_color
+            new Color( 255, 0, 0 ), // duplication_box_color
+            new Color( 0, 255, 0 ), // speciation_box_color
+            new Color( 255, 255, 0 ), // duplication_speciation_color
+            new Color( 27, 255, 0 ), // domains_color
+            new Color( 27, 255, 0 ), // binary_domain_combinations_color
+            new Color( 27, 255, 0 ) // annotation
+            , new Color( 77, 77, 255 ) // ov
+            }                             };
+    // Color schemes:
+    private int             _color_scheme;
+    // The drawing colors
+    private Color           seq_color;
+    private Color           taxonomy_color;
+    private Color           bootstrap_color;
+    private Color           branch_length_color;
+    private Color           branch_color;
+    private Color           box_color;
+    private Color           background_color;
+    private Color           background_color_gradient_bottom;
+    private Color           dup_box_color;
+    private Color           spec_box_color;
+    private Color           collapse_fill_color;
+    private Color           found_color;
+    private Color           duplication_or_specation_color;
+    private Color           domains_color;
+    private Color           binary_domain_combinations_color;
+    private Color           annotation_color;
+    private Color           ov_color;
+
+    private TreeColorSet() {
+        // Hidden constructor.
+    }
+
+    void cycleColorScheme() {
+        if ( getCurrentColorScheme() >= _color_schemes.length - 1 ) {
+            setColorSchema( 0 );
+        }
+        else {
+            setColorSchema( getCurrentColorScheme() + 1 );
+        }
+    }
+
+    Color getAnnotationColor() {
+        return annotation_color;
+    }
+
+    Color getBackgroundColor() {
+        return background_color;
+    }
+
+    Color getBackgroundColorGradientBottom() {
+        return background_color_gradient_bottom;
+    }
+
+    Color getBinaryDomainCombinationsColor() {
+        if ( Constants.SPECIAL_CUSTOM ) {
+            return new Color( 50, 50, 50 );
+        }
+        return binary_domain_combinations_color;
+    }
+
+    Color getBoxColor() {
+        return box_color;
+    }
+
+    Color getBranchColor() {
+        return branch_color;
+    }
+
+    Color getBranchColorForPdf() {
+        return Color.BLACK;
+    }
+
+    Color getBranchLengthColor() {
+        return branch_length_color;
+    }
+
+    Color getCollapseFillColor() {
+        return collapse_fill_color;
+    }
+
+    Color[][] getColorSchemes() {
+        return _color_schemes;
+    }
+
+    Color getConfidenceColor() {
+        return bootstrap_color;
+    }
+
+    int getCurrentColorScheme() {
+        return _color_scheme;
+    }
+
+    String getCurrentColorSchemeName() {
+        return SCHEME_NAMES[ getCurrentColorScheme() ];
+    }
+
+    Color getDomainsColor() {
+        return domains_color;
+    }
+
+    Color getDuplicationBoxColor() {
+        return dup_box_color;
+    }
+
+    Color getDuplicationOrSpeciationColor() {
+        return duplication_or_specation_color;
+    }
+
+    Color getFoundColor() {
+        return found_color;
+    }
+
+    Color getGainedCharactersColor() {
+        return Color.GREEN;
+    }
+
+    Color getLostCharactersColor() {
+        return Color.RED;
+    }
+
+    Color getOvColor() {
+        return ov_color;
+    }
+
+    Color getSequenceColor() {
+        return seq_color;
+    }
+
+    Color getSpecBoxColor() {
+        return spec_box_color;
+    }
+
+    Color getTaxonomyColor() {
+        return taxonomy_color;
+    }
+
+    void setColorforDefault( final String color_field_name, final Color color ) {
+        final String query = color_field_name.trim().replace( '_', ' ' );
+        boolean found = false;
+        int i = 0;
+        for( final String cf : COLOR_FIELDS ) {
+            if ( query.equalsIgnoreCase( cf ) ) {
+                found = true;
+                setColorForDefault( i, color );
+                break;
+            }
+            ++i;
+        }
+        if ( !found ) {
+            throw new IllegalArgumentException( "unknown color field name [" + color_field_name + "]" );
+        }
+    }
+
+    private void setColorForDefault( final int i, final Color color ) {
+        _color_schemes[ 0 ][ i ] = color;
+    }
+
+    /**
+     * Switches colors between different schemes.
+     */
+    void setColorSchema( final int scheme ) {
+        _color_scheme = scheme;
+        background_color = _color_schemes[ scheme ][ 0 ];
+        background_color_gradient_bottom = _color_schemes[ scheme ][ 1 ];
+        seq_color = _color_schemes[ scheme ][ 2 ];
+        taxonomy_color = _color_schemes[ scheme ][ 3 ];
+        bootstrap_color = _color_schemes[ scheme ][ 4 ];
+        branch_length_color = _color_schemes[ scheme ][ 5 ];
+        branch_color = _color_schemes[ scheme ][ 6 ];
+        box_color = _color_schemes[ scheme ][ 7 ];
+        collapse_fill_color = _color_schemes[ scheme ][ 8 ];
+        found_color = _color_schemes[ scheme ][ 9 ];
+        dup_box_color = _color_schemes[ scheme ][ 10 ];
+        spec_box_color = _color_schemes[ scheme ][ 11 ];
+        duplication_or_specation_color = _color_schemes[ scheme ][ 12 ];
+        domains_color = _color_schemes[ scheme ][ 13 ];
+        binary_domain_combinations_color = _color_schemes[ scheme ][ 14 ];
+        annotation_color = _color_schemes[ scheme ][ 15 ];
+        ov_color = _color_schemes[ scheme ][ 16 ];
+    }
+
+    void setCurrentColorScheme( final int color_scheme ) {
+        _color_scheme = color_scheme;
+    }
+
+    static TreeColorSet createInstance() {
+        final TreeColorSet tcs = new TreeColorSet();
+        tcs.setColorSchema( 0 );
+        return tcs;
+    }
+
+    static TreeColorSet createInstance( final Configuration configuration ) {
+        final TreeColorSet tcs = new TreeColorSet();
+        if ( ( configuration != null ) && ( configuration.getDisplayColors() != null )
+                && ( configuration.getDisplayColors().size() > 0 ) ) {
+            final Map<String, Color> colors = configuration.getDisplayColors();
+            for( final String field : colors.keySet() ) {
+                final Color color = colors.get( field );
+                try {
+                    tcs.setColorforDefault( field, color );
+                }
+                catch ( final IllegalArgumentException ex ) {
+                    ForesterUtil.printWarningMessage( Constants.PRG_NAME, ex.getMessage() );
+                }
+            }
+        }
+        tcs.setColorSchema( 0 );
+        return tcs;
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/TreeFontSet.java b/forester/java/src/org/forester/archaeopteryx/TreeFontSet.java
new file mode 100644 (file)
index 0000000..66020cc
--- /dev/null
@@ -0,0 +1,173 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// Copyright (C) 2000-2001 Washington University School of Medicine
+// and Howard Hughes Medical Institute
+// Copyright (C) 2003-2007 Ethalinda K.S. Cannon
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.Component;
+import java.awt.Font;
+import java.awt.FontMetrics;
+
+/*
+ * Maintains the fonts for drawing a tree.
+ */
+public final class TreeFontSet {
+
+    private final static String DEFAULT_FONT          = "Verdana";
+    private final static float  FONT_SIZE_CHANGE_STEP = 1.0f;
+    static final int            BOLD_AND_ITALIC       = Font.BOLD + Font.ITALIC;
+    // the owner (needed to get font metrics)
+    private final Component     _owner;
+    // The fonts
+    private Font                _small_font;
+    private Font                _large_font;
+    private Font                _small_italic_font;
+    private Font                _large_italic_font;
+    private Font                _base_font;
+    // Handy holders for font metrics
+    public FontMetrics          _fm_small;
+    FontMetrics                 _fm_large;
+    FontMetrics                 _fm_small_italic;
+    FontMetrics                 _fm_small_italic_bold;
+    FontMetrics                 _fm_large_italic;
+    FontMetrics                 _fm_large_italic_bold;
+    // hold font measurements
+    int                         _small_max_descent    = 0;
+    int                         _small_max_ascent     = 0;
+
+    TreeFontSet( final Component owner ) {
+        _owner = owner;
+        setBaseFont( new Font( DEFAULT_FONT, Font.PLAIN, 10 ) );
+    }
+
+    void decreaseFontSize() {
+        if ( _large_font.getSize() > 0 ) {
+            _small_font = _small_font.deriveFont( _small_font.getSize() - FONT_SIZE_CHANGE_STEP );
+            _large_font = _large_font.deriveFont( _large_font.getSize() - FONT_SIZE_CHANGE_STEP );
+            _small_italic_font = _small_italic_font.deriveFont( _small_italic_font.getSize() - FONT_SIZE_CHANGE_STEP );
+            _large_italic_font = _large_italic_font.deriveFont( _large_italic_font.getSize() - FONT_SIZE_CHANGE_STEP );
+            setupFontMetrics();
+        }
+    }
+
+    Font getBaseFont() {
+        return _base_font;
+    }
+
+    Font getLargeFont() {
+        return _large_font;
+    }
+
+    Font getLargeItalicFont() {
+        return _large_italic_font;
+    }
+
+    public Font getSmallFont() {
+        return _small_font;
+    }
+
+    Font getSmallItalicFont() {
+        return _small_italic_font;
+    }
+
+    void increaseFontSize() {
+        _small_font = _small_font.deriveFont( _small_font.getSize() + FONT_SIZE_CHANGE_STEP );
+        _large_font = _large_font.deriveFont( _large_font.getSize() + FONT_SIZE_CHANGE_STEP );
+        _small_italic_font = _small_italic_font.deriveFont( _small_italic_font.getSize() + FONT_SIZE_CHANGE_STEP );
+        _large_italic_font = _large_italic_font.deriveFont( _large_italic_font.getSize() + FONT_SIZE_CHANGE_STEP );
+        setupFontMetrics();
+    }
+
+    private void intializeFonts() {
+        final int small_size = getBaseFont().getSize() - 1;
+        int italic = Font.ITALIC;
+        if ( getBaseFont().getStyle() == Font.BOLD ) {
+            italic = italic + Font.BOLD;
+        }
+        _small_font = new Font( getBaseFont().getFontName(), getBaseFont().getStyle(), small_size );
+        _large_font = new Font( getBaseFont().getFontName(), getBaseFont().getStyle(), getBaseFont().getSize() );
+        _small_italic_font = new Font( getBaseFont().getFontName(), italic, small_size );
+        _large_italic_font = new Font( getBaseFont().getFontName(), italic, getBaseFont().getSize() );
+        setupFontMetrics();
+    }
+
+    void largeFonts() {
+        _small_font = _small_font.deriveFont( 12f );
+        _large_font = _large_font.deriveFont( 14f );
+        _small_italic_font = _small_italic_font.deriveFont( 12f );
+        _large_italic_font = _large_italic_font.deriveFont( 14f );
+        setupFontMetrics();
+    }
+
+    void mediumFonts() {
+        _small_font = _small_font.deriveFont( 8f );
+        _large_font = _large_font.deriveFont( 10f );
+        _small_italic_font = _small_italic_font.deriveFont( 8f );
+        _large_italic_font = _large_italic_font.deriveFont( 10f );
+        setupFontMetrics();
+    }
+
+    void setBaseFont( final Font base_font ) {
+        _base_font = base_font;
+        intializeFonts();
+    }
+
+    private void setupFontMetrics() {
+        _fm_small = _owner.getFontMetrics( _small_font );
+        _fm_large = _owner.getFontMetrics( _large_font );
+        _fm_small_italic = _owner.getFontMetrics( _small_italic_font );
+        _fm_small_italic_bold = _owner.getFontMetrics( _small_italic_font.deriveFont( Font.BOLD ) );
+        _fm_large_italic = _owner.getFontMetrics( _large_italic_font );
+        _fm_large_italic_bold = _owner.getFontMetrics( _large_italic_font.deriveFont( Font.BOLD ) );
+        _small_max_descent = _fm_small.getMaxDescent();
+        _small_max_ascent = _fm_small.getMaxAscent() + 1;
+    }
+
+    void smallFonts() {
+        _small_font = _small_font.deriveFont( 7f );
+        _large_font = _large_font.deriveFont( 8f );
+        _small_italic_font = _small_italic_font.deriveFont( 7f );
+        _large_italic_font = _large_italic_font.deriveFont( 8f );
+        setupFontMetrics();
+    }
+
+    void superTinyFonts() {
+        _small_font = _small_font.deriveFont( 2f );
+        _large_font = _large_font.deriveFont( 3f );
+        _small_italic_font = _small_italic_font.deriveFont( 2f );
+        _large_italic_font = _large_italic_font.deriveFont( 3f );
+        setupFontMetrics();
+    }
+
+    void tinyFonts() {
+        _small_font = _small_font.deriveFont( 5f );
+        _large_font = _large_font.deriveFont( 6f );
+        _small_italic_font = _small_italic_font.deriveFont( 5f );
+        _large_italic_font = _large_italic_font.deriveFont( 6f );
+        setupFontMetrics();
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/TreePanel.java b/forester/java/src/org/forester/archaeopteryx/TreePanel.java
new file mode 100644 (file)
index 0000000..7c40d10
--- /dev/null
@@ -0,0 +1,4842 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.Polygon;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Line2D;
+import java.awt.geom.QuadCurve2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URLEncoder;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.BorderFactory;
+import javax.swing.JApplet;
+import javax.swing.JColorChooser;
+import javax.swing.JDialog;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JTextArea;
+import javax.swing.Popup;
+import javax.swing.PopupFactory;
+
+import org.forester.archaeopteryx.ControlPanel.NodeClickAction;
+import org.forester.archaeopteryx.Options.CLADOGRAM_TYPE;
+import org.forester.archaeopteryx.Options.NODE_LABEL_DIRECTION;
+import org.forester.archaeopteryx.Options.PHYLOGENY_GRAPHICS_TYPE;
+import org.forester.archaeopteryx.phylogeny.data.RenderableDomainArchitecture;
+import org.forester.archaeopteryx.phylogeny.data.RenderableVector;
+import org.forester.io.parsers.phyloxml.PhyloXmlUtil;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.phylogeny.PhylogenyMethods;
+import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.Annotation;
+import org.forester.phylogeny.data.BranchColor;
+import org.forester.phylogeny.data.Confidence;
+import org.forester.phylogeny.data.Event;
+import org.forester.phylogeny.data.PhylogenyData;
+import org.forester.phylogeny.data.PropertiesMap;
+import org.forester.phylogeny.data.Property;
+import org.forester.phylogeny.data.Sequence;
+import org.forester.phylogeny.data.SequenceRelation;
+import org.forester.phylogeny.data.Taxonomy;
+import org.forester.phylogeny.data.Uri;
+import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
+import org.forester.phylogeny.iterators.PreorderTreeIterator;
+import org.forester.util.BasicDescriptiveStatistics;
+import org.forester.util.DescriptiveStatistics;
+import org.forester.util.ForesterConstants;
+import org.forester.util.ForesterUtil;
+
+public final class TreePanel extends JPanel implements ActionListener, MouseWheelListener, Printable {
+
+    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 );
+    private static final float              HALF_PI                           = ( float ) ( Math.PI / 2.0 );
+    private static final float              ANGLE_ROTATION_UNIT               = ( float ) ( Math.PI / 32 );
+    private static final short              OV_BORDER                         = 10;
+    final static Cursor                     CUT_CURSOR                        = Cursor
+                                                                                      .getPredefinedCursor( Cursor.CROSSHAIR_CURSOR );
+    final static Cursor                     MOVE_CURSOR                       = Cursor
+                                                                                      .getPredefinedCursor( Cursor.MOVE_CURSOR );
+    final static Cursor                     ARROW_CURSOR                      = Cursor
+                                                                                      .getPredefinedCursor( Cursor.DEFAULT_CURSOR );
+    final static Cursor                     HAND_CURSOR                       = Cursor
+                                                                                      .getPredefinedCursor( Cursor.HAND_CURSOR );
+    final static Cursor                     WAIT_CURSOR                       = Cursor
+                                                                                      .getPredefinedCursor( Cursor.WAIT_CURSOR );
+    private final static long               serialVersionUID                  = -978349745916505029L;
+    private final static int                EURO_D                            = 10;
+    private final static String             NODE_POPMENU_NODE_CLIENT_PROPERTY = "node";
+    private final static int                MIN_ROOT_LENGTH                   = 3;
+    private final static int                BOX_SIZE                          = 4;
+    private final static int                HALF_BOX_SIZE                     = TreePanel.BOX_SIZE / 2;
+    private final static int                MAX_SUBTREES                      = 100;
+    private final static int                MAX_NODE_FRAMES                   = 10;
+    private final static int                MOVE                              = 20;
+    private final static NumberFormat       FORMATTER_CONFIDENCE;
+    private final static NumberFormat       FORMATTER_BRANCH_LENGTH;
+    private final static int                WIGGLE                            = 2;
+    private final static int                HALF_BOX_SIZE_PLUS_WIGGLE         = HALF_BOX_SIZE + WIGGLE;
+    private final static int                LIMIT_FOR_HQ_RENDERING            = 1000;
+    // TODO "rendering_hints" was static before. Need to make sure everything is OK with it not
+    // being static anymore (02/20/2009).
+    private final RenderingHints            _rendering_hints                  = new RenderingHints( RenderingHints.KEY_RENDERING,
+                                                                                                    RenderingHints.VALUE_RENDER_DEFAULT );
+    private File                            _treefile                         = null;
+    private Configuration                   _configuration                    = null;
+    private final NodeFrame[]               _node_frames                      = new NodeFrame[ TreePanel.MAX_NODE_FRAMES ];
+    private int                             _node_frame_index                 = 0;
+    private Phylogeny                       _phylogeny                        = null;
+    private final Phylogeny[]               _sub_phylogenies                  = new Phylogeny[ TreePanel.MAX_SUBTREES ];
+    private final PhylogenyNode[]           _sub_phylogenies_temp_roots       = new PhylogenyNode[ TreePanel.MAX_SUBTREES ];
+    private int                             _subtree_index                    = 0;
+    private MainPanel                       _main_panel                       = null;
+    private Set<Integer>                    _found_nodes                      = null;
+    private PhylogenyNode                   _highlight_node                   = null;
+    private JPopupMenu                      _node_popup_menu                  = null;
+    private JMenuItem                       _node_popup_menu_items[]          = null;
+    private int                             _longest_ext_node_info            = 0;
+    private float                           _x_correction_factor              = 0.0f;
+    private float                           _ov_x_correction_factor           = 0.0f;
+    private float                           _x_distance                       = 0.0f;
+    private float                           _y_distance                       = 0.0f;
+    private PHYLOGENY_GRAPHICS_TYPE         _graphics_type                    = PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR;
+    private double                          _domain_structure_width           = Constants.DOMAIN_STRUCTURE_DEFAULT_WIDTH;
+    private int                             _domain_structure_e_value_thr_exp = Constants.DOMAIN_STRUCTURE_E_VALUE_THR_DEFAULT_EXP;
+    private float                           _last_drag_point_x                = 0;
+    private float                           _last_drag_point_y                = 0;
+    private ControlPanel                    _control_panel                    = null;
+    private int                             _external_node_index              = 0;
+    private final Polygon                   _polygon                          = new Polygon();
+    private final StringBuilder             _sb                               = new StringBuilder();
+    private JColorChooser                   _color_chooser                    = null;
+    private double                          _scale_distance                   = 0.0;
+    private String                          _scale_label                      = null;
+    private final CubicCurve2D              _cubic_curve                      = new CubicCurve2D.Float();
+    private final QuadCurve2D               _quad_curve                       = new QuadCurve2D.Float();
+    private final Line2D                    _line                             = new Line2D.Float();
+    private final Ellipse2D                 _ellipse                          = new Ellipse2D.Float();
+    private final Rectangle2D               _rectangle                        = new Rectangle2D.Float();
+    private Options                         _options                          = null;
+    private float                           _ov_max_width                     = 0;
+    private float                           _ov_max_height                    = 0;
+    private int                             _ov_x_position                    = 0;
+    private int                             _ov_y_position                    = 0;
+    private int                             _ov_y_start                       = 0;
+    private float                           _ov_y_distance                    = 0;
+    private float                           _ov_x_distance                    = 0;
+    private boolean                         _ov_on                            = false;
+    private double                          _urt_starting_angle               = ( float ) ( Math.PI / 2 );
+    private float                           _urt_factor                       = 1;
+    private float                           _urt_factor_ov                    = 1;
+    private final boolean                   _phy_has_branch_lengths;
+    private final Rectangle2D               _ov_rectangle                     = new Rectangle2D.Float();
+    private boolean                         _in_ov_rect                       = false;
+    private boolean                         _in_ov                            = false;
+    private final Rectangle                 _ov_virtual_rectangle             = new Rectangle();
+    final private static double             _180_OVER_PI                      = 180.0 / Math.PI;
+    private static final float              ROUNDED_D                         = 8;
+    private int                             _circ_max_depth;
+    private int                             _circ_num_ext_nodes;
+    private PhylogenyNode                   _root;
+    final private Arc2D                     _arc                              = new Arc2D.Double();
+    final private HashMap<Integer, Double>  _urt_nodeid_angle_map             = new HashMap<Integer, Double>();
+    final private HashMap<Integer, Integer> _urt_nodeid_index_map             = new HashMap<Integer, Integer>();
+    HashMap<Integer, Short>                 _nodeid_dist_to_leaf              = new HashMap<Integer, Short>();
+    private AffineTransform                 _at;
+    private double                          _max_distance_to_root             = -1;
+    private int                             _dynamic_hiding_factor            = 0;
+    private boolean                         _edited                           = false;
+    private Popup                           _node_desc_popup;
+    private JTextArea                       _rollover_popup;
+    //private final short                     _skip_counter                     = 0;
+    private final StringBuffer              _popup_buffer                     = new StringBuffer();
+    final private static Font               POPUP_FONT                        = new Font( Configuration
+                                                                                                  .getDefaultFontFamilyName(),
+                                                                                          Font.PLAIN,
+                                                                                          12 );
+    private static final boolean            DRAW_MEAN_COUNTS                  = true;                                                     //TODO remove me later
+    private Sequence                        _query_sequence                   = null;
+    private final FontRenderContext         _frc                              = new FontRenderContext( null,
+                                                                                                       false,
+                                                                                                       false );
+    // expression values menu:
+    private DescriptiveStatistics           _statistics_for_vector_data;
+    //  private Image                           offscreenImage;
+    //  private Graphics                        offscreenGraphics;
+    //  private Dimension                       offscreenDimension;
+    static {
+        final DecimalFormatSymbols dfs = new DecimalFormatSymbols();
+        dfs.setDecimalSeparator( '.' );
+        FORMATTER_CONFIDENCE = new DecimalFormat( "#.###", dfs );
+        FORMATTER_BRANCH_LENGTH = new DecimalFormat( "#.###", dfs );
+    }
+
+    TreePanel( final Phylogeny t, final Configuration configuration, final MainPanel tjp ) {
+        requestFocusInWindow();
+        addKeyListener( new KeyAdapter() {
+
+            @Override
+            public void keyPressed( final KeyEvent key_event ) {
+                keyPressedCalls( key_event );
+                requestFocusInWindow();
+            }
+        } );
+        addFocusListener( new FocusAdapter() {
+
+            @Override
+            public void focusGained( final FocusEvent e ) {
+                requestFocusInWindow();
+            }
+        } );
+        if ( ( t == null ) || t.isEmpty() ) {
+            throw new IllegalArgumentException( "attempt to draw phylogeny which is null or empty" );
+        }
+        _graphics_type = tjp.getOptions().getPhylogenyGraphicsType();
+        _main_panel = tjp;
+        _configuration = configuration;
+        _phylogeny = t;
+        _phy_has_branch_lengths = ForesterUtil.isHasAtLeastOneBranchLengthLargerThanZero( _phylogeny );
+        init();
+        // if ( !_phylogeny.isEmpty() ) {
+        _phylogeny.recalculateNumberOfExternalDescendants( true );
+        checkForVectorProperties( _phylogeny );
+        // }
+        setBackground( getTreeColorSet().getBackgroundColor() );
+        final MouseListener mouse_listener = new MouseListener( this );
+        addMouseListener( mouse_listener );
+        addMouseMotionListener( mouse_listener );
+        addMouseWheelListener( this );
+        calculateScaleDistance();
+        FORMATTER_CONFIDENCE.setMaximumFractionDigits( configuration.getNumberOfDigitsAfterCommaForConfidenceValues() );
+        FORMATTER_BRANCH_LENGTH.setMaximumFractionDigits( configuration
+                .getNumberOfDigitsAfterCommaForBranchLengthValues() );
+    }
+
+    public void checkForVectorProperties( final Phylogeny phy ) {
+        final DescriptiveStatistics stats = new BasicDescriptiveStatistics();
+        for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
+            final PhylogenyNode node = iter.next();
+            if ( node.getNodeData().getProperties() != null ) {
+                final PropertiesMap pm = node.getNodeData().getProperties();
+                final double[] vector = new double[ pm.getProperties().size() ];
+                int counter = 0;
+                for( final String ref : pm.getProperties().keySet() ) {
+                    if ( ref.startsWith( PhyloXmlUtil.VECTOR_PROPERTY_REF ) ) {
+                        final Property p = pm.getProperty( ref );
+                        final String value_str = p.getValue();
+                        final String index_str = ref
+                                .substring( PhyloXmlUtil.VECTOR_PROPERTY_REF.length(), ref.length() );
+                        double d = -100;
+                        try {
+                            d = Double.parseDouble( value_str );
+                        }
+                        catch ( final NumberFormatException e ) {
+                            JOptionPane.showMessageDialog( this, "Could not parse \"" + value_str
+                                    + "\" into a decimal value", "Problem with Vector Data", JOptionPane.ERROR_MESSAGE );
+                            return;
+                        }
+                        int i = -1;
+                        try {
+                            i = Integer.parseInt( index_str );
+                        }
+                        catch ( final NumberFormatException e ) {
+                            JOptionPane.showMessageDialog( this,
+                                                           "Could not parse \"" + index_str
+                                                                   + "\" into index for vector data",
+                                                           "Problem with Vector Data",
+                                                           JOptionPane.ERROR_MESSAGE );
+                            return;
+                        }
+                        if ( i < 0 ) {
+                            JOptionPane.showMessageDialog( this,
+                                                           "Attempt to use negative index for vector data",
+                                                           "Problem with Vector Data",
+                                                           JOptionPane.ERROR_MESSAGE );
+                            return;
+                        }
+                        vector[ i ] = d;
+                        ++counter;
+                        stats.addValue( d );
+                    }
+                }
+                final List<Double> vector_l = new ArrayList<Double>( counter );
+                for( int i = 0; i < counter; ++i ) {
+                    vector_l.add( vector[ i ] );
+                }
+                node.getNodeData().setVector( vector_l );
+            }
+        }
+        if ( stats.getN() > 0 ) {
+            _statistics_for_vector_data = stats;
+        }
+    }
+
+    final public void actionPerformed( final ActionEvent e ) {
+        int index;
+        boolean done = false;
+        final JMenuItem node_popup_menu_item = ( JMenuItem ) e.getSource();
+        for( index = 0; ( index < _node_popup_menu_items.length ) && !done; index++ ) {
+            // NOTE: index corresponds to the indices of click-to options
+            // in the control panel.
+            if ( node_popup_menu_item == _node_popup_menu_items[ index ] ) {
+                // Set this as the new default click-to action
+                _main_panel.getControlPanel().setClickToAction( index );
+                final PhylogenyNode node = ( PhylogenyNode ) _node_popup_menu
+                        .getClientProperty( NODE_POPMENU_NODE_CLIENT_PROPERTY );
+                handleClickToAction( _control_panel.getActionWhenNodeClicked(), node );
+                done = true;
+            }
+        }
+        repaint();
+        requestFocusInWindow();
+    }
+
+    final private void addEmptyNode( final PhylogenyNode node ) {
+        if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+            errorMessageNoCutCopyPasteInUnrootedDisplay();
+            return;
+        }
+        final String label = getASimpleTextRepresentationOfANode( node );
+        String msg = "";
+        if ( ForesterUtil.isEmpty( label ) ) {
+            msg = "How to add the new, empty node?";
+        }
+        else {
+            msg = "How to add the new, empty node to node" + label + "?";
+        }
+        final Object[] options = { "As sibling", "As descendant", "Cancel" };
+        final int r = JOptionPane.showOptionDialog( this,
+                                                    msg,
+                                                    "Addition of Empty New Node",
+                                                    JOptionPane.CLOSED_OPTION,
+                                                    JOptionPane.QUESTION_MESSAGE,
+                                                    null,
+                                                    options,
+                                                    options[ 2 ] );
+        boolean add_as_sibling = true;
+        if ( r == 1 ) {
+            add_as_sibling = false;
+        }
+        else if ( r != 0 ) {
+            return;
+        }
+        final Phylogeny phy = new Phylogeny();
+        phy.setRoot( new PhylogenyNode() );
+        phy.setRooted( true );
+        if ( add_as_sibling ) {
+            if ( node.isRoot() ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Cannot add sibling to root",
+                                               "Attempt to add sibling to root",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            phy.addAsSibling( node );
+        }
+        else {
+            phy.addAsChild( node );
+        }
+        _phylogeny.externalNodesHaveChanged();
+        _phylogeny.hashIDs();
+        _phylogeny.recalculateNumberOfExternalDescendants( true );
+        resetNodeIdToDistToLeafMap();
+        setEdited( true );
+        repaint();
+    }
+
+    final private void assignGraphicsForBranchWithColorForParentBranch( final PhylogenyNode node,
+                                                                        final boolean is_vertical,
+                                                                        final Graphics g,
+                                                                        final boolean to_pdf,
+                                                                        final boolean to_graphics_file ) {
+        final NodeClickAction action = _control_panel.getActionWhenNodeClicked();
+        if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
+            g.setColor( Color.BLACK );
+        }
+        else if ( ( ( action == NodeClickAction.COPY_SUBTREE ) || ( action == NodeClickAction.CUT_SUBTREE )
+                || ( action == NodeClickAction.DELETE_NODE_OR_SUBTREE ) || ( action == NodeClickAction.PASTE_SUBTREE ) || ( action == NodeClickAction.ADD_NEW_NODE ) )
+                && ( getCutOrCopiedTree() != null )
+                && ( getCopiedAndPastedNodes() != null )
+                && !to_pdf
+                && !to_graphics_file && getCopiedAndPastedNodes().contains( node.getId() ) ) {
+            g.setColor( getTreeColorSet().getFoundColor() );
+        }
+        else if ( getControlPanel().isColorBranches() && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
+            g.setColor( PhylogenyMethods.getBranchColorValue( node ) );
+        }
+        else if ( to_pdf ) {
+            g.setColor( getTreeColorSet().getBranchColorForPdf() );
+        }
+        else {
+            g.setColor( getTreeColorSet().getBranchColor() );
+        }
+    }
+
+    final void assignGraphicsForNodeBoxWithColorForParentBranch( final PhylogenyNode node, final Graphics g ) {
+        if ( getControlPanel().isColorBranches() && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
+            g.setColor( PhylogenyMethods.getBranchColorValue( node ) );
+        }
+        else {
+            g.setColor( getTreeColorSet().getBranchColor() );
+        }
+    }
+
+    final private void blast( final PhylogenyNode node ) {
+        if ( !isCanBlast( node ) ) {
+            JOptionPane.showMessageDialog( this,
+                                           "No sequence information present",
+                                           "Cannot Blast",
+                                           JOptionPane.WARNING_MESSAGE );
+            return;
+        }
+        if ( node.getNodeData().isHasSequence() ) {
+            String name = "";
+            if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getName() ) ) {
+                name = node.getNodeData().getSequence().getName();
+            }
+            else if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getSymbol() ) ) {
+                name = node.getNodeData().getSequence().getSymbol();
+            }
+            else if ( node.getNodeData().getSequence().getAccession() != null ) {
+                name = node.getNodeData().getSequence().getAccession().getValue();
+            }
+            if ( !ForesterUtil.isEmpty( name ) ) {
+                try {
+                    System.out.println( "trying: " + name );
+                    final Blast s = new Blast();
+                    s.go( name );
+                }
+                catch ( final Exception e ) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    final void calcMaxDepth() {
+        if ( _phylogeny != null ) {
+            _circ_max_depth = PhylogenyMethods.calculateMaxDepth( _phylogeny );
+        }
+    }
+
+    /**
+     * Calculate the length of the distance between the given node and its
+     * parent.
+     * 
+     * @param node
+     * @param ext_node_x
+     * @factor
+     * @return the distance value
+     */
+    final private float calculateBranchLengthToParent( final PhylogenyNode node, final float factor ) {
+        if ( getControlPanel().isDrawPhylogram() ) {
+            if ( node.getDistanceToParent() < 0.0 ) {
+                return 0.0f;
+            }
+            return ( float ) ( getXcorrectionFactor() * node.getDistanceToParent() );
+        }
+        else {
+            if ( ( factor == 0 ) || isNonLinedUpCladogram() ) {
+                return getXdistance();
+            }
+            return getXdistance() * factor;
+        }
+    }
+
+    final private Color calculateColorForAnnotation( final PhylogenyData ann ) {
+        Color c = getTreeColorSet().getAnnotationColor();
+        if ( getControlPanel().isColorAccordingToAnnotation() && ( getControlPanel().getAnnotationColors() != null ) ) {
+            c = getControlPanel().getAnnotationColors().get( ann.asSimpleText().toString() );
+            if ( c == null ) {
+                c = getTreeColorSet().getAnnotationColor();
+            }
+        }
+        return c;
+    }
+
+    final void calculateLongestExtNodeInfo() {
+        if ( ( _phylogeny == null ) || _phylogeny.isEmpty() ) {
+            return;
+        }
+        int longest = 20;
+        for( final PhylogenyNode node : _phylogeny.getExternalNodes() ) {
+            int sum = 0;
+            if ( node.isCollapse() ) {
+                continue;
+            }
+            if ( getControlPanel().isShowNodeNames() ) {
+                sum += getTreeFontSet()._fm_large.stringWidth( node.getName() + " " );
+            }
+            if ( node.getNodeData().isHasSequence() ) {
+                if ( getControlPanel().isShowSequenceAcc()
+                        && ( node.getNodeData().getSequence().getAccession() != null ) ) {
+                    sum += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getAccession()
+                            .getValue()
+                            + " " );
+                }
+                if ( getControlPanel().isShowGeneNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
+                    sum += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getName() + " " );
+                }
+                if ( getControlPanel().isShowGeneSymbols()
+                        && ( node.getNodeData().getSequence().getSymbol().length() > 0 ) ) {
+                    sum += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getSymbol() + " " );
+                }
+                if ( getControlPanel().isShowAnnotation()
+                        && ( node.getNodeData().getSequence().getAnnotations() != null )
+                        && !node.getNodeData().getSequence().getAnnotations().isEmpty() ) {
+                    sum += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getAnnotation( 0 )
+                            .asSimpleText()
+                            + " " );
+                }
+            }
+            if ( node.getNodeData().isHasTaxonomy() ) {
+                final Taxonomy tax = node.getNodeData().getTaxonomy();
+                if ( getControlPanel().isShowTaxonomyCode() && !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
+                    sum += getTreeFontSet()._fm_large_italic.stringWidth( tax.getTaxonomyCode() + " " );
+                }
+                if ( getControlPanel().isShowTaxonomyScientificNames()
+                        && !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
+                    sum += getTreeFontSet()._fm_large_italic.stringWidth( tax.getScientificName() + " " );
+                }
+                if ( getControlPanel().isShowTaxonomyCommonNames() && !ForesterUtil.isEmpty( tax.getCommonName() ) ) {
+                    sum += getTreeFontSet()._fm_large_italic.stringWidth( tax.getCommonName() + " ()" );
+                }
+            }
+            if ( getControlPanel().isShowBinaryCharacters() && node.getNodeData().isHasBinaryCharacters() ) {
+                sum += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getBinaryCharacters()
+                        .getGainedCharactersAsStringBuffer().toString() );
+            }
+            if ( getControlPanel().isShowDomainArchitectures() && node.getNodeData().isHasSequence()
+                    && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) {
+                sum += ( ( RenderableDomainArchitecture ) node.getNodeData().getSequence().getDomainArchitecture() )
+                        .getRenderingSize().getWidth();
+            }
+            if ( sum >= Constants.EXT_NODE_INFO_LENGTH_MAX ) {
+                setLongestExtNodeInfo( Constants.EXT_NODE_INFO_LENGTH_MAX );
+                return;
+            }
+            if ( sum > longest ) {
+                longest = sum;
+            }
+        }
+        if ( longest >= Constants.EXT_NODE_INFO_LENGTH_MAX ) {
+            setLongestExtNodeInfo( Constants.EXT_NODE_INFO_LENGTH_MAX );
+        }
+        else {
+            setLongestExtNodeInfo( longest );
+        }
+    }
+
+    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 void calculateScaleDistance() {
+        if ( ( _phylogeny == null ) || _phylogeny.isEmpty() ) {
+            return;
+        }
+        final double height = getMaxDistanceToRoot();
+        if ( height > 0 ) {
+            if ( ( height <= 0.5 ) ) {
+                setScaleDistance( 0.01 );
+            }
+            else if ( height <= 5.0 ) {
+                setScaleDistance( 0.1 );
+            }
+            else if ( height <= 50.0 ) {
+                setScaleDistance( 1 );
+            }
+            else if ( height <= 500.0 ) {
+                setScaleDistance( 10 );
+            }
+            else {
+                setScaleDistance( 100 );
+            }
+        }
+        else {
+            setScaleDistance( 0.0 );
+        }
+        String scale_label = String.valueOf( getScaleDistance() );
+        if ( !ForesterUtil.isEmpty( _phylogeny.getDistanceUnit() ) ) {
+            scale_label += " [" + _phylogeny.getDistanceUnit() + "]";
+        }
+        setScaleLabel( scale_label );
+    }
+
+    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 ( ForesterUtil.isEmpty( species ) ) {
+            return getTreeColorSet().getTaxonomyColor();
+        }
+        // Look in species hash
+        Color c = getControlPanel().getSpeciesColors().get( species );
+        if ( c == null ) {
+            c = Util.calculateColorFromString( species );
+            getControlPanel().getSpeciesColors().put( species, c );
+        }
+        return c;
+    }
+
+    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 );
+    }
+
+    /**
+     * Collapse the tree from the given node
+     * 
+     * @param node
+     *            a PhylogenyNode
+     */
+    final void collapse( final PhylogenyNode node ) {
+        if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Cannot collapse in unrooted display type",
+                                           "Attempt to collapse in unrooted display",
+                                           JOptionPane.WARNING_MESSAGE );
+            return;
+        }
+        if ( !node.isExternal() && !node.isRoot() ) {
+            final boolean collapse = !node.isCollapse();
+            Util.collapseSubtree( node, collapse );
+            _phylogeny.recalculateNumberOfExternalDescendants( true );
+            resetNodeIdToDistToLeafMap();
+            calculateLongestExtNodeInfo();
+            resetPreferredSize();
+            updateOvSizes();
+            _main_panel.adjustJScrollPane();
+            repaint();
+        }
+    }
+
+    final void collapseSpeciesSpecificSubtrees() {
+        if ( ( _phylogeny == null ) || ( _phylogeny.getNumberOfExternalNodes() < 2 ) ) {
+            return;
+        }
+        setWaitCursor();
+        Util.collapseSpeciesSpecificSubtrees( _phylogeny );
+        _phylogeny.recalculateNumberOfExternalDescendants( true );
+        resetNodeIdToDistToLeafMap();
+        calculateLongestExtNodeInfo();
+        resetPreferredSize();
+        _main_panel.adjustJScrollPane();
+        setArrowCursor();
+        repaint();
+    }
+
+    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 void confColor() {
+        if ( ( _phylogeny == null ) || ( _phylogeny.getNumberOfExternalNodes() < 2 ) ) {
+            return;
+        }
+        setWaitCursor();
+        Util.colorPhylogenyAccordingToConfidenceValues( _phylogeny, this );
+        _control_panel.setColorBranches( true );
+        if ( _control_panel.getColorBranchesCb() != null ) {
+            _control_panel.getColorBranchesCb().setSelected( true );
+        }
+        setArrowCursor();
+        repaint();
+    }
+
+    final private void copySubtree( final PhylogenyNode node ) {
+        if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+            errorMessageNoCutCopyPasteInUnrootedDisplay();
+            return;
+        }
+        setCutOrCopiedTree( _phylogeny.copy( node ) );
+        final List<PhylogenyNode> nodes = PhylogenyMethods.getAllDescendants( node );
+        final Set<Integer> node_ids = new HashSet<Integer>( nodes.size() );
+        for( final PhylogenyNode n : nodes ) {
+            node_ids.add( n.getId() );
+        }
+        node_ids.add( node.getId() );
+        setCopiedAndPastedNodes( node_ids );
+        repaint();
+    }
+
+    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 = getASimpleTextRepresentationOfANode( node );
+        final int r = JOptionPane.showConfirmDialog( null,
+                                                     "Cut subtree" + label + "?",
+                                                     "Confirm Cutting of Subtree",
+                                                     JOptionPane.YES_NO_OPTION );
+        if ( r != JOptionPane.OK_OPTION ) {
+            return;
+        }
+        setCopiedAndPastedNodes( null );
+        setCutOrCopiedTree( _phylogeny.copy( node ) );
+        _phylogeny.deleteSubtree( node, true );
+        _phylogeny.hashIDs();
+        _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 void decreaseDomainStructureEvalueThreshold() {
+        if ( _domain_structure_e_value_thr_exp > -20 ) {
+            _domain_structure_e_value_thr_exp -= 1;
+        }
+    }
+
+    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() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Cannot delete entire tree",
+                                           "Attempt to delete entire tree",
+                                           JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        final String label = getASimpleTextRepresentationOfANode( 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 ] );
+        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.hashIDs();
+        _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 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 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 );
+    }
+
+    /**
+     * Find the node, if any, at the given location
+     * 
+     * @param x
+     * @param y
+     * @return pointer to the node at x,y, null if not found
+     */
+    final PhylogenyNode findNode( final int x, final int y ) {
+        if ( ( _phylogeny == null ) || _phylogeny.isEmpty() ) {
+            return null;
+        }
+        for( final PhylogenyNodeIterator iter = _phylogeny.iteratorPostorder(); iter.hasNext(); ) {
+            final PhylogenyNode node = iter.next();
+            if ( ( _phylogeny.isRooted() || !node.isRoot() || ( node.getNumberOfDescendants() > 2 ) )
+                    && ( ( node.getXcoord() - HALF_BOX_SIZE_PLUS_WIGGLE ) <= x )
+                    && ( ( node.getXcoord() + HALF_BOX_SIZE_PLUS_WIGGLE ) >= x )
+                    && ( ( node.getYcoord() - HALF_BOX_SIZE_PLUS_WIGGLE ) <= y )
+                    && ( ( node.getYcoord() + HALF_BOX_SIZE_PLUS_WIGGLE ) >= y ) ) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    final private String getASimpleTextRepresentationOfANode( 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 Configuration getConfiguration() {
+        return _configuration;
+    }
+
+    final ControlPanel getControlPanel() {
+        return _control_panel;
+    }
+
+    final private Set<Integer> getCopiedAndPastedNodes() {
+        return getMainPanel().getCopiedAndPastedNodes();
+    }
+
+    final private Phylogeny getCutOrCopiedTree() {
+        return getMainPanel().getCutOrCopiedTree();
+    }
+
+    final int getDomainStructureEvalueThreshold() {
+        return _domain_structure_e_value_thr_exp;
+    }
+
+    final Set<Integer> getFoundNodes() {
+        return _found_nodes;
+    }
+
+    final private float getLastDragPointX() {
+        return _last_drag_point_x;
+    }
+
+    final private float getLastDragPointY() {
+        return _last_drag_point_y;
+    }
+
+    final int getLongestExtNodeInfo() {
+        return _longest_ext_node_info;
+    }
+
+    final public MainPanel getMainPanel() {
+        return _main_panel;
+    }
+
+    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 Options getOptions() {
+        if ( _options == null ) {
+            _options = getControlPanel().getOptions();
+        }
+        return _options;
+    }
+
+    final private float getOvMaxHeight() {
+        return _ov_max_height;
+    }
+
+    final private float getOvMaxWidth() {
+        return _ov_max_width;
+    }
+
+    final Rectangle2D getOvRectangle() {
+        return _ov_rectangle;
+    }
+
+    final Rectangle getOvVirtualRectangle() {
+        return _ov_virtual_rectangle;
+    }
+
+    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;
+    }
+
+    /**
+     * Get a pointer to the phylogeny 
+     * 
+     * @return a pointer to the phylogeny
+     */
+    final Phylogeny getPhylogeny() {
+        return _phylogeny;
+    }
+
+    final PHYLOGENY_GRAPHICS_TYPE getPhylogenyGraphicsType() {
+        return _graphics_type;
+    }
+
+    final private double getScaleDistance() {
+        return _scale_distance;
+    }
+
+    final private String getScaleLabel() {
+        return _scale_label;
+    }
+
+    final double getStartingAngle() {
+        return _urt_starting_angle;
+    }
+
+    /**
+     * Find a color for this species name.
+     * 
+     * @param species
+     * @return the species color
+     */
+    final Color getTaxonomyBasedColor( final PhylogenyNode node ) {
+        if ( node.getNodeData().isHasTaxonomy() ) {
+            return calculateTaxonomyBasedColor( node.getNodeData().getTaxonomy() );
+        }
+        // return non-colorized color
+        return getTreeColorSet().getTaxonomyColor();
+    }
+
+    /**
+     * @return pointer to colorset for tree drawing
+     */
+    final TreeColorSet getTreeColorSet() {
+        return getMainPanel().getTreeColorSet();
+    }
+
+    final File getTreeFile() {
+        return _treefile;
+    }
+
+    final private TreeFontSet getTreeFontSet() {
+        return getMainPanel().getTreeFontSet();
+    }
+
+    final private float getUrtFactor() {
+        return _urt_factor;
+    }
+
+    final private float getUrtFactorOv() {
+        return _urt_factor_ov;
+    }
+
+    final float getXcorrectionFactor() {
+        return _x_correction_factor;
+    }
+
+    final float getXdistance() {
+        return _x_distance;
+    }
+
+    final float getYdistance() {
+        return _y_distance;
+    }
+
+    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;
+            default:
+                throw new IllegalArgumentException( "unknown action: " + action );
+        }
+    }
+
+    final void increaseDomainStructureEvalueThreshold() {
+        if ( _domain_structure_e_value_thr_exp < 3 ) {
+            _domain_structure_e_value_thr_exp += 1;
+        }
+    }
+
+    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 void inferCommonPartOfScientificNames() {
+        if ( ( _phylogeny == null ) || ( _phylogeny.getNumberOfExternalNodes() < 2 ) ) {
+            return;
+        }
+        setWaitCursor();
+        Util.inferCommonPartOfScientificNames( _phylogeny );
+        setArrowCursor();
+        repaint();
+    }
+
+    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();
+    }
+
+    final private void initializeOvSettings() {
+        setOvMaxHeight( getConfiguration().getOvMaxHeight() );
+        setOvMaxWidth( getConfiguration().getOvMaxWidth() );
+    }
+
+    final void initNodeData() {
+        if ( ( _phylogeny == null ) || _phylogeny.isEmpty() ) {
+            return;
+        }
+        double max_original_domain_structure_width = 0.0;
+        for( final PhylogenyNode node : _phylogeny.getExternalNodes() ) {
+            if ( node.getNodeData().isHasSequence()
+                    && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) {
+                RenderableDomainArchitecture rds = null;
+                if ( !( node.getNodeData().getSequence().getDomainArchitecture() instanceof RenderableDomainArchitecture ) ) {
+                    rds = new RenderableDomainArchitecture( node.getNodeData().getSequence().getDomainArchitecture(),
+                                                            getConfiguration() );
+                    node.getNodeData().getSequence().setDomainArchitecture( rds );
+                }
+                else {
+                    rds = ( RenderableDomainArchitecture ) node.getNodeData().getSequence().getDomainArchitecture();
+                }
+                if ( getControlPanel().isShowDomainArchitectures() ) {
+                    final double dsw = rds.getOriginalSize().getWidth();
+                    if ( dsw > max_original_domain_structure_width ) {
+                        max_original_domain_structure_width = dsw;
+                    }
+                }
+            }
+        }
+        if ( getControlPanel().isShowDomainArchitectures() ) {
+            final double ds_factor_width = _domain_structure_width / max_original_domain_structure_width;
+            for( final PhylogenyNode node : _phylogeny.getExternalNodes() ) {
+                if ( node.getNodeData().isHasSequence()
+                        && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) {
+                    final RenderableDomainArchitecture rds = ( RenderableDomainArchitecture ) node.getNodeData()
+                            .getSequence().getDomainArchitecture();
+                    rds.setRenderingFactorWidth( ds_factor_width );
+                    rds.setParameter( _domain_structure_e_value_thr_exp );
+                }
+            }
+        }
+    }
+
+    final boolean inOv( final MouseEvent e ) {
+        return ( ( e.getX() > getVisibleRect().x + getOvXPosition() + 1 )
+                && ( e.getX() < getVisibleRect().x + getOvXPosition() + getOvMaxWidth() - 1 )
+                && ( e.getY() > getVisibleRect().y + getOvYPosition() + 1 ) && ( e.getY() < getVisibleRect().y
+                + getOvYPosition() + getOvMaxHeight() - 1 ) );
+    }
+
+    final boolean inOvRectangle( final MouseEvent e ) {
+        return ( ( e.getX() >= getOvRectangle().getX() - 1 )
+                && ( e.getX() <= getOvRectangle().getX() + getOvRectangle().getWidth() + 1 )
+                && ( e.getY() >= getOvRectangle().getY() - 1 ) && ( e.getY() <= getOvRectangle().getY()
+                + getOvRectangle().getHeight() + 1 ) );
+    }
+
+    final private boolean inOvVirtualRectangle( final int x, final int y ) {
+        return ( ( x >= getOvVirtualRectangle().x - 1 )
+                && ( x <= getOvVirtualRectangle().x + getOvVirtualRectangle().width + 1 )
+                && ( y >= getOvVirtualRectangle().y - 1 ) && ( y <= getOvVirtualRectangle().y
+                + getOvVirtualRectangle().height + 1 ) );
+    }
+
+    final private boolean inOvVirtualRectangle( final MouseEvent e ) {
+        return ( inOvVirtualRectangle( e.getX(), e.getY() ) );
+    }
+
+    final boolean isApplet() {
+        return getMainPanel() instanceof MainPanelApplets;
+    }
+
+    final private boolean isCanBlast( final PhylogenyNode node ) {
+        return ( node.getNodeData().isHasSequence() && ( ( ( node.getNodeData().getSequence().getAccession() != null ) && !ForesterUtil
+                .isEmpty( node.getNodeData().getSequence().getAccession().getValue() ) )
+                || !ForesterUtil.isEmpty( node.getNodeData().getSequence().getName() ) || !ForesterUtil.isEmpty( node
+                .getNodeData().getSequence().getSymbol() ) ) );
+    }
+
+    final boolean isCanCollapse() {
+        return ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
+    }
+
+    final boolean isCanColorSubtree() {
+        return ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
+    }
+
+    final boolean isCanCopy() {
+        return ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && getOptions().isEditable() );
+    }
+
+    final boolean isCanCut( final PhylogenyNode node ) {
+        return ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && getOptions().isEditable() && !node
+                .isRoot() );
+    }
+
+    final boolean isCanDelete() {
+        return ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && getOptions().isEditable() );
+    }
+
+    final private boolean isCanOpenSeqWeb( final PhylogenyNode node ) {
+        if ( node.getNodeData().isHasSequence()
+                && ( node.getNodeData().getSequence().getAccession() != null )
+                && !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().getSource() )
+                && !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().getValue() )
+                && getConfiguration().isHasWebLink( node.getNodeData().getSequence().getAccession().getSource()
+                        .toLowerCase() ) ) {
+            return true;
+        }
+        return false;
+    }
+
+    final private boolean isCanOpenTaxWeb( final PhylogenyNode node ) {
+        if ( node.getNodeData().isHasTaxonomy()
+                && ( ( ( node.getNodeData().getTaxonomy().getIdentifier() != null )
+                        && !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getIdentifier().getProvider() )
+                        && !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getIdentifier().getValue() ) && getConfiguration()
+                        .isHasWebLink( node.getNodeData().getTaxonomy().getIdentifier().getProvider().toLowerCase() ) )
+                        || ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getScientificName() ) )
+                        || ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getTaxonomyCode() ) )
+                        || ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getCommonName() ) ) || ( ( node
+                        .getNodeData().getTaxonomy().getIdentifier() != null )
+                        && !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getIdentifier().getValue() ) && node
+                        .getNodeData().getTaxonomy().getIdentifier().getValue().startsWith( "http://" ) ) ) ) {
+            return true;
+        }
+        else {
+            return false;
+        }
+    }
+
+    final boolean isCanPaste() {
+        return ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && getOptions().isEditable()
+                && ( getCutOrCopiedTree() != null ) && !getCutOrCopiedTree().isEmpty() );
+    }
+
+    final boolean isCanReroot() {
+        return ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && ( _subtree_index < 1 ) );
+    }
+
+    final boolean isCanSubtree( final PhylogenyNode node ) {
+        return ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && !node.isExternal() && ( !node
+                .isRoot() || ( _subtree_index > 0 ) ) );
+    }
+
+    final boolean isEdited() {
+        return _edited;
+    }
+
+    final private boolean isInFoundNodes( final PhylogenyNode node ) {
+        return ( ( getFoundNodes() != null ) && getFoundNodes().contains( node.getId() ) );
+    }
+
+    final private boolean isInOv() {
+        return _in_ov;
+    }
+
+    final boolean isInOvRect() {
+        return _in_ov_rect;
+    }
+
+    final private boolean isNodeDataInvisible( final PhylogenyNode node ) {
+        int y_dist = 40;
+        if ( getControlPanel().isShowTaxonomyImages() ) {
+            y_dist = 40 + ( int ) getYdistance();
+        }
+        return ( ( node.getYcoord() < getVisibleRect().getMinY() - y_dist )
+                || ( node.getYcoord() > getVisibleRect().getMaxY() + y_dist ) || ( ( node.getParent() != null ) && ( node
+                .getParent().getXcoord() > getVisibleRect().getMaxX() ) ) );
+    }
+
+    final private boolean isNodeDataInvisibleUnrootedCirc( final PhylogenyNode node ) {
+        return ( ( node.getYcoord() < getVisibleRect().getMinY() - 20 )
+                || ( node.getYcoord() > getVisibleRect().getMaxY() + 20 )
+                || ( node.getXcoord() < getVisibleRect().getMinX() - 20 ) || ( node.getXcoord() > getVisibleRect()
+                .getMaxX() + 20 ) );
+    }
+
+    final private boolean isNonLinedUpCladogram() {
+        return getOptions().getCladogramType() == CLADOGRAM_TYPE.NON_LINED_UP;
+    }
+
+    final boolean isOvOn() {
+        return _ov_on;
+    }
+
+    final boolean isPhyHasBranchLengths() {
+        return _phy_has_branch_lengths;
+    }
+
+    final private boolean isUniformBranchLengthsForCladogram() {
+        return getOptions().getCladogramType() == CLADOGRAM_TYPE.TOTAL_NODE_SUM_DEP;
+    }
+
+    final private void keyPressedCalls( final KeyEvent e ) {
+        if ( isOvOn() && ( getMousePosition() != null ) && ( getMousePosition().getLocation() != null ) ) {
+            if ( inOvVirtualRectangle( getMousePosition().x, getMousePosition().y ) ) {
+                if ( !isInOvRect() ) {
+                    setInOvRect( true );
+                }
+            }
+            else if ( isInOvRect() ) {
+                setInOvRect( false );
+            }
+        }
+        if ( e.getModifiersEx() == InputEvent.CTRL_DOWN_MASK ) {
+            if ( ( e.getKeyCode() == KeyEvent.VK_DELETE ) || ( e.getKeyCode() == KeyEvent.VK_HOME )
+                    || ( e.getKeyCode() == KeyEvent.VK_F ) ) {
+                getMainPanel().getTreeFontSet().mediumFonts();
+                getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( true );
+            }
+            else if ( ( e.getKeyCode() == KeyEvent.VK_SUBTRACT ) || ( e.getKeyCode() == KeyEvent.VK_MINUS ) ) {
+                getMainPanel().getTreeFontSet().decreaseFontSize();
+                getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( true );
+            }
+            else if ( plusPressed( e.getKeyCode() ) ) {
+                getMainPanel().getTreeFontSet().increaseFontSize();
+                getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( true );
+            }
+        }
+        else {
+            if ( ( e.getKeyCode() == KeyEvent.VK_DELETE ) || ( e.getKeyCode() == KeyEvent.VK_HOME )
+                    || ( e.getKeyCode() == KeyEvent.VK_F ) ) {
+                getControlPanel().showWhole();
+            }
+            else if ( ( e.getKeyCode() == KeyEvent.VK_UP ) || ( e.getKeyCode() == KeyEvent.VK_DOWN )
+                    || ( e.getKeyCode() == KeyEvent.VK_LEFT ) || ( e.getKeyCode() == KeyEvent.VK_RIGHT ) ) {
+                if ( e.getModifiersEx() == InputEvent.SHIFT_DOWN_MASK ) {
+                    if ( e.getKeyCode() == KeyEvent.VK_UP ) {
+                        getMainPanel().getControlPanel().zoomInY( Constants.WHEEL_ZOOM_IN_FACTOR );
+                        getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
+                    }
+                    else if ( e.getKeyCode() == KeyEvent.VK_DOWN ) {
+                        getMainPanel().getControlPanel().zoomOutY( Constants.WHEEL_ZOOM_OUT_FACTOR );
+                        getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
+                    }
+                    else if ( e.getKeyCode() == KeyEvent.VK_LEFT ) {
+                        getMainPanel().getControlPanel().zoomOutX( Constants.WHEEL_ZOOM_OUT_FACTOR,
+                                                                   Constants.WHEEL_ZOOM_OUT_X_CORRECTION_FACTOR );
+                        getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
+                    }
+                    else if ( e.getKeyCode() == KeyEvent.VK_RIGHT ) {
+                        getMainPanel().getControlPanel().zoomInX( Constants.WHEEL_ZOOM_IN_FACTOR,
+                                                                  Constants.WHEEL_ZOOM_IN_FACTOR );
+                        getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
+                    }
+                }
+                else {
+                    final int d = 80;
+                    int dx = 0;
+                    int dy = -d;
+                    if ( e.getKeyCode() == KeyEvent.VK_DOWN ) {
+                        dy = d;
+                    }
+                    else if ( e.getKeyCode() == KeyEvent.VK_LEFT ) {
+                        dx = -d;
+                        dy = 0;
+                    }
+                    else if ( e.getKeyCode() == KeyEvent.VK_RIGHT ) {
+                        dx = d;
+                        dy = 0;
+                    }
+                    final Point scroll_position = getMainPanel().getCurrentScrollPane().getViewport().getViewPosition();
+                    scroll_position.x = scroll_position.x + dx;
+                    scroll_position.y = scroll_position.y + dy;
+                    if ( scroll_position.x <= 0 ) {
+                        scroll_position.x = 0;
+                    }
+                    else {
+                        final int max_x = getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getMaximum()
+                                - getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getVisibleAmount();
+                        if ( scroll_position.x >= max_x ) {
+                            scroll_position.x = max_x;
+                        }
+                    }
+                    if ( scroll_position.y <= 0 ) {
+                        scroll_position.y = 0;
+                    }
+                    else {
+                        final int max_y = getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getMaximum()
+                                - getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getVisibleAmount();
+                        if ( scroll_position.y >= max_y ) {
+                            scroll_position.y = max_y;
+                        }
+                    }
+                    repaint();
+                    getMainPanel().getCurrentScrollPane().getViewport().setViewPosition( scroll_position );
+                }
+            }
+            else if ( ( e.getKeyCode() == KeyEvent.VK_SUBTRACT ) || ( e.getKeyCode() == KeyEvent.VK_MINUS ) ) {
+                getMainPanel().getControlPanel().zoomOutY( Constants.WHEEL_ZOOM_OUT_FACTOR );
+                getMainPanel().getControlPanel().zoomOutX( Constants.WHEEL_ZOOM_OUT_FACTOR,
+                                                           Constants.WHEEL_ZOOM_OUT_X_CORRECTION_FACTOR );
+                getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
+            }
+            else if ( plusPressed( e.getKeyCode() ) ) {
+                getMainPanel().getControlPanel().zoomInX( Constants.WHEEL_ZOOM_IN_FACTOR,
+                                                          Constants.WHEEL_ZOOM_IN_FACTOR );
+                getMainPanel().getControlPanel().zoomInY( Constants.WHEEL_ZOOM_IN_FACTOR );
+                getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
+            }
+            else if ( e.getKeyCode() == KeyEvent.VK_S ) {
+                if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
+                        || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
+                    setStartingAngle( ( getStartingAngle() % TWO_PI ) + ANGLE_ROTATION_UNIT );
+                    getControlPanel().displayedPhylogenyMightHaveChanged( false );
+                }
+            }
+            else if ( e.getKeyCode() == KeyEvent.VK_A ) {
+                if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
+                        || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
+                    setStartingAngle( ( getStartingAngle() % TWO_PI ) - ANGLE_ROTATION_UNIT );
+                    if ( getStartingAngle() < 0 ) {
+                        setStartingAngle( TWO_PI + getStartingAngle() );
+                    }
+                    getControlPanel().displayedPhylogenyMightHaveChanged( false );
+                }
+            }
+            else if ( e.getKeyCode() == KeyEvent.VK_D ) {
+                boolean selected = false;
+                if ( getOptions().getNodeLabelDirection() == NODE_LABEL_DIRECTION.HORIZONTAL ) {
+                    getOptions().setNodeLabelDirection( NODE_LABEL_DIRECTION.RADIAL );
+                    selected = true;
+                }
+                else {
+                    getOptions().setNodeLabelDirection( NODE_LABEL_DIRECTION.HORIZONTAL );
+                }
+                if ( getMainPanel().getMainFrame() == null ) {
+                    // Must be "E" applet version.
+                    final ArchaeopteryxE ae = ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet();
+                    if ( ae.getlabelDirectionCbmi() != null ) {
+                        ae.getlabelDirectionCbmi().setSelected( selected );
+                    }
+                }
+                else {
+                    getMainPanel().getMainFrame().getlabelDirectionCbmi().setSelected( selected );
+                }
+                repaint();
+            }
+            else if ( e.getKeyCode() == KeyEvent.VK_X ) {
+                switchDisplaygetPhylogenyGraphicsType();
+                repaint();
+            }
+            else if ( e.getKeyCode() == KeyEvent.VK_C ) {
+                cycleColors();
+                repaint();
+            }
+            else if ( getOptions().isShowOverview() && isOvOn() && ( e.getKeyCode() == KeyEvent.VK_O ) ) {
+                MainFrame.cycleOverview( getOptions(), this );
+                repaint();
+            }
+            else if ( getOptions().isShowOverview() && isOvOn() && ( e.getKeyCode() == KeyEvent.VK_I ) ) {
+                increaseOvSize();
+            }
+            else if ( getOptions().isShowOverview() && isOvOn() && ( e.getKeyCode() == KeyEvent.VK_U ) ) {
+                decreaseOvSize();
+            }
+            e.consume();
+        }
+    }
+
+    final private void makePopupMenus( final PhylogenyNode node ) {
+        _node_popup_menu = new JPopupMenu();
+        final List<String> clickto_names = _main_panel.getControlPanel().getSingleClickToNames();
+        _node_popup_menu_items = new JMenuItem[ clickto_names.size() ];
+        for( int i = 0; i < clickto_names.size(); i++ ) {
+            final String title = clickto_names.get( i );
+            _node_popup_menu_items[ i ] = new JMenuItem( title );
+            if ( title.equals( Configuration.clickto_options[ Configuration.open_seq_web ][ 0 ] ) ) {
+                _node_popup_menu_items[ i ].setEnabled( isCanOpenSeqWeb( node ) );
+            }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.open_tax_web ][ 0 ] ) ) {
+                _node_popup_menu_items[ i ].setEnabled( isCanOpenTaxWeb( node ) );
+            }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.blast ][ 0 ] ) ) {
+                if ( Constants.__RELEASE || Constants.__SNAPSHOT_RELEASE ) {
+                    continue;
+                }
+                _node_popup_menu_items[ i ].setEnabled( isCanBlast( node ) );
+            }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.delete_subtree_or_node ][ 0 ] ) ) {
+                if ( !getOptions().isEditable() ) {
+                    continue;
+                }
+                _node_popup_menu_items[ i ].setEnabled( isCanDelete() );
+            }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.cut_subtree ][ 0 ] ) ) {
+                if ( !getOptions().isEditable() ) {
+                    continue;
+                }
+                _node_popup_menu_items[ i ].setEnabled( isCanCut( node ) );
+            }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.copy_subtree ][ 0 ] ) ) {
+                if ( !getOptions().isEditable() ) {
+                    continue;
+                }
+                _node_popup_menu_items[ i ].setEnabled( isCanCopy() );
+            }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.paste_subtree ][ 0 ] ) ) {
+                if ( !getOptions().isEditable() ) {
+                    continue;
+                }
+                _node_popup_menu_items[ i ].setEnabled( isCanPaste() );
+            }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.edit_node_data ][ 0 ] ) ) {
+                if ( !getOptions().isEditable() ) {
+                    continue;
+                }
+            }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.add_new_node ][ 0 ] ) ) {
+                if ( !getOptions().isEditable() ) {
+                    continue;
+                }
+            }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.reroot ][ 0 ] ) ) {
+                _node_popup_menu_items[ i ].setEnabled( isCanReroot() );
+            }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.collapse_uncollapse ][ 0 ] ) ) {
+                _node_popup_menu_items[ i ].setEnabled( isCanCollapse() );
+            }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.color_subtree ][ 0 ] ) ) {
+                _node_popup_menu_items[ i ].setEnabled( isCanColorSubtree() );
+            }
+            else if ( title.equals( Configuration.clickto_options[ Configuration.subtree ][ 0 ] ) ) {
+                _node_popup_menu_items[ i ].setEnabled( isCanSubtree( node ) );
+            }
+            _node_popup_menu_items[ i ].addActionListener( this );
+            _node_popup_menu.add( _node_popup_menu_items[ i ] );
+        }
+    }
+
+    final void midpointRoot() {
+        if ( ( _phylogeny == null ) || ( _phylogeny.getNumberOfExternalNodes() < 2 ) ) {
+            return;
+        }
+        if ( !_phylogeny.isRerootable() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "This is not rerootable",
+                                           "Not rerootable",
+                                           JOptionPane.WARNING_MESSAGE );
+            return;
+        }
+        setWaitCursor();
+        PhylogenyMethods.midpointRoot( _phylogeny );
+        resetNodeIdToDistToLeafMap();
+        setArrowCursor();
+        repaint();
+    }
+
+    final void mouseClicked( final MouseEvent e ) {
+        if ( getOptions().isShowOverview() && isOvOn() && isInOv() ) {
+            final double w_ratio = getVisibleRect().width / getOvRectangle().getWidth();
+            final double h_ratio = getVisibleRect().height / getOvRectangle().getHeight();
+            double x = ( e.getX() - getVisibleRect().x - getOvXPosition() - getOvRectangle().getWidth() / 2.0 )
+                    * w_ratio;
+            double y = ( e.getY() - getVisibleRect().y - getOvYPosition() - getOvRectangle().getHeight() / 2.0 )
+                    * h_ratio;
+            if ( x < 0 ) {
+                x = 0;
+            }
+            if ( y < 0 ) {
+                y = 0;
+            }
+            final double max_x = getWidth() - getVisibleRect().width;
+            final double max_y = getHeight() - getVisibleRect().height;
+            if ( x > max_x ) {
+                x = max_x;
+            }
+            if ( y > max_y ) {
+                y = max_y;
+            }
+            getMainPanel().getCurrentScrollPane().getViewport()
+                    .setViewPosition( new Point( ForesterUtil.roundToInt( x ), ForesterUtil.roundToInt( y ) ) );
+            setInOvRect( true );
+            repaint();
+        }
+        else {
+            final PhylogenyNode node = findNode( e.getX(), e.getY() );
+            if ( node != null ) {
+                if ( !node.isRoot() && node.getParent().isCollapse() ) {
+                    return;
+                }
+                _highlight_node = node;
+                // Check if shift key is down
+                if ( ( e.getModifiers() & InputEvent.SHIFT_MASK ) != 0 ) {
+                    // Yes, so add to _found_nodes
+                    if ( getFoundNodes() == null ) {
+                        setFoundNodes( new HashSet<Integer>() );
+                    }
+                    getFoundNodes().add( node.getId() );
+                    // Check if control key is down
+                }
+                else if ( ( e.getModifiers() & InputEvent.CTRL_MASK ) != 0 ) {
+                    // Yes, so pop-up menu
+                    displayNodePopupMenu( node, e.getX(), e.getY() );
+                    // Handle unadorned click
+                }
+                else {
+                    // Check for right mouse button
+                    if ( e.getModifiers() == 4 ) {
+                        displayNodePopupMenu( node, e.getX(), e.getY() );
+                    }
+                    else {
+                        // if not in _found_nodes, clear _found_nodes
+                        handleClickToAction( _control_panel.getActionWhenNodeClicked(), node );
+                    }
+                }
+            }
+            else {
+                // no node was clicked
+                _highlight_node = null;
+            }
+        }
+        repaint();
+    }
+
+    final void mouseDragInBrowserPanel( final MouseEvent e ) {
+        setCursor( MOVE_CURSOR );
+        final Point scroll_position = getMainPanel().getCurrentScrollPane().getViewport().getViewPosition();
+        scroll_position.x -= ( e.getX() - getLastDragPointX() );
+        scroll_position.y -= ( e.getY() - getLastDragPointY() );
+        if ( scroll_position.x < 0 ) {
+            scroll_position.x = 0;
+        }
+        else {
+            final int max_x = getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getMaximum()
+                    - getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getVisibleAmount();
+            if ( scroll_position.x > max_x ) {
+                scroll_position.x = max_x;
+            }
+        }
+        if ( scroll_position.y < 0 ) {
+            scroll_position.y = 0;
+        }
+        else {
+            final int max_y = getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getMaximum()
+                    - getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getVisibleAmount();
+            if ( scroll_position.y > max_y ) {
+                scroll_position.y = max_y;
+            }
+        }
+        if ( isOvOn() || getOptions().isShowScale() ) {
+            repaint();
+        }
+        getMainPanel().getCurrentScrollPane().getViewport().setViewPosition( scroll_position );
+    }
+
+    final void mouseDragInOvRectangle( final MouseEvent e ) {
+        setCursor( HAND_CURSOR );
+        final double w_ratio = getVisibleRect().width / getOvRectangle().getWidth();
+        final double h_ratio = getVisibleRect().height / getOvRectangle().getHeight();
+        final Point scroll_position = getMainPanel().getCurrentScrollPane().getViewport().getViewPosition();
+        double dx = ( w_ratio * e.getX() - w_ratio * getLastDragPointX() );
+        double dy = ( h_ratio * e.getY() - h_ratio * getLastDragPointY() );
+        scroll_position.x = ForesterUtil.roundToInt( scroll_position.x + dx );
+        scroll_position.y = ForesterUtil.roundToInt( scroll_position.y + dy );
+        if ( scroll_position.x <= 0 ) {
+            scroll_position.x = 0;
+            dx = 0;
+        }
+        else {
+            final int max_x = getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getMaximum()
+                    - getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getVisibleAmount();
+            if ( scroll_position.x >= max_x ) {
+                dx = 0;
+                scroll_position.x = max_x;
+            }
+        }
+        if ( scroll_position.y <= 0 ) {
+            dy = 0;
+            scroll_position.y = 0;
+        }
+        else {
+            final int max_y = getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getMaximum()
+                    - getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getVisibleAmount();
+            if ( scroll_position.y >= max_y ) {
+                dy = 0;
+                scroll_position.y = max_y;
+            }
+        }
+        repaint();
+        getMainPanel().getCurrentScrollPane().getViewport().setViewPosition( scroll_position );
+        setLastMouseDragPointX( ( float ) ( e.getX() + dx ) );
+        setLastMouseDragPointY( ( float ) ( e.getY() + dy ) );
+    }
+
+    final void mouseMoved( final MouseEvent e ) {
+        requestFocusInWindow();
+        if ( getControlPanel().isNodeDescPopup() ) {
+            if ( _node_desc_popup != null ) {
+                _node_desc_popup.hide();
+                _node_desc_popup = null;
+            }
+        }
+        if ( getOptions().isShowOverview() && isOvOn() ) {
+            if ( inOvVirtualRectangle( e ) ) {
+                if ( !isInOvRect() ) {
+                    setInOvRect( true );
+                    repaint();
+                }
+            }
+            else {
+                if ( isInOvRect() ) {
+                    setInOvRect( false );
+                    repaint();
+                }
+            }
+        }
+        if ( inOv( e ) && getOptions().isShowOverview() && isOvOn() ) {
+            if ( !isInOv() ) {
+                setInOv( true );
+            }
+        }
+        else {
+            if ( isInOv() ) {
+                setInOv( false );
+            }
+            final PhylogenyNode node = findNode( e.getX(), e.getY() );
+            if ( ( node != null ) && ( node.isRoot() || !node.getParent().isCollapse() ) ) {
+                // cursor is over a tree node
+                if ( ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.CUT_SUBTREE )
+                        || ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.COPY_SUBTREE )
+                        || ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.PASTE_SUBTREE )
+                        || ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.DELETE_NODE_OR_SUBTREE )
+                        || ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.REROOT )
+                        || ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.ADD_NEW_NODE ) ) {
+                    setCursor( CUT_CURSOR );
+                }
+                else {
+                    setCursor( HAND_CURSOR );
+                    if ( getControlPanel().isNodeDescPopup() ) {
+                        showNodeDataPopup( e, node );
+                    }
+                }
+            }
+            else {
+                setCursor( ARROW_CURSOR );
+            }
+        }
+    }
+
+    final void mouseReleasedInBrowserPanel( final MouseEvent e ) {
+        setCursor( ARROW_CURSOR );
+    }
+
+    final public void mouseWheelMoved( final MouseWheelEvent e ) {
+        final int notches = e.getWheelRotation();
+        if ( inOvVirtualRectangle( e ) ) {
+            if ( !isInOvRect() ) {
+                setInOvRect( true );
+                repaint();
+            }
+        }
+        else {
+            if ( isInOvRect() ) {
+                setInOvRect( false );
+                repaint();
+            }
+        }
+        if ( e.isControlDown() ) {
+            if ( notches < 0 ) {
+                getTreeFontSet().increaseFontSize();
+                getControlPanel().displayedPhylogenyMightHaveChanged( true );
+            }
+            else {
+                getTreeFontSet().decreaseFontSize();
+                getControlPanel().displayedPhylogenyMightHaveChanged( true );
+            }
+        }
+        else if ( e.isShiftDown() ) {
+            if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
+                    || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
+                if ( notches < 0 ) {
+                    for( int i = 0; i < ( -notches ); ++i ) {
+                        setStartingAngle( ( getStartingAngle() % TWO_PI ) + ANGLE_ROTATION_UNIT );
+                        getControlPanel().displayedPhylogenyMightHaveChanged( false );
+                    }
+                }
+                else {
+                    for( int i = 0; i < notches; ++i ) {
+                        setStartingAngle( ( getStartingAngle() % TWO_PI ) - ANGLE_ROTATION_UNIT );
+                        if ( getStartingAngle() < 0 ) {
+                            setStartingAngle( TWO_PI + getStartingAngle() );
+                        }
+                        getControlPanel().displayedPhylogenyMightHaveChanged( false );
+                    }
+                }
+            }
+            else {
+                if ( notches < 0 ) {
+                    for( int i = 0; i < ( -notches ); ++i ) {
+                        getControlPanel().zoomInY( Constants.WHEEL_ZOOM_IN_FACTOR );
+                        getControlPanel().displayedPhylogenyMightHaveChanged( false );
+                    }
+                }
+                else {
+                    for( int i = 0; i < notches; ++i ) {
+                        getControlPanel().zoomOutY( Constants.WHEEL_ZOOM_OUT_FACTOR );
+                        getControlPanel().displayedPhylogenyMightHaveChanged( false );
+                    }
+                }
+            }
+        }
+        else {
+            if ( notches < 0 ) {
+                for( int i = 0; i < ( -notches ); ++i ) {
+                    getControlPanel().zoomInX( Constants.WHEEL_ZOOM_IN_FACTOR,
+                                               Constants.WHEEL_ZOOM_IN_X_CORRECTION_FACTOR );
+                    getControlPanel().zoomInY( Constants.WHEEL_ZOOM_IN_FACTOR );
+                    getControlPanel().displayedPhylogenyMightHaveChanged( false );
+                }
+            }
+            else {
+                for( int i = 0; i < notches; ++i ) {
+                    getControlPanel().zoomOutY( Constants.WHEEL_ZOOM_OUT_FACTOR );
+                    getControlPanel().zoomOutX( Constants.WHEEL_ZOOM_OUT_FACTOR,
+                                                Constants.WHEEL_ZOOM_OUT_X_CORRECTION_FACTOR );
+                    getControlPanel().displayedPhylogenyMightHaveChanged( false );
+                }
+            }
+        }
+        requestFocus();
+        requestFocusInWindow();
+        requestFocus();
+    }
+
+    final void multiplyUrtFactor( final float f ) {
+        _urt_factor *= f;
+    }
+
+    final JApplet obtainApplet() {
+        return ( ( MainPanelApplets ) getMainPanel() ).getApplet();
+    }
+
+    final private void openSeqWeb( final PhylogenyNode node ) {
+        if ( !isCanOpenSeqWeb( node ) ) {
+            cannotOpenBrowserWarningMessage( "sequence" );
+            return;
+        }
+        String uri_str = null;
+        final Sequence seq = node.getNodeData().getSequence();
+        final String source = seq.getAccession().getSource().toLowerCase();
+        String url;
+        if ( source.toLowerCase().equals( "ncbi" ) ) {
+            url = Constants.NCBI_ALL_DATABASE_SEARCH;
+        }
+        else {
+            final WebLink weblink = getConfiguration().getWebLink( source );
+            url = weblink.getUrl().toString();
+        }
+        try {
+            uri_str = url + URLEncoder.encode( seq.getAccession().getValue(), ForesterConstants.UTF8 );
+        }
+        catch ( final UnsupportedEncodingException e ) {
+            Util.showErrorMessage( this, e.toString() );
+            e.printStackTrace();
+        }
+        if ( !ForesterUtil.isEmpty( uri_str ) ) {
+            try {
+                JApplet applet = null;
+                if ( isApplet() ) {
+                    applet = obtainApplet();
+                }
+                Util.launchWebBrowser( new URI( uri_str ), isApplet(), applet, "_aptx_seq" );
+            }
+            catch ( final IOException e ) {
+                Util.showErrorMessage( this, e.toString() );
+                e.printStackTrace();
+            }
+            catch ( final URISyntaxException e ) {
+                Util.showErrorMessage( this, e.toString() );
+                e.printStackTrace();
+            }
+        }
+        else {
+            cannotOpenBrowserWarningMessage( "sequence" );
+        }
+    }
+
+    final private void openTaxWeb( final PhylogenyNode node ) {
+        if ( !isCanOpenTaxWeb( node ) ) {
+            cannotOpenBrowserWarningMessage( "taxonomic" );
+            return;
+        }
+        String uri_str = null;
+        final Taxonomy tax = node.getNodeData().getTaxonomy();
+        if ( ( tax.getIdentifier() != null ) && !ForesterUtil.isEmpty( tax.getIdentifier().getProvider() )
+                && getConfiguration().isHasWebLink( tax.getIdentifier().getProvider().toLowerCase() ) ) {
+            final String type = tax.getIdentifier().getProvider().toLowerCase();
+            final WebLink weblink = getConfiguration().getWebLink( type );
+            try {
+                uri_str = weblink.getUrl() + URLEncoder.encode( tax.getIdentifier().getValue(), ForesterConstants.UTF8 );
+            }
+            catch ( final UnsupportedEncodingException e ) {
+                Util.showErrorMessage( this, e.toString() );
+                e.printStackTrace();
+            }
+        }
+        else if ( ( tax.getIdentifier() != null ) && !ForesterUtil.isEmpty( tax.getIdentifier().getValue() )
+                && tax.getIdentifier().getValue().startsWith( "http://" ) ) {
+            try {
+                uri_str = new URI( tax.getIdentifier().getValue() ).toString();
+            }
+            catch ( final URISyntaxException e ) {
+                Util.showErrorMessage( this, e.toString() );
+                uri_str = null;
+                e.printStackTrace();
+            }
+        }
+        else if ( !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
+            try {
+                uri_str = "http://www.eol.org/search?q="
+                        + URLEncoder.encode( tax.getScientificName(), ForesterConstants.UTF8 );
+            }
+            catch ( final UnsupportedEncodingException e ) {
+                Util.showErrorMessage( this, e.toString() );
+                e.printStackTrace();
+            }
+        }
+        else if ( !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
+            try {
+                uri_str = "http://www.uniprot.org/taxonomy/?query="
+                        + URLEncoder.encode( tax.getTaxonomyCode(), ForesterConstants.UTF8 );
+            }
+            catch ( final UnsupportedEncodingException e ) {
+                Util.showErrorMessage( this, e.toString() );
+                e.printStackTrace();
+            }
+        }
+        else if ( !ForesterUtil.isEmpty( tax.getCommonName() ) ) {
+            try {
+                uri_str = "http://www.eol.org/search?q="
+                        + URLEncoder.encode( tax.getCommonName(), ForesterConstants.UTF8 );
+            }
+            catch ( final UnsupportedEncodingException e ) {
+                Util.showErrorMessage( this, e.toString() );
+                e.printStackTrace();
+            }
+        }
+        if ( !ForesterUtil.isEmpty( uri_str ) ) {
+            try {
+                JApplet applet = null;
+                if ( isApplet() ) {
+                    applet = obtainApplet();
+                }
+                Util.launchWebBrowser( new URI( uri_str ), isApplet(), applet, "_aptx_tax" );
+            }
+            catch ( final IOException e ) {
+                Util.showErrorMessage( this, e.toString() );
+                e.printStackTrace();
+            }
+            catch ( final URISyntaxException e ) {
+                Util.showErrorMessage( this, e.toString() );
+                e.printStackTrace();
+            }
+        }
+        else {
+            cannotOpenBrowserWarningMessage( "taxonomic" );
+        }
+    }
+
+    final void paintBranchCircular( final PhylogenyNode p,
+                                    final PhylogenyNode c,
+                                    final Graphics2D g,
+                                    final boolean radial_labels,
+                                    final boolean to_pdf,
+                                    final boolean to_graphics_file ) {
+        final double angle = _urt_nodeid_angle_map.get( c.getId() );
+        final double root_x = _root.getXcoord();
+        final double root_y = _root.getYcoord();
+        final double dx = root_x - p.getXcoord();
+        final double dy = root_y - p.getYcoord();
+        final double parent_radius = Math.sqrt( dx * dx + dy * dy );
+        final double arc = ( _urt_nodeid_angle_map.get( p.getId() ) ) - angle;
+        assignGraphicsForBranchWithColorForParentBranch( c, false, g, to_pdf, to_graphics_file );
+        if ( ( c.isFirstChildNode() || c.isLastChildNode() )
+                && ( ( Math.abs( parent_radius * arc ) > 1.5 ) || to_pdf || to_graphics_file ) ) {
+            final double r2 = 2.0 * parent_radius;
+            drawArc( root_x - parent_radius, root_y - parent_radius, r2, r2, ( -angle - arc ), arc, g );
+        }
+        drawLine( c.getXcoord(), c.getYcoord(), root_x + ( Math.cos( angle ) * parent_radius ), root_y
+                + ( Math.sin( angle ) * parent_radius ), g );
+        paintNodeBox( c.getXcoord(), c.getYcoord(), c, g, to_pdf, to_graphics_file, isInFoundNodes( c ) );
+        if ( c.isExternal() ) {
+            final boolean is_in_found_nodes = isInFoundNodes( c );
+            if ( ( _dynamic_hiding_factor > 1 ) && !is_in_found_nodes
+                    && ( _urt_nodeid_index_map.get( c.getId() ) % _dynamic_hiding_factor != 1 ) ) {
+                return;
+            }
+            paintNodeDataUnrootedCirc( g, c, to_pdf, to_graphics_file, radial_labels, 0, is_in_found_nodes );
+        }
+    }
+
+    final void paintBranchCircularLite( final PhylogenyNode p, final PhylogenyNode c, final Graphics2D g ) {
+        final double angle = _urt_nodeid_angle_map.get( c.getId() );
+        final double root_x = _root.getXSecondary();
+        final double root_y = _root.getYSecondary();
+        final double dx = root_x - p.getXSecondary();
+        final double dy = root_y - p.getYSecondary();
+        final double arc = ( _urt_nodeid_angle_map.get( p.getId() ) ) - angle;
+        final double parent_radius = Math.sqrt( dx * dx + dy * dy );
+        g.setColor( getTreeColorSet().getOvColor() );
+        if ( ( c.isFirstChildNode() || c.isLastChildNode() ) && ( Math.abs( arc ) > 0.02 ) ) {
+            final double r2 = 2.0 * parent_radius;
+            drawArc( root_x - parent_radius, root_y - parent_radius, r2, r2, ( -angle - arc ), arc, g );
+        }
+        drawLine( c.getXSecondary(), c.getYSecondary(), root_x + ( Math.cos( angle ) * parent_radius ), root_y
+                + ( Math.sin( angle ) * parent_radius ), g );
+        if ( isInFoundNodes( c ) ) {
+            g.setColor( getTreeColorSet().getFoundColor() );
+            drawRectFilled( c.getXSecondary() - 1, c.getYSecondary() - 1, 3, 3, g );
+        }
+    }
+
+    final private void paintBranchLength( final Graphics2D g,
+                                          final PhylogenyNode node,
+                                          final boolean to_pdf,
+                                          final boolean to_graphics_file ) {
+        g.setFont( getTreeFontSet().getSmallFont() );
+        if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
+            g.setColor( Color.BLACK );
+        }
+        else {
+            g.setColor( getTreeColorSet().getBranchLengthColor() );
+        }
+        if ( !node.isRoot() ) {
+            if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
+                TreePanel.drawString( FORMATTER_BRANCH_LENGTH.format( node.getDistanceToParent() ), node.getParent()
+                        .getXcoord()
+                        + EURO_D, node.getYcoord() - getTreeFontSet()._small_max_descent, g );
+            }
+            else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
+                TreePanel.drawString( FORMATTER_BRANCH_LENGTH.format( node.getDistanceToParent() ), node.getParent()
+                        .getXcoord()
+                        + ROUNDED_D, node.getYcoord() - getTreeFontSet()._small_max_descent, g );
+            }
+            else {
+                TreePanel.drawString( FORMATTER_BRANCH_LENGTH.format( node.getDistanceToParent() ), node.getParent()
+                        .getXcoord() + 3, node.getYcoord() - getTreeFontSet()._small_max_descent, g );
+            }
+        }
+        else {
+            TreePanel.drawString( FORMATTER_BRANCH_LENGTH.format( node.getDistanceToParent() ), 3, node.getYcoord()
+                    - getTreeFontSet()._small_max_descent, g );
+        }
+    }
+
+    final private void paintBranchLite( final Graphics2D g,
+                                        final float x1,
+                                        final float x2,
+                                        final float y1,
+                                        final float y2,
+                                        final PhylogenyNode node ) {
+        g.setColor( getTreeColorSet().getOvColor() );
+        if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR ) {
+            drawLine( x1, y1, x2, y2, g );
+        }
+        else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CONVEX ) {
+            _quad_curve.setCurve( x1, y1, x1, y2, x2, y2 );
+            ( g ).draw( _quad_curve );
+        }
+        else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CURVED ) {
+            final float dx = x2 - x1;
+            final float dy = y2 - y1;
+            _cubic_curve.setCurve( x1, y1, x1 + ( dx * 0.4f ), y1 + ( dy * 0.2f ), x1 + ( dx * 0.6f ), y1
+                    + ( dy * 0.8f ), x2, y2 );
+            ( g ).draw( _cubic_curve );
+        }
+        else {
+            final float x2a = x2;
+            final float x1a = x1;
+            // draw the vertical line
+            if ( node.isFirstChildNode() || node.isLastChildNode() ) {
+                drawLine( x1, y1, x1, y2, g );
+            }
+            // draw the horizontal line
+            drawLine( x1a, y2, x2a, y2, g );
+        }
+    }
+
+    /**
+     * Paint a branch which consists of a vertical and a horizontal bar
+     * @param is_ind_found_nodes 
+     */
+    final private void paintBranchRectangular( final Graphics2D g,
+                                               final float x1,
+                                               final float x2,
+                                               float y1,
+                                               final float y2,
+                                               final PhylogenyNode node,
+                                               final boolean to_pdf,
+                                               final boolean to_graphics_file ) {
+        assignGraphicsForBranchWithColorForParentBranch( node, false, g, to_pdf, to_graphics_file );
+        if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR ) {
+            drawLine( x1, y1, x2, y2, g );
+        }
+        else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CONVEX ) {
+            _quad_curve.setCurve( x1, y1, x1, y2, x2, y2 );
+            g.draw( _quad_curve );
+        }
+        else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CURVED ) {
+            final float dx = x2 - x1;
+            final float dy = y2 - y1;
+            _cubic_curve.setCurve( x1, y1, x1 + ( dx * 0.4f ), y1 + ( dy * 0.2f ), x1 + ( dx * 0.6f ), y1
+                    + ( dy * 0.8f ), x2, y2 );
+            g.draw( _cubic_curve );
+        }
+        else {
+            float x2a = x2;
+            float x1a = x1;
+            // draw the vertical line
+            boolean draw_horizontal = true;
+            float y2_r = 0;
+            if ( node.isFirstChildNode() || node.isLastChildNode()
+                    || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE )
+                    || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) ) {
+                boolean draw_vertical = true;
+                final PhylogenyNode parent = node.getParent();
+                if ( ( ( getOptions().isShowNodeBoxes() && !to_pdf && !to_graphics_file ) || ( ( getControlPanel()
+                        .isEvents() )
+                        && ( parent != null ) && parent.isHasAssignedEvent() ) )
+                        && ( _phylogeny.isRooted() || !( ( parent != null ) && parent.isRoot() ) )
+                        && !( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() && !parent
+                                .isDuplication() ) ) {
+                    if ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE )
+                            && ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) ) {
+                        if ( Math.abs( y2 - y1 ) <= TreePanel.HALF_BOX_SIZE ) {
+                            draw_vertical = false;
+                        }
+                        else {
+                            if ( y1 < y2 ) {
+                                y1 += TreePanel.HALF_BOX_SIZE;
+                            }
+                            else {
+                                if ( !to_pdf ) {
+                                    y1 -= TreePanel.HALF_BOX_SIZE + 1;
+                                }
+                                else {
+                                    y1 -= TreePanel.HALF_BOX_SIZE;
+                                }
+                            }
+                        }
+                    }
+                    if ( ( x2 - x1 ) <= TreePanel.HALF_BOX_SIZE ) {
+                        draw_horizontal = false;
+                    }
+                    else if ( !draw_vertical ) {
+                        x1a += TreePanel.HALF_BOX_SIZE;
+                    }
+                    if ( ( ( x2 - x1a ) > TreePanel.HALF_BOX_SIZE )
+                            && !( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() && !node
+                                    .isDuplication() ) ) {
+                        x2a -= TreePanel.HALF_BOX_SIZE;
+                    }
+                }
+                if ( draw_vertical ) {
+                    if ( !to_graphics_file
+                            && !to_pdf
+                            && ( ( ( y2 < getVisibleRect().getMinY() - 20 ) && ( y1 < getVisibleRect().getMinY() - 20 ) ) || ( ( y2 > getVisibleRect()
+                                    .getMaxY() + 20 ) && ( y1 > getVisibleRect().getMaxY() + 20 ) ) ) ) {
+                        // Do nothing.
+                    }
+                    else {
+                        if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
+                            float x2c = x1 + EURO_D;
+                            if ( x2c > x2a ) {
+                                x2c = x2a;
+                            }
+                            drawLine( x1, y1, x2c, y2, g );
+                        }
+                        else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
+                            if ( y2 > y1 ) {
+                                y2_r = y2 - ROUNDED_D;
+                                if ( y2_r < y1 ) {
+                                    y2_r = y1;
+                                }
+                                drawLine( x1, y1, x1, y2_r, g );
+                            }
+                            else {
+                                y2_r = y2 + ROUNDED_D;
+                                if ( y2_r > y1 ) {
+                                    y2_r = y1;
+                                }
+                                drawLine( x1, y1, x1, y2_r, g );
+                            }
+                        }
+                        else {
+                            drawLine( x1, y1, x1, y2, g );
+                        }
+                    }
+                }
+            }
+            // draw the horizontal line
+            if ( !to_graphics_file && !to_pdf
+                    && ( ( y2 < getVisibleRect().getMinY() - 20 ) || ( y2 > getVisibleRect().getMaxY() + 20 ) ) ) {
+                return;
+            }
+            float x1_r = 0;
+            if ( draw_horizontal ) {
+                if ( !getControlPanel().isWidthBranches() || ( PhylogenyMethods.getBranchWidthValue( node ) == 1 ) ) {
+                    if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
+                        x1_r = x1a + ROUNDED_D;
+                        if ( x1_r < x2a ) {
+                            drawLine( x1_r, y2, x2a, y2, g );
+                        }
+                    }
+                    else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
+                        final float x1c = x1a + EURO_D;
+                        if ( x1c < x2a ) {
+                            drawLine( x1c, y2, x2a, y2, g );
+                        }
+                    }
+                    else {
+                        drawLine( x1a, y2, x2a, y2, g );
+                    }
+                }
+                else {
+                    final double w = PhylogenyMethods.getBranchWidthValue( node );
+                    if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
+                        x1_r = x1a + ROUNDED_D;
+                        if ( x1_r < x2a ) {
+                            drawRectFilled( x1_r, y2 - ( w / 2 ), x2a - x1_r, w, g );
+                        }
+                    }
+                    else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
+                        final float x1c = x1a + EURO_D;
+                        if ( x1c < x2a ) {
+                            drawRectFilled( x1c, y2 - ( w / 2 ), x2a - x1c, w, g );
+                        }
+                    }
+                    else {
+                        drawRectFilled( x1a, y2 - ( w / 2 ), x2a - x1a, w, g );
+                    }
+                }
+            }
+            if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) ) {
+                if ( x1_r > x2a ) {
+                    x1_r = x2a;
+                }
+                if ( y2 > y2_r ) {
+                    final double diff = y2 - y2_r;
+                    _arc.setArc( x1, y2_r - diff, 2 * ( x1_r - x1 ), 2 * diff, 180, 90, Arc2D.OPEN );
+                }
+                else {
+                    _arc.setArc( x1, y2, 2 * ( x1_r - x1 ), 2 * ( y2_r - y2 ), 90, 90, Arc2D.OPEN );
+                }
+                g.draw( _arc );
+            }
+        }
+        paintNodeBox( x2, y2, node, g, to_pdf, to_graphics_file, isInFoundNodes( node ) );
+    }
+
+    final void paintCircular( final Phylogeny phy,
+                              final double starting_angle,
+                              final int center_x,
+                              final int center_y,
+                              final int radius,
+                              final Graphics2D g,
+                              final boolean to_pdf,
+                              final boolean to_graphics_file ) {
+        _circ_num_ext_nodes = phy.getNumberOfExternalNodes();
+        _root = phy.getRoot();
+        _root.setXcoord( center_x );
+        _root.setYcoord( center_y );
+        paintNodeBox( _root.getXcoord(), _root.getYcoord(), _root, g, to_pdf, to_graphics_file, isInFoundNodes( _root ) );
+        final boolean radial_labels = getOptions().getNodeLabelDirection() == NODE_LABEL_DIRECTION.RADIAL;
+        double current_angle = starting_angle;
+        int i = 0;
+        for( final PhylogenyNodeIterator it = phy.iteratorExternalForward(); it.hasNext(); ) {
+            final PhylogenyNode n = it.next();
+            n.setXcoord( ( float ) ( center_x + ( radius * Math.cos( current_angle ) ) ) );
+            n.setYcoord( ( float ) ( center_y + ( radius * Math.sin( current_angle ) ) ) );
+            _urt_nodeid_angle_map.put( n.getId(), current_angle );
+            _urt_nodeid_index_map.put( n.getId(), i++ );
+            current_angle += ( TWO_PI / _circ_num_ext_nodes );
+        }
+        paintCirculars( phy.getRoot(), phy, center_x, center_y, radius, radial_labels, g, to_pdf, to_graphics_file );
+    }
+
+    final void paintCircularLite( final Phylogeny phy,
+                                  final double starting_angle,
+                                  final int center_x,
+                                  final int center_y,
+                                  final int radius,
+                                  final Graphics2D g ) {
+        _circ_num_ext_nodes = phy.getNumberOfExternalNodes();
+        _root = phy.getRoot();
+        _root.setXSecondary( center_x );
+        _root.setYSecondary( center_y );
+        double current_angle = starting_angle;
+        for( final PhylogenyNodeIterator it = phy.iteratorExternalForward(); it.hasNext(); ) {
+            final PhylogenyNode n = it.next();
+            n.setXSecondary( ( float ) ( center_x + radius * Math.cos( current_angle ) ) );
+            n.setYSecondary( ( float ) ( center_y + radius * Math.sin( current_angle ) ) );
+            _urt_nodeid_angle_map.put( n.getId(), current_angle );
+            current_angle += ( TWO_PI / _circ_num_ext_nodes );
+        }
+        paintCircularsLite( phy.getRoot(), phy, center_x, center_y, radius, g );
+    }
+
+    final private double paintCirculars( final PhylogenyNode n,
+                                         final Phylogeny phy,
+                                         final float center_x,
+                                         final float center_y,
+                                         final double radius,
+                                         final boolean radial_labels,
+                                         final Graphics2D g,
+                                         final boolean to_pdf,
+                                         final boolean to_graphics_file ) {
+        if ( n.isExternal() ) {
+            if ( !_urt_nodeid_angle_map.containsKey( n.getId() ) ) {
+                System.out.println( "no " + n + ", fucker!" );//TODO
+            }
+            return _urt_nodeid_angle_map.get( n.getId() );
+        }
+        else {
+            final List<PhylogenyNode> descs = n.getDescendants();
+            double sum = 0;
+            for( final PhylogenyNode desc : descs ) {
+                sum += paintCirculars( desc,
+                                       phy,
+                                       center_x,
+                                       center_y,
+                                       radius,
+                                       radial_labels,
+                                       g,
+                                       to_pdf,
+                                       to_graphics_file );
+            }
+            double r = 0;
+            if ( !n.isRoot() ) {
+                r = 1 - ( ( ( double ) _circ_max_depth - PhylogenyMethods.calculateDepth( n ) ) / _circ_max_depth );
+            }
+            final double theta = sum / descs.size();
+            n.setXcoord( ( float ) ( center_x + r * radius * Math.cos( theta ) ) );
+            n.setYcoord( ( float ) ( center_y + r * radius * Math.sin( theta ) ) );
+            _urt_nodeid_angle_map.put( n.getId(), theta );
+            for( final PhylogenyNode desc : descs ) {
+                paintBranchCircular( n, desc, g, radial_labels, to_pdf, to_graphics_file );
+            }
+            return theta;
+        }
+    }
+
+    final private void paintCircularsLite( final PhylogenyNode n,
+                                           final Phylogeny phy,
+                                           final int center_x,
+                                           final int center_y,
+                                           final int radius,
+                                           final Graphics2D g ) {
+        if ( n.isExternal() ) {
+            return;
+        }
+        else {
+            final List<PhylogenyNode> descs = n.getDescendants();
+            for( final PhylogenyNode desc : descs ) {
+                paintCircularsLite( desc, phy, center_x, center_y, radius, g );
+            }
+            float r = 0;
+            if ( !n.isRoot() ) {
+                r = 1 - ( ( ( float ) _circ_max_depth - PhylogenyMethods.calculateDepth( n ) ) / _circ_max_depth );
+            }
+            final double theta = _urt_nodeid_angle_map.get( n.getId() );
+            n.setXSecondary( ( float ) ( center_x + radius * r * Math.cos( theta ) ) );
+            n.setYSecondary( ( float ) ( center_y + radius * r * Math.sin( theta ) ) );
+            for( final PhylogenyNode desc : descs ) {
+                paintBranchCircularLite( n, desc, g );
+            }
+        }
+    }
+
+    final private void paintCollapsedNode( final Graphics2D g,
+                                           final PhylogenyNode node,
+                                           final boolean to_graphics_file,
+                                           final boolean to_pdf,
+                                           final boolean is_in_found_nodes ) {
+        if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
+            g.setColor( Color.BLACK );
+        }
+        else if ( is_in_found_nodes ) {
+            g.setColor( getTreeColorSet().getFoundColor() );
+        }
+        else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
+            g.setColor( getTaxonomyBasedColor( node ) );
+        }
+        else if ( getOptions().isColorLabelsSameAsParentBranch() && getControlPanel().isColorBranches()
+                && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
+            g.setColor( PhylogenyMethods.getBranchColorValue( node ) );
+        }
+        else {
+            g.setColor( getTreeColorSet().getCollapseFillColor() );
+        }
+        double d = node.getAllExternalDescendants().size();
+        if ( d > 1000 ) {
+            d = ( 3 * _y_distance ) / 3;
+        }
+        else {
+            d = ( Math.log10( d ) * _y_distance ) / 2.5;
+        }
+        if ( d < BOX_SIZE ) {
+            d = BOX_SIZE;
+        }
+        _polygon.reset();
+        _polygon.addPoint( ForesterUtil.roundToInt( node.getXcoord() - TreePanel.BOX_SIZE ), ForesterUtil
+                .roundToInt( node.getYcoord() ) );
+        _polygon.addPoint( ForesterUtil.roundToInt( node.getXcoord() + TreePanel.BOX_SIZE ), ForesterUtil
+                .roundToInt( node.getYcoord() - d ) );
+        _polygon.addPoint( ForesterUtil.roundToInt( node.getXcoord() + TreePanel.BOX_SIZE ), ForesterUtil
+                .roundToInt( node.getYcoord() + d ) );
+        g.fillPolygon( _polygon );
+        paintNodeData( g, node, to_graphics_file, to_pdf, is_in_found_nodes );
+    }
+
+    @Override
+    final public void paintComponent( final Graphics g ) {
+        // Dimension currentSize = getSize();
+        //  if ( offscreenImage == null || !currentSize.equals( offscreenDimension ) ) {
+        // call the 'java.awt.Component.createImage(...)' method to get an
+        // image
+        //   offscreenImage = createImage( currentSize.width, currentSize.height );
+        //  offscreenGraphics = offscreenImage.getGraphics();
+        //  offscreenDimension = currentSize;
+        // }
+        // super.paintComponent( g ); //why?
+        //final Graphics2D g2d = ( Graphics2D ) offscreenGraphics;
+        final Graphics2D g2d = ( Graphics2D ) g;
+        g2d.setRenderingHints( _rendering_hints );
+        paintPhylogeny( g2d, false, false, 0, 0, 0, 0 );
+        //g.drawImage( offscreenImage, 0, 0, this );
+    }
+
+    @Override
+    public void update( final Graphics g ) {
+        paint( g );
+    }
+
+    final private void paintConfidenceValues( final Graphics2D g,
+                                              final PhylogenyNode node,
+                                              final boolean to_pdf,
+                                              final boolean to_graphics_file ) {
+        String conf_str = "";
+        final List<Confidence> confidences = node.getBranchData().getConfidences();
+        if ( confidences.size() == 1 ) {
+            final double value = node.getBranchData().getConfidence( 0 ).getValue();
+            if ( ( value == Confidence.CONFIDENCE_DEFAULT_VALUE ) || ( value < getOptions().getMinConfidenceValue() ) ) {
+                return;
+            }
+            conf_str = FORMATTER_CONFIDENCE.format( value );
+        }
+        else if ( confidences.size() > 1 ) {
+            boolean one_ok = false;
+            boolean not_first = false;
+            Collections.sort( confidences );
+            final StringBuilder sb = new StringBuilder();
+            for( final Confidence confidence : confidences ) {
+                final double value = confidence.getValue();
+                if ( value != Confidence.CONFIDENCE_DEFAULT_VALUE ) {
+                    if ( value >= getOptions().getMinConfidenceValue() ) {
+                        one_ok = true;
+                    }
+                    if ( not_first ) {
+                        sb.append( "/" );
+                    }
+                    else {
+                        not_first = true;
+                    }
+                    sb.append( FORMATTER_CONFIDENCE.format( ForesterUtil.round( value, getOptions()
+                            .getNumberOfDigitsAfterCommaForConfidenceValues() ) ) );
+                }
+            }
+            if ( one_ok ) {
+                conf_str = sb.toString();
+            }
+        }
+        if ( conf_str.length() > 0 ) {
+            final double parent_x = node.getParent().getXcoord();
+            double x = node.getXcoord();
+            g.setFont( getTreeFontSet().getSmallFont() );
+            if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
+                x += EURO_D;
+            }
+            else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
+                x += ROUNDED_D;
+            }
+            if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
+                g.setColor( Color.BLACK );
+            }
+            else {
+                g.setColor( getTreeColorSet().getConfidenceColor() );
+            }
+            TreePanel
+                    .drawString( conf_str, parent_x
+                            + ( ( x - parent_x - getTreeFontSet()._fm_small.stringWidth( conf_str ) ) / 2 ), ( node
+                            .getYcoord() + getTreeFontSet()._small_max_ascent ) - 1, g );
+        }
+    }
+
+    final private void paintFoundNode( final int x, final int y, final Graphics2D g ) {
+        g.setColor( getTreeColorSet().getFoundColor() );
+        g.fillRect( x - TreePanel.HALF_BOX_SIZE, y - TreePanel.HALF_BOX_SIZE, TreePanel.BOX_SIZE, TreePanel.BOX_SIZE );
+    }
+
+    final private void paintGainedAndLostCharacters( final Graphics2D g,
+                                                     final PhylogenyNode node,
+                                                     final String gained,
+                                                     final String lost ) {
+        if ( node.getParent() != null ) {
+            final double parent_x = node.getParent().getXcoord();
+            final double x = node.getXcoord();
+            g.setFont( getTreeFontSet().getLargeFont() );
+            g.setColor( getTreeColorSet().getGainedCharactersColor() );
+            if ( Constants.SPECIAL_CUSTOM ) {
+                g.setColor( Color.BLUE );
+            }
+            TreePanel
+                    .drawString( gained, parent_x
+                            + ( ( x - parent_x - getTreeFontSet()._fm_large.stringWidth( gained ) ) / 2 ), ( node
+                            .getYcoord() - getTreeFontSet()._fm_large.getMaxDescent() ), g );
+            g.setColor( getTreeColorSet().getLostCharactersColor() );
+            TreePanel.drawString( lost,
+                                  parent_x + ( ( x - parent_x - getTreeFontSet()._fm_large.stringWidth( lost ) ) / 2 ),
+                                  ( node.getYcoord() + getTreeFontSet()._fm_large.getMaxAscent() ),
+                                  g );
+        }
+    }
+
+    /**
+     * Draw a box at the indicated node.
+     * 
+     * @param x
+     * @param y
+     * @param node
+     * @param g
+     */
+    final private void paintNodeBox( final double x,
+                                     final double y,
+                                     final PhylogenyNode node,
+                                     final Graphics2D g,
+                                     final boolean to_pdf,
+                                     final boolean to_graphics_file,
+                                     final boolean is_in_found_nodes ) {
+        if ( node.isCollapse() ) {
+            return;
+        }
+        // if this node should be highlighted, do so
+        if ( ( _highlight_node == node ) && !to_pdf && !to_graphics_file ) {
+            g.setColor( getTreeColorSet().getFoundColor() );
+            drawOval( x - 8, y - 8, 16, 16, g );
+            drawOval( x - 9, y - 8, 17, 17, g );
+            drawOval( x - 9, y - 9, 18, 18, g );
+        }
+        if ( is_in_found_nodes ) {
+            paintFoundNode( ForesterUtil.roundToInt( x ), ForesterUtil.roundToInt( y ), g );
+        }
+        else {
+            if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
+                g.setColor( Color.BLACK );
+            }
+            else if ( getControlPanel().isEvents() && Util.isHasAssignedEvent( node ) ) {
+                final Event event = node.getNodeData().getEvent();
+                if ( event.isDuplication() ) {
+                    g.setColor( getTreeColorSet().getDuplicationBoxColor() );
+                }
+                else if ( event.isSpeciation() ) {
+                    g.setColor( getTreeColorSet().getSpecBoxColor() );
+                }
+                else if ( event.isSpeciationOrDuplication() ) {
+                    g.setColor( getTreeColorSet().getDuplicationOrSpeciationColor() );
+                }
+            }
+            else {
+                assignGraphicsForNodeBoxWithColorForParentBranch( node, g );
+            }
+            if ( ( getOptions().isShowNodeBoxes() && !to_pdf && !to_graphics_file )
+                    || ( getControlPanel().isEvents() && node.isHasAssignedEvent() ) ) {
+                if ( to_pdf || to_graphics_file ) {
+                    if ( node.isDuplication() || !getOptions().isPrintBlackAndWhite() ) {
+                        drawOvalFilled( x - HALF_BOX_SIZE, y - HALF_BOX_SIZE, BOX_SIZE, BOX_SIZE, g );
+                    }
+                }
+                else {
+                    drawRectFilled( x - HALF_BOX_SIZE, y - HALF_BOX_SIZE, BOX_SIZE, BOX_SIZE, g );
+                }
+            }
+        }
+    }
+
+    final private void paintNodeData( final Graphics2D g,
+                                      final PhylogenyNode node,
+                                      final boolean to_graphics_file,
+                                      final boolean to_pdf,
+                                      final boolean is_in_found_nodes ) {
+        if ( isNodeDataInvisible( node ) && !to_graphics_file && !to_pdf ) {
+            return;
+        }
+        if ( getOptions().isShowBranchLengthValues()
+                && ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR )
+                        || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) )
+                && ( !node.isRoot() ) && ( node.getDistanceToParent() != PhylogenyNode.DISTANCE_DEFAULT ) ) {
+            paintBranchLength( g, node, to_pdf, to_graphics_file );
+        }
+        if ( !getControlPanel().isShowInternalData() && !node.isExternal() && !node.isCollapse() ) {
+            return;
+        }
+        int x = 0;
+        if ( getControlPanel().isShowTaxonomyImages()
+                && ( getImageMap() != null )
+                && !getImageMap().isEmpty()
+                && node.getNodeData().isHasTaxonomy()
+                && ( ( node.getNodeData().getTaxonomy().getUris() != null ) && !node.getNodeData().getTaxonomy()
+                        .getUris().isEmpty() ) ) {
+            x += drawTaxonomyImage( node.getXcoord() + 2 + TreePanel.HALF_BOX_SIZE, node.getYcoord(), node, g );
+        }
+        if ( ( getControlPanel().isShowTaxonomyCode() || getControlPanel().isShowTaxonomyScientificNames() || getControlPanel()
+                .isShowTaxonomyCommonNames() )
+                && node.getNodeData().isHasTaxonomy() ) {
+            x += paintTaxonomy( g, node, is_in_found_nodes, to_pdf, to_graphics_file, x );
+        }
+        if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
+            g.setColor( Color.BLACK );
+        }
+        else if ( is_in_found_nodes ) {
+            g.setColor( getTreeColorSet().getFoundColor() );
+        }
+        else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
+            g.setColor( getTaxonomyBasedColor( node ) );
+        }
+        else if ( getOptions().isColorLabelsSameAsParentBranch() && getControlPanel().isColorBranches()
+                && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
+            g.setColor( PhylogenyMethods.getBranchColorValue( node ) );
+        }
+        else if ( to_pdf ) {
+            g.setColor( Color.BLACK );
+        }
+        else {
+            g.setColor( getTreeColorSet().getSequenceColor() );
+        }
+        _sb.setLength( 0 );
+        if ( node.isCollapse() && ( ( !node.isRoot() && !node.getParent().isCollapse() ) || node.isRoot() ) ) {
+            _sb.append( " [" );
+            _sb.append( node.getAllExternalDescendants().size() );
+            _sb.append( "]" );
+        }
+        if ( getControlPanel().isShowNodeNames() && ( node.getName().length() > 0 ) ) {
+            if ( _sb.length() > 0 ) {
+                _sb.append( " " );
+            }
+            _sb.append( node.getName() );
+        }
+        if ( node.getNodeData().isHasSequence() ) {
+            if ( getControlPanel().isShowGeneSymbols() && ( 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 ( _sb.length() > 0 ) {
+                    _sb.append( " " );
+                }
+                _sb.append( node.getNodeData().getSequence().getName() );
+            }
+            if ( getControlPanel().isShowSequenceAcc() && ( node.getNodeData().getSequence().getAccession() != null ) ) {
+                if ( _sb.length() > 0 ) {
+                    _sb.append( " " );
+                }
+                if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().getSource() ) ) {
+                    _sb.append( node.getNodeData().getSequence().getAccession().getSource() );
+                    _sb.append( ":" );
+                }
+                _sb.append( node.getNodeData().getSequence().getAccession().getValue() );
+            }
+        }
+        g.setFont( getTreeFontSet().getLargeFont() );
+        if ( is_in_found_nodes ) {
+            g.setFont( getTreeFontSet().getLargeFont().deriveFont( Font.BOLD ) );
+        }
+        double down_shift_factor = 3.0;
+        if ( !node.isExternal() && ( node.getNumberOfDescendants() == 1 ) ) {
+            down_shift_factor = 1;
+        }
+        // GUILHEM_BEG ______________
+        final double posX = node.getXcoord() + x + 2 + TreePanel.HALF_BOX_SIZE;
+        final double posY = ( node.getYcoord() + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ) );
+        final int CONFIDENCE_LEFT_MARGIN = 4;
+        final String sNodeText = _sb.toString();
+        if ( _control_panel.isShowSequenceRelations() && node.getNodeData().isHasSequence()
+                && ( _query_sequence != null ) ) {
+            int nodeTextBoundsWidth = 0;
+            if ( sNodeText.length() > 0 ) {
+                final Rectangle2D node_text_bounds = new TextLayout( sNodeText, g.getFont(), _frc ).getBounds(); //would like to remove this 'new', but how...
+                nodeTextBoundsWidth = ( int ) node_text_bounds.getWidth();
+            }
+            if ( node.getNodeData().getSequence().equals( _query_sequence ) ) {
+                if ( nodeTextBoundsWidth > 0 ) { // invert font color and background color to show that this is the query sequence
+                    g.fillRect( ( int ) posX - 1, ( int ) posY - 8, nodeTextBoundsWidth + 5, 11 );
+                    g.setColor( getTreeColorSet().getBackgroundColor() );
+                }
+            }
+            else {
+                final List<SequenceRelation> seqRelations = node.getNodeData().getSequence().getSequenceRelations();
+                for( final SequenceRelation seqRelation : seqRelations ) {
+                    final boolean fGotRelationWithQuery = ( seqRelation.getRef0().isEqual( _query_sequence ) || seqRelation
+                            .getRef1().isEqual( _query_sequence ) )
+                            && seqRelation.getType().equals( getControlPanel().getSequenceRelationTypeBox()
+                                    .getSelectedItem() );
+                    if ( fGotRelationWithQuery ) { // we will underline the text to show that this sequence is ortholog to the query
+                        final double linePosX = node.getXcoord() + 2 + TreePanel.HALF_BOX_SIZE;
+                        final String sConfidence = ( !getControlPanel().isShowSequenceRelationConfidence() || ( seqRelation
+                                .getConfidence() == null ) ) ? null : " (" + seqRelation.getConfidence().getValue()
+                                + ")";
+                        if ( sConfidence != null ) {
+                            double confidenceX = posX;
+                            if ( sNodeText.length() > 0 ) {
+                                confidenceX += new TextLayout( sNodeText, g.getFont(), _frc ).getBounds().getWidth()
+                                        + CONFIDENCE_LEFT_MARGIN;
+                            }
+                            if ( confidenceX > linePosX ) { // let's only display confidence value if we are already displaying at least one of Prot/Gene Name and Taxonomy Code 
+                                final int confidenceWidth = ( int ) new TextLayout( sConfidence, g.getFont(), _frc )
+                                        .getBounds().getWidth();
+                                TreePanel.drawString( sConfidence, confidenceX, posY, g );
+                                x += CONFIDENCE_LEFT_MARGIN + confidenceWidth;
+                            }
+                        }
+                        if ( x + nodeTextBoundsWidth > 0 ) /* we only underline if there is something displayed */
+                        {
+                            if ( nodeTextBoundsWidth == 0 ) {
+                                nodeTextBoundsWidth -= 3; /* the gap between taxonomy code and node name should not be underlined if nothing comes after it */
+                            }
+                            else {
+                                nodeTextBoundsWidth += 2;
+                            }
+                            g.drawLine( ( int ) linePosX + 1, 3 + ( int ) posY, ( int ) linePosX + x
+                                    + nodeTextBoundsWidth, 3 + ( int ) posY );
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        if ( sNodeText.length() > 0 ) {
+            TreePanel.drawString( sNodeText, posX, posY, g );
+        }
+        // GUILHEM_END _____________
+        // COMMENTED_OUT_BY_GUILHEM_BEG _______________
+        // TODO FIXME need to check this one!
+        //if ( _sb.length() > 0 ) {
+        //    TreePanel.drawString( _sb.toString(), node.getXcoord() + x + 2 + TreePanel.HALF_BOX_SIZE, node.getYcoord()
+        //            + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ), g );
+        //}
+        // COMMENTED_OUT_BY_GUILHEM_END ________________
+        if ( getControlPanel().isShowAnnotation() && node.getNodeData().isHasSequence()
+                && ( node.getNodeData().getSequence().getAnnotations() != null )
+                && ( !node.getNodeData().getSequence().getAnnotations().isEmpty() ) ) {
+            if ( _sb.length() > 0 ) {
+                x += getTreeFontSet()._fm_large.stringWidth( _sb.toString() ) + 5;
+            }
+            final Annotation ann = node.getNodeData().getSequence().getAnnotation( 0 );
+            if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
+                g.setColor( Color.BLACK );
+            }
+            else {
+                g.setColor( calculateColorForAnnotation( ann ) );
+            }
+            final String ann_str = ann.asSimpleText().toString();
+            TreePanel.drawString( ann_str, node.getXcoord() + x + 3 + TreePanel.HALF_BOX_SIZE, node.getYcoord()
+                    + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ), g );
+            _sb.setLength( 0 );
+            _sb.append( ann_str );
+        }
+        if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR )
+                || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE )
+                || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) ) {
+            if ( ( getControlPanel().isShowBinaryCharacters() || getControlPanel().isShowBinaryCharacterCounts() )
+                    && node.getNodeData().isHasBinaryCharacters() ) {
+                if ( _sb.length() > 0 ) {
+                    x += getTreeFontSet()._fm_large.stringWidth( _sb.toString() ) + 5;
+                }
+                if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
+                    g.setColor( Color.BLACK );
+                }
+                else {
+                    g.setColor( getTreeColorSet().getBinaryDomainCombinationsColor() );
+                }
+                if ( getControlPanel().isShowBinaryCharacters() ) {
+                    TreePanel.drawString( node.getNodeData().getBinaryCharacters().getPresentCharactersAsStringBuffer()
+                            .toString(), node.getXcoord() + x + 1 + TreePanel.HALF_BOX_SIZE, node.getYcoord()
+                            + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ), g );
+                    paintGainedAndLostCharacters( g, node, node.getNodeData().getBinaryCharacters()
+                            .getGainedCharactersAsStringBuffer().toString(), node.getNodeData().getBinaryCharacters()
+                            .getLostCharactersAsStringBuffer().toString() );
+                }
+                else {
+                    if ( DRAW_MEAN_COUNTS && node.isInternal() ) {
+                        final List<PhylogenyNode> ec = node.getAllExternalDescendants();
+                        double sum = 0;
+                        int count = 0;
+                        for( final PhylogenyNode phylogenyNode : ec ) {
+                            count++;
+                            if ( phylogenyNode.getNodeData().getBinaryCharacters() != null ) {
+                                sum += phylogenyNode.getNodeData().getBinaryCharacters().getPresentCount();
+                            }
+                        }
+                        final double mean = ForesterUtil.round( sum / count, 1 );
+                        TreePanel.drawString( " " + node.getNodeData().getBinaryCharacters().getPresentCount() + " ["
+                                + mean + "]", node.getXcoord() + x + 4 + TreePanel.HALF_BOX_SIZE, node.getYcoord()
+                                + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ), g );
+                    }
+                    else {
+                        TreePanel.drawString( " " + node.getNodeData().getBinaryCharacters().getPresentCount(), node
+                                .getXcoord()
+                                + x + 4 + TreePanel.HALF_BOX_SIZE, node.getYcoord()
+                                + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ), g );
+                    }
+                    paintGainedAndLostCharacters( g, node, "+"
+                            + node.getNodeData().getBinaryCharacters().getGainedCount(), "-"
+                            + node.getNodeData().getBinaryCharacters().getLostCount() );
+                }
+            }
+        }
+    }
+
+    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 paintNodeDataUnrootedCirc( final Graphics2D g,
+                                                  final PhylogenyNode node,
+                                                  final boolean to_pdf,
+                                                  final boolean to_graphics_file,
+                                                  final boolean radial_labels,
+                                                  final double ur_angle,
+                                                  final boolean is_in_found_nodes ) {
+        if ( isNodeDataInvisibleUnrootedCirc( node ) && !to_graphics_file && !to_pdf ) {
+            return;
+        }
+        if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
+            g.setColor( Color.BLACK );
+        }
+        else if ( is_in_found_nodes ) {
+            g.setColor( getTreeColorSet().getFoundColor() );
+        }
+        else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
+            g.setColor( getTaxonomyBasedColor( node ) );
+        }
+        else {
+            g.setColor( getTreeColorSet().getSequenceColor() );
+        }
+        _sb.setLength( 0 );
+        _sb.append( " " );
+        if ( node.getNodeData().isHasTaxonomy()
+                && ( getControlPanel().isShowTaxonomyCode() || getControlPanel().isShowTaxonomyScientificNames() || getControlPanel()
+                        .isShowTaxonomyCommonNames() ) ) {
+            final Taxonomy taxonomy = node.getNodeData().getTaxonomy();
+            if ( _control_panel.isShowTaxonomyCode() && !ForesterUtil.isEmpty( taxonomy.getTaxonomyCode() ) ) {
+                _sb.append( taxonomy.getTaxonomyCode() );
+                _sb.append( " " );
+            }
+            if ( _control_panel.isShowTaxonomyScientificNames() && _control_panel.isShowTaxonomyCommonNames() ) {
+                if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() )
+                        && !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
+                    _sb.append( taxonomy.getScientificName() );
+                    _sb.append( " (" );
+                    _sb.append( taxonomy.getCommonName() );
+                    _sb.append( ") " );
+                }
+                else if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() ) ) {
+                    _sb.append( taxonomy.getScientificName() );
+                    _sb.append( " " );
+                }
+                else if ( !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
+                    _sb.append( taxonomy.getCommonName() );
+                    _sb.append( " " );
+                }
+            }
+            else if ( _control_panel.isShowTaxonomyScientificNames() ) {
+                if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() ) ) {
+                    _sb.append( taxonomy.getScientificName() );
+                    _sb.append( " " );
+                }
+            }
+            else if ( _control_panel.isShowTaxonomyCommonNames() ) {
+                if ( !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
+                    _sb.append( taxonomy.getCommonName() );
+                    _sb.append( " " );
+                }
+            }
+        }
+        if ( node.isCollapse() && ( ( !node.isRoot() && !node.getParent().isCollapse() ) || node.isRoot() ) ) {
+            _sb.append( " [" );
+            _sb.append( node.getAllExternalDescendants().size() );
+            _sb.append( "]" );
+        }
+        if ( getControlPanel().isShowNodeNames() && ( node.getName().length() > 0 ) ) {
+            if ( _sb.length() > 0 ) {
+                _sb.append( " " );
+            }
+            _sb.append( node.getName() );
+        }
+        if ( node.getNodeData().isHasSequence() ) {
+            if ( getControlPanel().isShowSequenceAcc() && ( node.getNodeData().getSequence().getAccession() != null ) ) {
+                if ( _sb.length() > 0 ) {
+                    _sb.append( " " );
+                }
+                if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().getSource() ) ) {
+                    _sb.append( node.getNodeData().getSequence().getAccession().getSource() );
+                    _sb.append( ":" );
+                }
+                _sb.append( node.getNodeData().getSequence().getAccession().getValue() );
+            }
+            if ( getControlPanel().isShowGeneNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
+                if ( _sb.length() > 0 ) {
+                    _sb.append( " " );
+                }
+                _sb.append( node.getNodeData().getSequence().getName() );
+            }
+        }
+        g.setFont( getTreeFontSet().getLargeFont() );
+        if ( is_in_found_nodes ) {
+            g.setFont( getTreeFontSet().getLargeFont().deriveFont( Font.BOLD ) );
+        }
+        if ( _sb.length() > 1 ) {
+            final String sb_str = _sb.toString();
+            double m = 0;
+            if ( _graphics_type == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) {
+                m = _urt_nodeid_angle_map.get( node.getId() ) % TWO_PI;
+            }
+            else {
+                m = ( float ) ( ur_angle % TWO_PI );
+            }
+            _at = g.getTransform();
+            boolean need_to_reset = false;
+            final float x_coord = node.getXcoord();
+            final float y_coord = node.getYcoord() + ( getTreeFontSet()._fm_large.getAscent() / 3.0f );
+            if ( radial_labels ) {
+                need_to_reset = true;
+                boolean left = false;
+                if ( ( m > HALF_PI ) && ( m < ONEHALF_PI ) ) {
+                    m -= PI;
+                    left = true;
+                }
+                g.rotate( m, x_coord, node.getYcoord() );
+                if ( left ) {
+                    g.translate( -( getTreeFontSet()._fm_large.getStringBounds( sb_str, g ).getWidth() ), 0 );
+                }
+            }
+            else {
+                if ( ( m > HALF_PI ) && ( m < ONEHALF_PI ) ) {
+                    need_to_reset = true;
+                    g.translate( -getTreeFontSet()._fm_large.getStringBounds( sb_str, g ).getWidth(), 0 );
+                }
+            }
+            TreePanel.drawString( sb_str, x_coord, y_coord, g );
+            if ( need_to_reset ) {
+                g.setTransform( _at );
+            }
+        }
+    }
+
+    final private void paintNodeLite( final Graphics2D g, final PhylogenyNode node ) {
+        if ( node.isCollapse() ) {
+            if ( ( !node.isRoot() && !node.getParent().isCollapse() ) || node.isRoot() ) {
+                paintCollapsedNode( g, node, false, false, false );
+            }
+            return;
+        }
+        if ( isInFoundNodes( node ) ) {
+            g.setColor( getTreeColorSet().getFoundColor() );
+            drawRectFilled( node.getXSecondary() - 1, node.getYSecondary() - 1, 3, 3, g );
+        }
+        float new_x = 0;
+        if ( !node.isExternal() && !node.isCollapse() ) {
+            boolean first_child = true;
+            float y2 = 0.0f;
+            final int parent_max_branch_to_leaf = getMaxBranchesToLeaf( node );
+            for( int i = 0; i < node.getNumberOfDescendants(); ++i ) {
+                final PhylogenyNode child_node = node.getChildNode( i );
+                int factor_x;
+                if ( !isUniformBranchLengthsForCladogram() ) {
+                    factor_x = node.getNumberOfExternalNodes() - child_node.getNumberOfExternalNodes();
+                }
+                else {
+                    factor_x = parent_max_branch_to_leaf - getMaxBranchesToLeaf( child_node );
+                }
+                if ( first_child ) {
+                    first_child = false;
+                    y2 = node.getYSecondary()
+                            - ( getOvYDistance() * ( node.getNumberOfExternalNodes() - child_node
+                                    .getNumberOfExternalNodes() ) );
+                }
+                else {
+                    y2 += getOvYDistance() * child_node.getNumberOfExternalNodes();
+                }
+                final float x2 = calculateOvBranchLengthToParent( child_node, factor_x );
+                new_x = x2 + node.getXSecondary();
+                final float diff_y = node.getYSecondary() - y2;
+                final float diff_x = node.getXSecondary() - new_x;
+                if ( ( diff_y > 2 ) || ( diff_y < -2 ) || ( diff_x > 2 ) || ( diff_x < -2 ) ) {
+                    paintBranchLite( g, node.getXSecondary(), new_x, node.getYSecondary(), y2, child_node );
+                }
+                child_node.setXSecondary( new_x );
+                child_node.setYSecondary( y2 );
+                y2 += getOvYDistance() * child_node.getNumberOfExternalNodes();
+            }
+        }
+    }
+
+    final private void paintNodeRectangular( final Graphics2D g,
+                                             final PhylogenyNode node,
+                                             final boolean to_pdf,
+                                             final boolean dynamically_hide,
+                                             final int dynamic_hiding_factor,
+                                             final boolean to_graphics_file ) {
+        final boolean is_in_found_nodes = isInFoundNodes( node );
+        if ( node.isCollapse() ) {
+            if ( ( !node.isRoot() && !node.getParent().isCollapse() ) || node.isRoot() ) {
+                paintCollapsedNode( g, node, to_graphics_file, to_pdf, is_in_found_nodes );
+            }
+            return;
+        }
+        if ( node.isExternal() ) {
+            ++_external_node_index;
+        }
+        // Confidence values
+        if ( getControlPanel().isShowBootstrapValues()
+                && !node.isExternal()
+                && !node.isRoot()
+                && ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED )
+                        || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ) || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) )
+                && node.getBranchData().isHasConfidences() ) {
+            paintConfidenceValues( g, node, to_pdf, to_graphics_file );
+        }
+        // Draw a line to root:
+        if ( node.isRoot() && _phylogeny.isRooted() ) {
+            paintRootBranch( g, node.getXcoord(), node.getYcoord(), node, to_pdf, to_graphics_file );
+        }
+        float new_x = 0;
+        float new_x_min = Float.MAX_VALUE;
+        final boolean disallow_shortcutting = dynamic_hiding_factor < 40;
+        float min_dist = 1.5f;
+        if ( !disallow_shortcutting ) {
+            //   System.out.println( dynamic_hiding_factor );
+            if ( dynamic_hiding_factor > 4000 ) {
+                min_dist = 4;
+            }
+            else if ( dynamic_hiding_factor > 1000 ) {
+                min_dist = 3;
+            }
+            else if ( dynamic_hiding_factor > 100 ) {
+                min_dist = 2;
+            }
+        }
+        if ( !node.isExternal() && !node.isCollapse() ) {
+            boolean first_child = true;
+            float y2 = 0.0f;
+            final int parent_max_branch_to_leaf = getMaxBranchesToLeaf( node );
+            for( int i = 0; i < node.getNumberOfDescendants(); ++i ) {
+                final PhylogenyNode child_node = node.getChildNode( i );
+                int factor_x;
+                if ( !isUniformBranchLengthsForCladogram() ) {
+                    factor_x = node.getNumberOfExternalNodes() - child_node.getNumberOfExternalNodes();
+                }
+                else {
+                    factor_x = parent_max_branch_to_leaf - getMaxBranchesToLeaf( child_node );
+                }
+                if ( first_child ) {
+                    first_child = false;
+                    y2 = node.getYcoord()
+                            - ( _y_distance * ( node.getNumberOfExternalNodes() - child_node.getNumberOfExternalNodes() ) );
+                }
+                else {
+                    y2 += _y_distance * child_node.getNumberOfExternalNodes();
+                }
+                final float x2 = calculateBranchLengthToParent( child_node, factor_x );
+                new_x = x2 + node.getXcoord();
+                if ( dynamically_hide && ( x2 < new_x_min ) ) {
+                    new_x_min = x2;
+                }
+                final float diff_y = node.getYcoord() - y2;
+                final float diff_x = node.getXcoord() - new_x;
+                if ( disallow_shortcutting || ( diff_y > min_dist ) || ( diff_y < -min_dist ) || ( diff_x > min_dist )
+                        || ( diff_x < -min_dist ) || to_graphics_file || to_pdf ) {
+                    paintBranchRectangular( g,
+                                            node.getXcoord(),
+                                            new_x,
+                                            node.getYcoord(),
+                                            y2,
+                                            child_node,
+                                            to_pdf,
+                                            to_graphics_file );
+                }
+                child_node.setXcoord( new_x );
+                child_node.setYcoord( y2 );
+                y2 += _y_distance * child_node.getNumberOfExternalNodes();
+            }
+        }
+        if ( dynamically_hide
+                && !is_in_found_nodes
+                && ( ( node.isExternal() && ( _external_node_index % dynamic_hiding_factor != 1 ) ) || ( !node
+                        .isExternal() && ( ( new_x_min < 20 ) || ( _y_distance * node.getNumberOfExternalNodes() < getTreeFontSet()._fm_large
+                        .getHeight() ) ) ) ) ) {
+            return;
+        }
+        paintNodeData( g, node, to_graphics_file, to_pdf, is_in_found_nodes );
+        paintNodeWithRenderableData( g, node, to_graphics_file, to_pdf );
+    }
+
+    final private void paintNodeWithRenderableData( final Graphics2D g,
+                                                    final PhylogenyNode node,
+                                                    final boolean to_graphics_file,
+                                                    final boolean to_pdf ) {
+        if ( isNodeDataInvisible( node ) && !to_graphics_file ) {
+            return;
+        }
+        if ( ( !getControlPanel().isShowInternalData() && !node.isExternal() ) ) {
+            return;
+        }
+        if ( getControlPanel().isShowDomainArchitectures() && node.getNodeData().isHasSequence()
+                && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) {
+            RenderableDomainArchitecture rds = null;
+            if ( node.getNodeData().getSequence().getDomainArchitecture() instanceof RenderableDomainArchitecture ) {
+                try {
+                    rds = ( RenderableDomainArchitecture ) node.getNodeData().getSequence().getDomainArchitecture();
+                }
+                catch ( final ClassCastException cce ) {
+                    cce.printStackTrace();
+                    return;
+                }
+                rds.setRenderingHeight( 6 );
+                int x = 0;
+                if ( getControlPanel().isShowTaxonomyCode() && ( PhylogenyMethods.getSpecies( node ).length() > 0 ) ) {
+                    x += getTreeFontSet()._fm_large_italic.stringWidth( PhylogenyMethods.getSpecies( node ) + " " );
+                }
+                if ( getControlPanel().isShowNodeNames() && ( node.getName().length() > 0 ) ) {
+                    x += getTreeFontSet()._fm_large.stringWidth( node.getName() + " " );
+                }
+                rds.render( node.getXcoord() + x, node.getYcoord() - 3, g, this, to_pdf );
+            }
+        }
+        //////////////
+        if ( getControlPanel().isShowVectorData() && ( node.getNodeData().getVector() != null )
+                && ( node.getNodeData().getVector().size() > 0 ) && ( getStatisticsForExpressionValues() != null ) ) {
+            final RenderableVector rv = RenderableVector.createInstance( node.getNodeData().getVector(),
+                                                                         getStatisticsForExpressionValues(),
+                                                                         getConfiguration() );
+            int x = 0;
+            PhylogenyNode my_node = node;
+            if ( !getControlPanel().isDrawPhylogram() ) {
+                my_node = getPhylogeny().getFirstExternalNode();
+            }
+            if ( getControlPanel().isShowTaxonomyCode() && ( PhylogenyMethods.getSpecies( my_node ).length() > 0 ) ) {
+                x += getTreeFontSet()._fm_large_italic.stringWidth( PhylogenyMethods.getSpecies( my_node ) + " " );
+            }
+            if ( getControlPanel().isShowNodeNames() && ( my_node.getName().length() > 0 ) ) {
+                x += getTreeFontSet()._fm_large.stringWidth( my_node.getName() + " " );
+            }
+            rv.render( my_node.getXcoord() + x, node.getYcoord() - 5, g, this, to_pdf );
+        }
+        //////////////
+    }
+
+    final private void paintOvRectangle( final Graphics2D g ) {
+        final float w_ratio = ( float ) getWidth() / getVisibleRect().width;
+        final float h_ratio = ( float ) getHeight() / getVisibleRect().height;
+        final float x_ratio = ( float ) getWidth() / getVisibleRect().x;
+        final float y_ratio = ( float ) getHeight() / getVisibleRect().y;
+        final float width = getOvMaxWidth() / w_ratio;
+        final float height = getOvMaxHeight() / h_ratio;
+        final float x = getVisibleRect().x + getOvXPosition() + getOvMaxWidth() / x_ratio;
+        final float y = getVisibleRect().y + getOvYPosition() + getOvMaxHeight() / y_ratio;
+        g.setColor( getTreeColorSet().getFoundColor() );
+        getOvRectangle().setRect( x, y, width, height );
+        if ( ( width < 6 ) && ( height < 6 ) ) {
+            drawRectFilled( x, y, 6, 6, g );
+            getOvVirtualRectangle().setRect( x, y, 6, 6 );
+        }
+        else if ( width < 6 ) {
+            drawRectFilled( x, y, 6, height, g );
+            getOvVirtualRectangle().setRect( x, y, 6, height );
+        }
+        else if ( height < 6 ) {
+            drawRectFilled( x, y, width, 6, g );
+            getOvVirtualRectangle().setRect( x, y, width, 6 );
+        }
+        else {
+            drawRect( x, y, width, height, g );
+            if ( isInOvRect() ) {
+                drawRect( x + 1, y + 1, width - 2, height - 2, g );
+            }
+            getOvVirtualRectangle().setRect( x, y, width, height );
+        }
+    }
+
+    final void paintPhylogeny( final Graphics2D g,
+                               final boolean to_pdf,
+                               final boolean to_graphics_file,
+                               final int graphics_file_width,
+                               final int graphics_file_height,
+                               final int graphics_file_x,
+                               final int graphics_file_y ) {
+        /* GUILHEM_BEG */
+        // System.out.println( "p" + ( xxx++ ) );
+        _query_sequence = _control_panel.getSelectedQuerySequence();
+        /* GUILHEM_END */
+        // Color the background
+        if ( !to_pdf ) {
+            final Rectangle r = getVisibleRect();
+            if ( !getOptions().isBackgroundColorGradient() || getOptions().isPrintBlackAndWhite() ) {
+                g.setColor( getTreeColorSet().getBackgroundColor() );
+                if ( !to_graphics_file ) {
+                    g.fill( r );
+                }
+                else {
+                    if ( getOptions().isPrintBlackAndWhite() ) {
+                        g.setColor( Color.WHITE );
+                    }
+                    g.fillRect( graphics_file_x, graphics_file_y, graphics_file_width, graphics_file_height );
+                }
+            }
+            else {
+                if ( !to_graphics_file ) {
+                    g.setPaint( new GradientPaint( r.x, r.y, getTreeColorSet().getBackgroundColor(), r.x, r.y
+                            + r.height, getTreeColorSet().getBackgroundColorGradientBottom() ) );
+                    g.fill( r );
+                }
+                else {
+                    g.setPaint( new GradientPaint( graphics_file_x,
+                                                   graphics_file_y,
+                                                   getTreeColorSet().getBackgroundColor(),
+                                                   graphics_file_x,
+                                                   graphics_file_y + graphics_file_height,
+                                                   getTreeColorSet().getBackgroundColorGradientBottom() ) );
+                    g.fillRect( graphics_file_x, graphics_file_y, graphics_file_width, graphics_file_height );
+                }
+            }
+            g.setStroke( new BasicStroke( 1 ) );
+        }
+        else {
+            g.setStroke( new BasicStroke( getOptions().getPrintLineWidth() ) );
+        }
+        if ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
+                && ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
+            _external_node_index = 0;
+            // Position starting X of tree
+            if ( !_phylogeny.isRooted() /*|| ( _subtree_index > 0 )*/) {
+                _phylogeny.getRoot().setXcoord( TreePanel.MOVE );
+            }
+            else if ( ( _phylogeny.getRoot().getDistanceToParent() > 0.0 ) && getControlPanel().isDrawPhylogram() ) {
+                _phylogeny.getRoot().setXcoord( ( float ) ( TreePanel.MOVE + ( _phylogeny.getRoot()
+                        .getDistanceToParent() * getXcorrectionFactor() ) ) );
+            }
+            else {
+                _phylogeny.getRoot().setXcoord( TreePanel.MOVE + getXdistance() );
+            }
+            // Position starting Y of tree
+            _phylogeny.getRoot().setYcoord( ( getYdistance() * _phylogeny.getRoot().getNumberOfExternalNodes() )
+                    + ( TreePanel.MOVE / 2.0f ) );
+            final int dynamic_hiding_factor = ( int ) ( getTreeFontSet()._fm_large.getHeight() / ( 1.5 * getYdistance() ) );
+            if ( getControlPanel().isDynamicallyHideData() ) {
+                if ( dynamic_hiding_factor > 1 ) {
+                    getControlPanel().setDynamicHidingIsOn( true );
+                }
+                else {
+                    getControlPanel().setDynamicHidingIsOn( false );
+                }
+            }
+            final PhylogenyNodeIterator it;
+            for( it = _phylogeny.iteratorPreorder(); it.hasNext(); ) {
+                paintNodeRectangular( g, it.next(), to_pdf, getControlPanel().isDynamicallyHideData()
+                        && ( dynamic_hiding_factor > 1 ), dynamic_hiding_factor, to_graphics_file );
+            }
+            if ( getOptions().isShowScale() && getControlPanel().isDrawPhylogram() && ( getScaleDistance() > 0.0 ) ) {
+                if ( !( to_graphics_file || to_pdf ) ) {
+                    paintScale( g,
+                                getVisibleRect().x,
+                                getVisibleRect().y + getVisibleRect().height,
+                                to_pdf,
+                                to_graphics_file );
+                }
+                else {
+                    paintScale( g, graphics_file_x, graphics_file_y + graphics_file_height, to_pdf, to_graphics_file );
+                }
+            }
+            if ( getOptions().isShowOverview() && isOvOn() && !to_graphics_file && !to_pdf ) {
+                paintPhylogenyLite( g );
+            }
+        }
+        else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+            if ( getControlPanel().getDynamicallyHideData() != null ) {
+                getControlPanel().setDynamicHidingIsOn( false );
+            }
+            final double angle = getStartingAngle();
+            final boolean radial_labels = getOptions().getNodeLabelDirection() == NODE_LABEL_DIRECTION.RADIAL;
+            _dynamic_hiding_factor = 0;
+            if ( getControlPanel().isDynamicallyHideData() ) {
+                _dynamic_hiding_factor = ( int ) ( ( getTreeFontSet()._fm_large.getHeight() * 1.5 * getPhylogeny()
+                        .getNumberOfExternalNodes() ) / ( TWO_PI * 10 ) );
+            }
+            if ( getControlPanel().getDynamicallyHideData() != null ) {
+                if ( _dynamic_hiding_factor > 1 ) {
+                    getControlPanel().setDynamicHidingIsOn( true );
+                }
+                else {
+                    getControlPanel().setDynamicHidingIsOn( false );
+                }
+            }
+            paintUnrooted( _phylogeny.getRoot(),
+                           angle,
+                           ( float ) ( angle + 2 * Math.PI ),
+                           radial_labels,
+                           g,
+                           to_pdf,
+                           to_graphics_file );
+            if ( getOptions().isShowScale() ) {
+                if ( !( to_graphics_file || to_pdf ) ) {
+                    paintScale( g,
+                                getVisibleRect().x,
+                                getVisibleRect().y + getVisibleRect().height,
+                                to_pdf,
+                                to_graphics_file );
+                }
+                else {
+                    paintScale( g, graphics_file_x, graphics_file_y + graphics_file_height, to_pdf, to_graphics_file );
+                }
+            }
+            if ( getOptions().isShowOverview() && isOvOn() && !to_graphics_file && !to_pdf ) {
+                g.setColor( getTreeColorSet().getOvColor() );
+                paintUnrootedLite( _phylogeny.getRoot(),
+                                   angle,
+                                   angle + 2 * Math.PI,
+                                   g,
+                                   ( getUrtFactorOv() / ( getVisibleRect().width / getOvMaxWidth() ) ) );
+                paintOvRectangle( g );
+            }
+        }
+        else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) {
+            final int radius = ( int ) ( ( Math.min( getPreferredSize().getWidth(), getPreferredSize().getHeight() ) / 2 ) - ( MOVE + getLongestExtNodeInfo() ) );
+            final int d = radius + MOVE + getLongestExtNodeInfo();
+            _dynamic_hiding_factor = 0;
+            if ( getControlPanel().isDynamicallyHideData() && ( radius > 0 ) ) {
+                _dynamic_hiding_factor = ( int ) ( ( getTreeFontSet()._fm_large.getHeight() * 1.5 * getPhylogeny()
+                        .getNumberOfExternalNodes() ) / ( TWO_PI * radius ) );
+            }
+            if ( getControlPanel().getDynamicallyHideData() != null ) {
+                if ( _dynamic_hiding_factor > 1 ) {
+                    getControlPanel().setDynamicHidingIsOn( true );
+                }
+                else {
+                    getControlPanel().setDynamicHidingIsOn( false );
+                }
+            }
+            paintCircular( _phylogeny, getStartingAngle(), d, d, radius > 0 ? radius : 0, g, to_pdf, to_graphics_file );
+            if ( getOptions().isShowOverview() && isOvOn() && !to_graphics_file && !to_pdf ) {
+                final int radius_ov = ( int ) ( getOvMaxHeight() < getOvMaxWidth() ? getOvMaxHeight() / 2
+                        : getOvMaxWidth() / 2 );
+                double x_scale = 1.0;
+                double y_scale = 1.0;
+                int x_pos = getVisibleRect().x + getOvXPosition();
+                int y_pos = getVisibleRect().y + getOvYPosition();
+                if ( getWidth() > getHeight() ) {
+                    x_scale = ( double ) getHeight() / getWidth();
+                    x_pos = ForesterUtil.roundToInt( x_pos / x_scale );
+                }
+                else {
+                    y_scale = ( double ) getWidth() / getHeight();
+                    y_pos = ForesterUtil.roundToInt( y_pos / y_scale );
+                }
+                _at = g.getTransform();
+                g.scale( x_scale, y_scale );
+                paintCircularLite( _phylogeny,
+                                   getStartingAngle(),
+                                   x_pos + radius_ov,
+                                   y_pos + radius_ov,
+                                   ( int ) ( radius_ov - ( getLongestExtNodeInfo() / ( getVisibleRect().width / getOvRectangle()
+                                           .getWidth() ) ) ),
+                                   g );
+                g.setTransform( _at );
+                paintOvRectangle( g );
+            }
+        }
+    }
+
+    final private void paintPhylogenyLite( final Graphics2D g ) {
+        //System.out.println( getVisibleRect().x + " " + getVisibleRect().y );
+        _phylogeny
+                .getRoot()
+                .setXSecondary( ( float ) ( getVisibleRect().x + getOvXPosition() + ( MOVE / ( getVisibleRect().width / getOvRectangle()
+                        .getWidth() ) ) ) );
+        _phylogeny.getRoot().setYSecondary( ( getVisibleRect().y + getOvYStart() ) );
+        final PhylogenyNodeIterator it;
+        for( it = _phylogeny.iteratorPreorder(); it.hasNext(); ) {
+            paintNodeLite( g, it.next() );
+        }
+        paintOvRectangle( g );
+    }
+
+    /**
+     * Paint the root branch. (Differs from others because it will always be a
+     * single horizontal line).
+     * @param to_graphics_file 
+     * 
+     * @return new x1 value
+     */
+    final private void paintRootBranch( final Graphics2D g,
+                                        final float x1,
+                                        final float y1,
+                                        final PhylogenyNode root,
+                                        final boolean to_pdf,
+                                        final boolean to_graphics_file ) {
+        assignGraphicsForBranchWithColorForParentBranch( root, false, g, to_pdf, to_graphics_file );
+        float d = getXdistance();
+        if ( getControlPanel().isDrawPhylogram() && ( root.getDistanceToParent() > 0.0 ) ) {
+            d = ( float ) ( getXcorrectionFactor() * root.getDistanceToParent() );
+        }
+        if ( d < MIN_ROOT_LENGTH ) {
+            d = MIN_ROOT_LENGTH;
+        }
+        if ( !getControlPanel().isWidthBranches() || ( PhylogenyMethods.getBranchWidthValue( root ) == 1 ) ) {
+            drawLine( x1 - d, root.getYcoord(), x1, root.getYcoord(), g );
+        }
+        else {
+            final double w = PhylogenyMethods.getBranchWidthValue( root );
+            drawRectFilled( x1 - d, root.getYcoord() - ( w / 2 ), d, w, g );
+        }
+        paintNodeBox( x1, root.getYcoord(), root, g, to_pdf, to_graphics_file, isInFoundNodes( root ) );
+    }
+
+    final private void paintScale( final Graphics2D g,
+                                   int x1,
+                                   int y1,
+                                   final boolean to_pdf,
+                                   final boolean to_graphics_file ) {
+        x1 += MOVE;
+        final double x2 = x1 + ( getScaleDistance() * getXcorrectionFactor() );
+        y1 -= 12;
+        final int y2 = y1 - 8;
+        final int y3 = y1 - 4;
+        g.setFont( getTreeFontSet().getSmallFont() );
+        if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
+            g.setColor( Color.BLACK );
+        }
+        else {
+            g.setColor( getTreeColorSet().getBranchLengthColor() );
+        }
+        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 );
+        }
+    }
+
+    final private int paintTaxonomy( final Graphics2D g,
+                                     final PhylogenyNode node,
+                                     final boolean is_in_found_nodes,
+                                     final boolean to_pdf,
+                                     final boolean to_graphics_file,
+                                     final double x_shift ) {
+        final Taxonomy taxonomy = node.getNodeData().getTaxonomy();
+        g.setFont( getTreeFontSet().getLargeItalicFont() );
+        if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
+            g.setColor( Color.BLACK );
+        }
+        else if ( is_in_found_nodes ) {
+            g.setFont( getTreeFontSet().getLargeItalicFont().deriveFont( TreeFontSet.BOLD_AND_ITALIC ) );
+            g.setColor( getTreeColorSet().getFoundColor() );
+        }
+        else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
+            g.setColor( getTaxonomyBasedColor( node ) );
+        }
+        else if ( getOptions().isColorLabelsSameAsParentBranch() && getControlPanel().isColorBranches()
+                && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
+            g.setColor( PhylogenyMethods.getBranchColorValue( node ) );
+        }
+        else if ( to_pdf ) {
+            g.setColor( Color.BLACK );
+        }
+        else {
+            g.setColor( getTreeColorSet().getTaxonomyColor() );
+        }
+        final double start_x = node.getXcoord() + 3 + TreePanel.HALF_BOX_SIZE + x_shift;
+        final double start_y = node.getYcoord()
+                + ( getTreeFontSet()._fm_large.getAscent() / ( node.getNumberOfDescendants() == 1 ? 1 : 3.0 ) );
+        _sb.setLength( 0 );
+        if ( _control_panel.isShowTaxonomyCode() && !ForesterUtil.isEmpty( taxonomy.getTaxonomyCode() ) ) {
+            _sb.append( taxonomy.getTaxonomyCode() );
+            _sb.append( " " );
+        }
+        if ( _control_panel.isShowTaxonomyScientificNames() && _control_panel.isShowTaxonomyCommonNames() ) {
+            if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() )
+                    && !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
+                if ( getOptions().isAbbreviateScientificTaxonNames()
+                        && ( taxonomy.getScientificName().indexOf( ' ' ) > 0 ) ) {
+                    abbreviateScientificName( taxonomy.getScientificName() );
+                }
+                else {
+                    _sb.append( taxonomy.getScientificName() );
+                }
+                _sb.append( " (" );
+                _sb.append( taxonomy.getCommonName() );
+                _sb.append( ") " );
+            }
+            else if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() ) ) {
+                if ( getOptions().isAbbreviateScientificTaxonNames()
+                        && ( taxonomy.getScientificName().indexOf( ' ' ) > 0 ) ) {
+                    abbreviateScientificName( taxonomy.getScientificName() );
+                }
+                else {
+                    _sb.append( taxonomy.getScientificName() );
+                }
+                _sb.append( " " );
+            }
+            else if ( !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
+                _sb.append( taxonomy.getCommonName() );
+                _sb.append( " " );
+            }
+        }
+        else if ( _control_panel.isShowTaxonomyScientificNames() ) {
+            if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() ) ) {
+                if ( getOptions().isAbbreviateScientificTaxonNames()
+                        && ( taxonomy.getScientificName().indexOf( ' ' ) > 0 ) ) {
+                    abbreviateScientificName( taxonomy.getScientificName() );
+                }
+                else {
+                    _sb.append( taxonomy.getScientificName() );
+                }
+                _sb.append( " " );
+            }
+        }
+        else if ( _control_panel.isShowTaxonomyCommonNames() ) {
+            if ( !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
+                _sb.append( taxonomy.getCommonName() );
+                _sb.append( " " );
+            }
+        }
+        final String label = _sb.toString();
+        /* GUILHEM_BEG */
+        if ( ( label.length() > 0 ) && ( node.getNodeData().isHasSequence() )
+                && node.getNodeData().getSequence().equals( _query_sequence ) ) {
+            // invert font color and background color to show that this is the query sequence
+            final Rectangle2D nodeTextBounds = new TextLayout( label, g.getFont(), new FontRenderContext( null,
+                                                                                                          false,
+                                                                                                          false ) )
+                    .getBounds();
+            g.fillRect( ( int ) start_x - 1, ( int ) start_y - 8, ( int ) nodeTextBounds.getWidth() + 4, 11 );
+            g.setColor( getTreeColorSet().getBackgroundColor() );
+        }
+        /* GUILHEM_END */
+        TreePanel.drawString( label, start_x, start_y, g );
+        if ( is_in_found_nodes ) {
+            return getTreeFontSet()._fm_large_italic_bold.stringWidth( label );
+        }
+        else {
+            return getTreeFontSet()._fm_large_italic.stringWidth( label );
+        }
+    }
+
+    private void abbreviateScientificName( final String sn ) {
+        final String[] a = sn.split( "\\s+" );
+        _sb.append( a[ 0 ].substring( 0, 1 ) );
+        _sb.append( a[ 1 ].substring( 0, 2 ) );
+        if ( a.length > 2 ) {
+            for( int i = 2; i < a.length; i++ ) {
+                _sb.append( " " );
+                _sb.append( a[ i ] );
+            }
+        }
+    }
+
+    final private void paintUnrooted( final PhylogenyNode n,
+                                      final double low_angle,
+                                      final double high_angle,
+                                      final boolean radial_labels,
+                                      final Graphics2D g,
+                                      final boolean to_pdf,
+                                      final boolean to_graphics_file ) {
+        if ( n.isRoot() ) {
+            n.setXcoord( getWidth() / 2 );
+            n.setYcoord( getHeight() / 2 );
+            paintNodeBox( n.getXcoord(), n.getYcoord(), n, g, to_pdf, to_graphics_file, isInFoundNodes( n ) );
+        }
+        if ( n.isExternal() ) {
+            paintNodeDataUnrootedCirc( g,
+                                       n,
+                                       to_pdf,
+                                       to_graphics_file,
+                                       radial_labels,
+                                       ( high_angle + low_angle ) / 2,
+                                       isInFoundNodes( n ) );
+            return;
+        }
+        final float num_enclosed = n.getNumberOfExternalNodes();
+        final float x = n.getXcoord();
+        final float y = n.getYcoord();
+        double current_angle = low_angle;
+        // final boolean n_below = n.getYcoord() < getVisibleRect().getMinY() - 20;
+        // final boolean n_above = n.getYcoord() > getVisibleRect().getMaxY() + 20;
+        // final boolean n_left = n.getXcoord() < getVisibleRect().getMinX() - 20;
+        // final boolean n_right = n.getXcoord() > getVisibleRect().getMaxX() + 20;
+        for( int i = 0; i < n.getNumberOfDescendants(); ++i ) {
+            final PhylogenyNode desc = n.getChildNode( i );
+            ///  if ( ( ( n_below ) & ( desc.getYcoord() < getVisibleRect().getMinY() - 20 ) )
+            //          || ( ( n_above ) & ( desc.getYcoord() > getVisibleRect().getMaxY() + 20 ) )
+            //         || ( ( n_left ) & ( desc.getXcoord() < getVisibleRect().getMinX() - 20 ) )
+            //          || ( ( n_right ) & ( desc.getXcoord() > getVisibleRect().getMaxX() + 20 ) ) ) {
+            //     continue;
+            // }
+            //if ( ( desc.getYcoord() > n.getYcoord() ) && ( n.getYcoord() > getVisibleRect().getMaxY() - 20 ) ) {
+            //    continue;
+            //}
+            //if ( ( desc.getYcoord() < n.getYcoord() ) && ( n.getYcoord() < getVisibleRect().getMinY() + 20 ) ) {
+            //    continue;
+            // }
+            final int desc_num_enclosed = desc.getNumberOfExternalNodes();
+            final double arc_size = ( desc_num_enclosed / num_enclosed ) * ( high_angle - low_angle );
+            float length;
+            if ( isPhyHasBranchLengths() && getControlPanel().isDrawPhylogram() ) {
+                if ( desc.getDistanceToParent() < 0 ) {
+                    length = 0;
+                }
+                else {
+                    length = ( float ) ( desc.getDistanceToParent() * getUrtFactor() );
+                }
+            }
+            else {
+                length = getUrtFactor();
+            }
+            final double mid_angle = current_angle + arc_size / 2;
+            final float new_x = ( float ) ( x + Math.cos( mid_angle ) * length );
+            final float new_y = ( float ) ( y + Math.sin( mid_angle ) * length );
+            desc.setXcoord( new_x );
+            desc.setYcoord( new_y );
+            paintNodeBox( new_x, new_y, desc, g, to_pdf, to_graphics_file, isInFoundNodes( desc ) );
+            paintUnrooted( desc, current_angle, current_angle + arc_size, radial_labels, g, to_pdf, to_graphics_file );
+            current_angle += arc_size;
+            assignGraphicsForBranchWithColorForParentBranch( desc, false, g, to_pdf, to_graphics_file );
+            drawLine( x, y, new_x, new_y, g );
+        }
+    }
+
+    final private void paintUnrootedLite( final PhylogenyNode n,
+                                          final double low_angle,
+                                          final double high_angle,
+                                          final Graphics2D g,
+                                          final float urt_ov_factor ) {
+        if ( n.isRoot() ) {
+            final int x_pos = ( int ) ( getVisibleRect().x + getOvXPosition() + getOvMaxWidth() / 2 );
+            final int y_pos = ( int ) ( getVisibleRect().y + getOvYPosition() + getOvMaxHeight() / 2 );
+            n.setXSecondary( x_pos );
+            n.setYSecondary( y_pos );
+        }
+        if ( n.isExternal() ) {
+            return;
+        }
+        final float num_enclosed = n.getNumberOfExternalNodes();
+        final float x = n.getXSecondary();
+        final float y = n.getYSecondary();
+        double current_angle = low_angle;
+        for( int i = 0; i < n.getNumberOfDescendants(); ++i ) {
+            final PhylogenyNode desc = n.getChildNode( i );
+            final int desc_num_enclosed = desc.getNumberOfExternalNodes();
+            final double arc_size = ( desc_num_enclosed / num_enclosed ) * ( high_angle - low_angle );
+            float length;
+            if ( isPhyHasBranchLengths() && getControlPanel().isDrawPhylogram() ) {
+                if ( desc.getDistanceToParent() < 0 ) {
+                    length = 0;
+                }
+                else {
+                    length = ( float ) ( desc.getDistanceToParent() * urt_ov_factor );
+                }
+            }
+            else {
+                length = urt_ov_factor;
+            }
+            final double mid_angle = current_angle + arc_size / 2;
+            final float new_x = ( float ) ( x + Math.cos( mid_angle ) * length );
+            final float new_y = ( float ) ( y + Math.sin( mid_angle ) * length );
+            desc.setXSecondary( new_x );
+            desc.setYSecondary( new_y );
+            if ( isInFoundNodes( desc ) ) {
+                g.setColor( getTreeColorSet().getFoundColor() );
+                drawRectFilled( desc.getXSecondary() - 1, desc.getYSecondary() - 1, 3, 3, g );
+                g.setColor( getTreeColorSet().getOvColor() );
+            }
+            paintUnrootedLite( desc, current_angle, current_angle + arc_size, g, urt_ov_factor );
+            current_angle += arc_size;
+            drawLine( x, y, new_x, new_y, g );
+        }
+    }
+
+    final private void pasteSubtree( final PhylogenyNode node ) {
+        if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+            errorMessageNoCutCopyPasteInUnrootedDisplay();
+            return;
+        }
+        if ( ( getCutOrCopiedTree() == null ) || getCutOrCopiedTree().isEmpty() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "No tree in buffer (need to copy or cut a subtree first)",
+                                           "Attempt to paste with empty buffer",
+                                           JOptionPane.ERROR_MESSAGE );
+            return;
+        }
+        final String label = getASimpleTextRepresentationOfANode( getCutOrCopiedTree().getRoot() );
+        final Object[] options = { "As sibling", "As descendant", "Cancel" };
+        final int r = JOptionPane.showOptionDialog( this,
+                                                    "How to paste subtree" + label + "?",
+                                                    "Paste Subtree",
+                                                    JOptionPane.CLOSED_OPTION,
+                                                    JOptionPane.QUESTION_MESSAGE,
+                                                    null,
+                                                    options,
+                                                    options[ 2 ] );
+        boolean paste_as_sibling = true;
+        if ( r == 1 ) {
+            paste_as_sibling = false;
+        }
+        else if ( r != 0 ) {
+            return;
+        }
+        final Phylogeny buffer_phy = getCutOrCopiedTree().copy();
+        buffer_phy.setAllNodesToNotCollapse();
+        buffer_phy.preOrderReId();
+        buffer_phy.setRooted( true );
+        boolean need_to_show_whole = false;
+        if ( paste_as_sibling ) {
+            if ( node.isRoot() ) {
+                JOptionPane.showMessageDialog( this,
+                                               "Cannot paste sibling to root",
+                                               "Attempt to paste sibling to root",
+                                               JOptionPane.ERROR_MESSAGE );
+                return;
+            }
+            buffer_phy.addAsSibling( node );
+        }
+        else {
+            if ( ( node.getNumberOfExternalNodes() == 1 ) && node.isRoot() ) {
+                need_to_show_whole = true;
+                _phylogeny = buffer_phy;
+            }
+            else {
+                buffer_phy.addAsChild( node );
+            }
+        }
+        if ( getCopiedAndPastedNodes() == null ) {
+            setCopiedAndPastedNodes( new HashSet<Integer>() );
+        }
+        final List<PhylogenyNode> nodes = PhylogenyMethods.obtainAllNodesAsList( buffer_phy );
+        final Set<Integer> node_ids = new HashSet<Integer>( nodes.size() );
+        for( final PhylogenyNode n : nodes ) {
+            node_ids.add( n.getId() );
+        }
+        node_ids.add( node.getId() );
+        getCopiedAndPastedNodes().addAll( node_ids );
+        _phylogeny.externalNodesHaveChanged();
+        _phylogeny.hashIDs();
+        _phylogeny.recalculateNumberOfExternalDescendants( true );
+        resetNodeIdToDistToLeafMap();
+        setEdited( true );
+        if ( need_to_show_whole ) {
+            getControlPanel().showWhole();
+        }
+        repaint();
+    }
+
+    final public int print( final Graphics g, final PageFormat page_format, final int page_index )
+            throws PrinterException {
+        if ( page_index > 0 ) {
+            return ( NO_SUCH_PAGE );
+        }
+        else {
+            final Graphics2D g2d = ( Graphics2D ) g;
+            g2d.translate( page_format.getImageableX(), page_format.getImageableY() );
+            // Turn off double buffering !?
+            paintPhylogeny( g2d, true, false, 0, 0, 0, 0 );
+            // Turn double buffering back on !?
+            return ( PAGE_EXISTS );
+        }
+    }
+
+    final void recalculateMaxDistanceToRoot() {
+        _max_distance_to_root = PhylogenyMethods.calculateMaxDistanceToRoot( getPhylogeny() );
+    }
+
+    /**
+     * Remove all edit-node frames
+     */
+    final void removeAllEditNodeJFrames() {
+        for( int i = 0; i <= ( TreePanel.MAX_NODE_FRAMES - 1 ); i++ ) {
+            if ( _node_frames[ i ] != null ) {
+                _node_frames[ i ].dispose();
+                _node_frames[ i ] = null;
+            }
+        }
+        _node_frame_index = 0;
+    }
+
+    /**
+     * Remove a node-edit frame.
+     */
+    final void removeEditNodeFrame( final int i ) {
+        _node_frame_index--;
+        _node_frames[ i ] = null;
+        if ( i < _node_frame_index ) {
+            for( int j = 0; j < _node_frame_index - 1; j++ ) {
+                _node_frames[ j ] = _node_frames[ j + 1 ];
+            }
+            _node_frames[ _node_frame_index ] = null;
+        }
+    }
+
+    final void reRoot( final PhylogenyNode node ) {
+        if ( !getPhylogeny().isRerootable() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "This is not rerootable",
+                                           "Not rerootable",
+                                           JOptionPane.WARNING_MESSAGE );
+            return;
+        }
+        if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Cannot reroot in unrooted display type",
+                                           "Attempt to reroot tree in unrooted display",
+                                           JOptionPane.WARNING_MESSAGE );
+            return;
+        }
+        getPhylogeny().reRoot( node );
+        getPhylogeny().recalculateNumberOfExternalDescendants( true );
+        resetNodeIdToDistToLeafMap();
+        resetPreferredSize();
+        getMainPanel().adjustJScrollPane();
+        repaint();
+        if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) {
+            getControlPanel().showWhole();
+        }
+    }
+
+    final void resetNodeIdToDistToLeafMap() {
+        _nodeid_dist_to_leaf = new HashMap<Integer, Short>();
+    }
+
+    final void resetPreferredSize() {
+        if ( ( getPhylogeny() == null ) || getPhylogeny().isEmpty() ) {
+            return;
+        }
+        int x = 0;
+        int y = 0;
+        y = TreePanel.MOVE
+                + ForesterUtil.roundToInt( getYdistance() * getPhylogeny().getRoot().getNumberOfExternalNodes() * 2 );
+        if ( getControlPanel().isDrawPhylogram() ) {
+            x = TreePanel.MOVE
+                    + getLongestExtNodeInfo()
+                    + ForesterUtil
+                            .roundToInt( ( getXcorrectionFactor() * getPhylogeny().getHeight() ) + getXdistance() );
+        }
+        else {
+            if ( !isNonLinedUpCladogram() && !isUniformBranchLengthsForCladogram() ) {
+                x = TreePanel.MOVE
+                        + getLongestExtNodeInfo()
+                        + ForesterUtil.roundToInt( getXdistance()
+                                * ( getPhylogeny().getRoot().getNumberOfExternalNodes() + 2 ) );
+            }
+            else {
+                x = TreePanel.MOVE
+                        + getLongestExtNodeInfo()
+                        + ForesterUtil.roundToInt( getXdistance()
+                                * ( PhylogenyMethods.calculateMaxDepth( getPhylogeny() ) + 1 ) );
+            }
+        }
+        setPreferredSize( new Dimension( x, y ) );
+    }
+
+    final void setArrowCursor() {
+        setCursor( ARROW_CURSOR );
+        repaint();
+    }
+
+    final void setControlPanel( final ControlPanel atv_control ) {
+        _control_panel = atv_control;
+    }
+
+    final private void setCopiedAndPastedNodes( final Set<Integer> nodeIds ) {
+        getMainPanel().setCopiedAndPastedNodes( nodeIds );
+    }
+
+    final private void setCutOrCopiedTree( final Phylogeny cut_or_copied_tree ) {
+        getMainPanel().setCutOrCopiedTree( cut_or_copied_tree );
+    }
+
+    final void setEdited( final boolean edited ) {
+        _edited = edited;
+    }
+
+    final void setFoundNodes( final Set<Integer> found_nodes ) {
+        _found_nodes = found_nodes;
+    }
+
+    final private void setInOv( final boolean in_ov ) {
+        _in_ov = in_ov;
+    }
+
+    final void setInOvRect( final boolean in_ov_rect ) {
+        _in_ov_rect = in_ov_rect;
+    }
+
+    final void setLargeFonts() {
+        getTreeFontSet().largeFonts();
+    }
+
+    final void setLastMouseDragPointX( final float x ) {
+        _last_drag_point_x = x;
+    }
+
+    final void setLastMouseDragPointY( final float y ) {
+        _last_drag_point_y = y;
+    }
+
+    final void setLongestExtNodeInfo( final int i ) {
+        _longest_ext_node_info = i;
+    }
+
+    final void setMediumFonts() {
+        getTreeFontSet().mediumFonts();
+    }
+
+    final private void setOvMaxHeight( final float ov_max_height ) {
+        _ov_max_height = ov_max_height;
+    }
+
+    final private void setOvMaxWidth( final float ov_max_width ) {
+        _ov_max_width = ov_max_width;
+    }
+
+    final void setOvOn( final boolean ov_on ) {
+        _ov_on = ov_on;
+    }
+
+    final private void setOvXcorrectionFactor( final float f ) {
+        _ov_x_correction_factor = f;
+    }
+
+    final private void setOvXDistance( final float ov_x_distance ) {
+        _ov_x_distance = ov_x_distance;
+    }
+
+    final private void setOvXPosition( final int ov_x_position ) {
+        _ov_x_position = ov_x_position;
+    }
+
+    final private void setOvYDistance( final float ov_y_distance ) {
+        _ov_y_distance = ov_y_distance;
+    }
+
+    final private void setOvYPosition( final int ov_y_position ) {
+        _ov_y_position = ov_y_position;
+    }
+
+    final private void setOvYStart( final int ov_y_start ) {
+        _ov_y_start = ov_y_start;
+    }
+
+    /**
+     * Set parameters for printing the displayed tree
+     * 
+     * @param x
+     * @param y
+     */
+    final void setParametersForPainting( final int x, final int y, final boolean recalc_longest_ext_node_info ) {
+        // updateStyle(); not needed?
+        if ( ( _phylogeny != null ) && !_phylogeny.isEmpty() ) {
+            initNodeData();
+            if ( recalc_longest_ext_node_info ) {
+                calculateLongestExtNodeInfo();
+            }
+            int ext_nodes = _phylogeny.getRoot().getNumberOfExternalNodes();
+            final int max_depth = PhylogenyMethods.calculateMaxDepth( _phylogeny );
+            if ( ext_nodes == 1 ) {
+                ext_nodes = max_depth;
+                if ( ext_nodes < 1 ) {
+                    ext_nodes = 1;
+                }
+            }
+            updateOvSizes();
+            float xdist = 0;
+            float ov_xdist = 0;
+            if ( !isNonLinedUpCladogram() && !isUniformBranchLengthsForCladogram() ) {
+                xdist = ( float ) ( ( x - getLongestExtNodeInfo() - TreePanel.MOVE ) / ( ext_nodes + 3.0 ) );
+                ov_xdist = ( float ) ( getOvMaxWidth() / ( ext_nodes + 3.0 ) );
+            }
+            else {
+                xdist = ( ( x - getLongestExtNodeInfo() - TreePanel.MOVE ) / ( max_depth + 1 ) );
+                ov_xdist = ( getOvMaxWidth() / ( max_depth + 1 ) );
+            }
+            float ydist = ( float ) ( ( y - TreePanel.MOVE ) / ( ext_nodes * 2.0 ) );
+            if ( xdist < 0.0 ) {
+                xdist = 0.0f;
+            }
+            if ( ov_xdist < 0.0 ) {
+                ov_xdist = 0.0f;
+            }
+            if ( ydist < 0.0 ) {
+                ydist = 0.0f;
+            }
+            setXdistance( xdist );
+            setYdistance( ydist );
+            setOvXDistance( ov_xdist );
+            final double height = _phylogeny.getHeight();
+            if ( height > 0 ) {
+                final float corr = ( float ) ( ( x - TreePanel.MOVE - getLongestExtNodeInfo() - getXdistance() ) / height );
+                setXcorrectionFactor( corr > 0 ? corr : 0 );
+                final float ov_corr = ( float ) ( ( getOvMaxWidth() - getOvXDistance() ) / height );
+                setOvXcorrectionFactor( ov_corr > 0 ? ov_corr : 0 );
+            }
+            else {
+                setXcorrectionFactor( 0 );
+                setOvXcorrectionFactor( 0 );
+            }
+            _circ_max_depth = max_depth;
+            setUpUrtFactor();
+        }
+    }
+
+    final void setPhylogenyGraphicsType( final PHYLOGENY_GRAPHICS_TYPE graphics_type ) {
+        _graphics_type = graphics_type;
+        setTextAntialias();
+    }
+
+    final private void setScaleDistance( final double scale_distance ) {
+        _scale_distance = scale_distance;
+    }
+
+    final private void setScaleLabel( final String scale_label ) {
+        _scale_label = scale_label;
+    }
+
+    final void setSmallFonts() {
+        getTreeFontSet().smallFonts();
+    }
+
+    final void setStartingAngle( final double starting_angle ) {
+        _urt_starting_angle = starting_angle;
+    }
+
+    final void setSuperTinyFonts() {
+        getTreeFontSet().superTinyFonts();
+    }
+
+    final void setTextAntialias() {
+        if ( ( _phylogeny != null ) && !_phylogeny.isEmpty() ) {
+            if ( _phylogeny.getNumberOfExternalNodes() <= LIMIT_FOR_HQ_RENDERING ) {
+                _rendering_hints.put( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY );
+            }
+            else {
+                _rendering_hints.put( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED );
+            }
+        }
+        if ( getMainPanel().getOptions().isAntialiasScreen() ) {
+            if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ) {
+                _rendering_hints.put( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
+            }
+            else {
+                _rendering_hints.put( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
+            }
+            try {
+                _rendering_hints.put( RenderingHints.KEY_TEXT_ANTIALIASING,
+                                      RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB );
+            }
+            catch ( final Throwable e ) {
+                _rendering_hints.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
+            }
+        }
+        else {
+            _rendering_hints.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF );
+            _rendering_hints.put( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
+        }
+    }
+
+    final void setTinyFonts() {
+        getTreeFontSet().tinyFonts();
+    }
+
+    /**
+     * Set a phylogeny tree.
+     * 
+     * @param t
+     *            an instance of a Phylogeny
+     */
+    final void setTree( final Phylogeny t ) {
+        _phylogeny = t;
+    }
+
+    final void setTreeFile( final File treefile ) {
+        _treefile = treefile;
+    }
+
+    final private void setUpUrtFactor() {
+        final int d = getVisibleRect().width < getVisibleRect().height ? getVisibleRect().width
+                : getVisibleRect().height;
+        if ( isPhyHasBranchLengths() && getControlPanel().isDrawPhylogram() ) {
+            setUrtFactor( ( float ) ( d / ( 2 * getMaxDistanceToRoot() ) ) );
+        }
+        else {
+            final int max_depth = _circ_max_depth;
+            if ( max_depth > 0 ) {
+                setUrtFactor( d / ( 2 * max_depth ) );
+            }
+            else {
+                setUrtFactor( d / 2 );
+            }
+        }
+        setUrtFactorOv( getUrtFactor() );
+    }
+
+    final private void setUrtFactor( final float urt_factor ) {
+        _urt_factor = urt_factor;
+    }
+
+    final private void setUrtFactorOv( final float urt_factor_ov ) {
+        _urt_factor_ov = urt_factor_ov;
+    }
+
+    final void setWaitCursor() {
+        setCursor( WAIT_CURSOR );
+        repaint();
+    }
+
+    final void setXcorrectionFactor( final float f ) {
+        _x_correction_factor = f;
+    }
+
+    final void setXdistance( final float x ) {
+        _x_distance = x;
+    }
+
+    final void setYdistance( final float y ) {
+        _y_distance = y;
+    }
+
+    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() ) {
+                _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() ) ) {
+                    lines++;
+                    boolean enc_data = false;
+                    final Taxonomy tax = node.getNodeData().getTaxonomy();
+                    if ( _popup_buffer.length() > 0 ) {
+                        _popup_buffer.append( "\n" );
+                    }
+                    if ( !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
+                        _popup_buffer.append( "[" );
+                        _popup_buffer.append( tax.getTaxonomyCode() );
+                        _popup_buffer.append( "]" );
+                        enc_data = true;
+                    }
+                    if ( !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
+                        if ( enc_data ) {
+                            _popup_buffer.append( " " );
+                        }
+                        _popup_buffer.append( tax.getScientificName() );
+                        enc_data = true;
+                    }
+                    if ( !ForesterUtil.isEmpty( tax.getCommonName() ) ) {
+                        if ( enc_data ) {
+                            _popup_buffer.append( " (" );
+                        }
+                        else {
+                            _popup_buffer.append( "(" );
+                        }
+                        _popup_buffer.append( tax.getCommonName() );
+                        _popup_buffer.append( ")" );
+                        enc_data = true;
+                    }
+                    if ( !ForesterUtil.isEmpty( tax.getAuthority() ) ) {
+                        if ( enc_data ) {
+                            _popup_buffer.append( " (" );
+                        }
+                        else {
+                            _popup_buffer.append( "(" );
+                        }
+                        _popup_buffer.append( tax.getAuthority() );
+                        _popup_buffer.append( ")" );
+                        enc_data = true;
+                    }
+                    if ( !ForesterUtil.isEmpty( tax.getRank() ) ) {
+                        if ( enc_data ) {
+                            _popup_buffer.append( " [" );
+                        }
+                        else {
+                            _popup_buffer.append( "[" );
+                        }
+                        _popup_buffer.append( tax.getRank() );
+                        _popup_buffer.append( "]" );
+                        enc_data = true;
+                    }
+                    if ( tax.getSynonyms().size() > 0 ) {
+                        if ( enc_data ) {
+                            _popup_buffer.append( " " );
+                        }
+                        _popup_buffer.append( "[" );
+                        int counter = 1;
+                        for( final String syn : tax.getSynonyms() ) {
+                            if ( !ForesterUtil.isEmpty( syn ) ) {
+                                enc_data = true;
+                                _popup_buffer.append( syn );
+                                if ( counter < tax.getSynonyms().size() ) {
+                                    _popup_buffer.append( ", " );
+                                }
+                            }
+                            counter++;
+                        }
+                        _popup_buffer.append( "]" );
+                    }
+                    if ( !enc_data ) {
+                        if ( ( tax.getIdentifier() != null ) && !ForesterUtil.isEmpty( tax.getIdentifier().getValue() ) ) {
+                            if ( !ForesterUtil.isEmpty( tax.getIdentifier().getProvider() ) ) {
+                                _popup_buffer.append( "[" );
+                                _popup_buffer.append( tax.getIdentifier().getProvider() );
+                                _popup_buffer.append( "] " );
+                            }
+                            _popup_buffer.append( tax.getIdentifier().getValue() );
+                        }
+                    }
+                }
+                if ( node.getNodeData().isHasSequence() && !isSequenceEmpty( node.getNodeData().getSequence() ) ) {
+                    lines++;
+                    boolean enc_data = false;
+                    if ( _popup_buffer.length() > 0 ) {
+                        _popup_buffer.append( "\n" );
+                    }
+                    final Sequence seq = node.getNodeData().getSequence();
+                    if ( seq.getAccession() != null ) {
+                        _popup_buffer.append( "[" );
+                        if ( !ForesterUtil.isEmpty( seq.getAccession().getSource() ) ) {
+                            _popup_buffer.append( seq.getAccession().getSource() );
+                            _popup_buffer.append( ":" );
+                        }
+                        _popup_buffer.append( seq.getAccession().getValue() );
+                        _popup_buffer.append( "]" );
+                        enc_data = true;
+                    }
+                    if ( !ForesterUtil.isEmpty( seq.getSymbol() ) ) {
+                        if ( enc_data ) {
+                            _popup_buffer.append( " [" );
+                        }
+                        else {
+                            _popup_buffer.append( "[" );
+                        }
+                        _popup_buffer.append( seq.getSymbol() );
+                        _popup_buffer.append( "]" );
+                        enc_data = true;
+                    }
+                    if ( !ForesterUtil.isEmpty( seq.getName() ) ) {
+                        if ( enc_data ) {
+                            _popup_buffer.append( " " );
+                        }
+                        _popup_buffer.append( seq.getName() );
+                    }
+                }
+                if ( node.getNodeData().isHasDate() ) {
+                    lines++;
+                    if ( _popup_buffer.length() > 0 ) {
+                        _popup_buffer.append( "\n" );
+                    }
+                    _popup_buffer.append( node.getNodeData().getDate().asSimpleText() );
+                }
+                if ( node.getNodeData().isHasDistribution() ) {
+                    lines++;
+                    if ( _popup_buffer.length() > 0 ) {
+                        _popup_buffer.append( "\n" );
+                    }
+                    _popup_buffer.append( node.getNodeData().getDistribution().asSimpleText() );
+                }
+                if ( node.getBranchData().isHasConfidences() ) {
+                    final List<Confidence> confs = node.getBranchData().getConfidences();
+                    for( final Confidence confidence : confs ) {
+                        lines++;
+                        if ( _popup_buffer.length() > 0 ) {
+                            _popup_buffer.append( "\n" );
+                        }
+                        if ( !ForesterUtil.isEmpty( confidence.getType() ) ) {
+                            _popup_buffer.append( "[" );
+                            _popup_buffer.append( confidence.getType() );
+                            _popup_buffer.append( "] " );
+                        }
+                        _popup_buffer.append( FORMATTER_CONFIDENCE.format( ForesterUtil
+                                .round( confidence.getValue(), getOptions()
+                                        .getNumberOfDigitsAfterCommaForConfidenceValues() ) ) );
+                    }
+                }
+                if ( _popup_buffer.length() > 0 ) {
+                    if ( !getConfiguration().isUseNativeUI() ) {
+                        _rollover_popup
+                                .setBorder( BorderFactory.createLineBorder( getTreeColorSet().getBranchColor() ) );
+                        _rollover_popup.setBackground( getTreeColorSet().getBackgroundColor() );
+                        if ( isInFoundNodes( node ) ) {
+                            _rollover_popup.setForeground( getTreeColorSet().getFoundColor() );
+                        }
+                        else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
+                            _rollover_popup.setForeground( getTaxonomyBasedColor( node ) );
+                        }
+                        else {
+                            _rollover_popup.setForeground( getTreeColorSet().getSequenceColor() );
+                        }
+                    }
+                    else {
+                        _rollover_popup.setBorder( BorderFactory.createLineBorder( Color.BLACK ) );
+                    }
+                    _rollover_popup.setText( _popup_buffer.toString() );
+                    _node_desc_popup = PopupFactory.getSharedInstance().getPopup( null,
+                                                                                  _rollover_popup,
+                                                                                  e.getLocationOnScreen().x + 10,
+                                                                                  e.getLocationOnScreen().y
+                                                                                          - ( lines * 20 ) );
+                    _node_desc_popup.show();
+                }
+            }
+        }
+        catch ( final Exception ex ) {
+            // Do nothing.
+        }
+    }
+
+    final private void showNodeEditFrame( final PhylogenyNode n ) {
+        if ( _node_frame_index < TreePanel.MAX_NODE_FRAMES ) {
+            // pop up edit box for single node
+            _node_frames[ _node_frame_index ] = new NodeFrame( n, _phylogeny, this, _node_frame_index, "" );
+            _node_frame_index++;
+        }
+        else {
+            JOptionPane.showMessageDialog( this, "too many node windows are open" );
+        }
+    }
+
+    final private void showNodeFrame( final PhylogenyNode n ) {
+        if ( _node_frame_index < TreePanel.MAX_NODE_FRAMES ) {
+            // pop up edit box for single node
+            _node_frames[ _node_frame_index ] = new NodeFrame( n, _phylogeny, this, _node_frame_index );
+            _node_frame_index++;
+        }
+        else {
+            JOptionPane.showMessageDialog( this, "too many node windows are open" );
+        }
+    }
+
+    final void subTree( final PhylogenyNode node ) {
+        if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Cannot get a sub/super tree in unrooted display",
+                                           "Attempt to get sub/super tree in unrooted display",
+                                           JOptionPane.WARNING_MESSAGE );
+            return;
+        }
+        if ( node.isExternal() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Cannot get a subtree of a external node",
+                                           "Attempt to get subtree of external node",
+                                           JOptionPane.WARNING_MESSAGE );
+            return;
+        }
+        if ( node.isRoot() && !isCurrentTreeIsSubtree() ) {
+            JOptionPane.showMessageDialog( this,
+                                           "Cannot get a subtree of the root node",
+                                           "Attempt to get subtree of root node",
+                                           JOptionPane.WARNING_MESSAGE );
+            return;
+        }
+        if ( !node.isExternal() && !node.isRoot() && ( _subtree_index <= ( TreePanel.MAX_SUBTREES - 1 ) ) ) {
+            _sub_phylogenies[ _subtree_index ] = _phylogeny;
+            _sub_phylogenies_temp_roots[ _subtree_index ] = node;
+            ++_subtree_index;
+            _phylogeny = subTree( node, _phylogeny );
+            updateSubSuperTreeButton();
+        }
+        else if ( node.isRoot() && isCurrentTreeIsSubtree() ) {
+            superTree();
+        }
+        _main_panel.getControlPanel().showWhole();
+        repaint();
+    }
+
+    final boolean isCurrentTreeIsSubtree() {
+        return ( _subtree_index > 0 );
+    }
+
+    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 void superTree() {
+        final PhylogenyNode temp_root = _sub_phylogenies_temp_roots[ _subtree_index - 1 ];
+        for( final PhylogenyNode n : temp_root.getDescendants() ) {
+            n.setParent( temp_root );
+        }
+        _sub_phylogenies[ _subtree_index ] = null;
+        _sub_phylogenies_temp_roots[ _subtree_index ] = null;
+        _phylogeny = _sub_phylogenies[ --_subtree_index ];
+        updateSubSuperTreeButton();
+    }
+
+    final void swap( final PhylogenyNode node ) {
+        if ( !node.isExternal() ) {
+            _phylogeny.swapChildren( node );
+        }
+        repaint();
+    }
+
+    final private void switchDisplaygetPhylogenyGraphicsType() {
+        switch ( getPhylogenyGraphicsType() ) {
+            case RECTANGULAR:
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE );
+                getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE );
+                break;
+            case EURO_STYLE:
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.ROUNDED );
+                getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.ROUNDED );
+                break;
+            case ROUNDED:
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CURVED );
+                getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CURVED );
+                break;
+            case CURVED:
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR );
+                getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR );
+                break;
+            case TRIANGULAR:
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CONVEX );
+                getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CONVEX );
+                break;
+            case CONVEX:
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
+                getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
+                break;
+            case UNROOTED:
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CIRCULAR );
+                getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CIRCULAR );
+                break;
+            case CIRCULAR:
+                setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
+                getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
+                break;
+            default:
+                throw new RuntimeException( "unkwnown display type: " + getPhylogenyGraphicsType() );
+        }
+        if ( getControlPanel().getDynamicallyHideData() != null ) {
+            if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
+                getControlPanel().getDynamicallyHideData().setEnabled( false );
+            }
+            else {
+                getControlPanel().getDynamicallyHideData().setEnabled( true );
+            }
+        }
+        if ( isPhyHasBranchLengths() && ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
+            getControlPanel().setDrawPhylogramEnabled( true );
+        }
+        else {
+            getControlPanel().setDrawPhylogramEnabled( false );
+        }
+        if ( getMainPanel().getMainFrame() == null ) {
+            // Must be "E" applet version.
+            ( ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet() )
+                    .setSelectedTypeInTypeMenu( getPhylogenyGraphicsType() );
+        }
+        else {
+            getMainPanel().getMainFrame().setSelectedTypeInTypeMenu( getPhylogenyGraphicsType() );
+        }
+    }
+
+    final void taxColor() {
+        if ( ( _phylogeny == null ) || ( _phylogeny.getNumberOfExternalNodes() < 2 ) ) {
+            return;
+        }
+        setWaitCursor();
+        Util.colorPhylogenyAccordingToExternalTaxonomy( _phylogeny, this );
+        _control_panel.setColorBranches( true );
+        if ( _control_panel.getColorBranchesCb() != null ) {
+            _control_panel.getColorBranchesCb().setSelected( true );
+        }
+        setArrowCursor();
+        repaint();
+    }
+
+    final void updateOvSettings() {
+        switch ( getOptions().getOvPlacement() ) {
+            case LOWER_LEFT:
+                setOvXPosition( OV_BORDER );
+                setOvYPosition( ForesterUtil.roundToInt( getVisibleRect().height - OV_BORDER - getOvMaxHeight() ) );
+                setOvYStart( ForesterUtil.roundToInt( getOvYPosition() + ( getOvMaxHeight() / 2 ) ) );
+                break;
+            case LOWER_RIGHT:
+                setOvXPosition( ForesterUtil.roundToInt( getVisibleRect().width - OV_BORDER - getOvMaxWidth() ) );
+                setOvYPosition( ForesterUtil.roundToInt( getVisibleRect().height - OV_BORDER - getOvMaxHeight() ) );
+                setOvYStart( ForesterUtil.roundToInt( getOvYPosition() + ( getOvMaxHeight() / 2 ) ) );
+                break;
+            case UPPER_RIGHT:
+                setOvXPosition( ForesterUtil.roundToInt( getVisibleRect().width - OV_BORDER - getOvMaxWidth() ) );
+                setOvYPosition( OV_BORDER );
+                setOvYStart( ForesterUtil.roundToInt( OV_BORDER + ( getOvMaxHeight() / 2 ) ) );
+                break;
+            default:
+                setOvXPosition( OV_BORDER );
+                setOvYPosition( OV_BORDER );
+                setOvYStart( ForesterUtil.roundToInt( OV_BORDER + ( getOvMaxHeight() / 2 ) ) );
+                break;
+        }
+    }
+
+    final void updateOvSizes() {
+        if ( ( getWidth() > 1.05 * getVisibleRect().width ) || ( getHeight() > 1.05 * getVisibleRect().height ) ) {
+            setOvOn( true );
+            float l = getLongestExtNodeInfo();
+            final float w_ratio = getOvMaxWidth() / getWidth();
+            l *= w_ratio;
+            final int ext_nodes = _phylogeny.getRoot().getNumberOfExternalNodes();
+            setOvYDistance( getOvMaxHeight() / ( 2 * ext_nodes ) );
+            float ov_xdist = 0;
+            if ( !isNonLinedUpCladogram() && !isUniformBranchLengthsForCladogram() ) {
+                ov_xdist = ( ( getOvMaxWidth() - l ) / ( ext_nodes ) );
+            }
+            else {
+                ov_xdist = ( ( getOvMaxWidth() - l ) / ( PhylogenyMethods.calculateMaxDepth( _phylogeny ) ) );
+            }
+            float ydist = ( float ) ( ( getOvMaxWidth() / ( ext_nodes * 2.0 ) ) );
+            if ( ov_xdist < 0.0 ) {
+                ov_xdist = 0.0f;
+            }
+            if ( ydist < 0.0 ) {
+                ydist = 0.0f;
+            }
+            setOvXDistance( ov_xdist );
+            final double height = _phylogeny.getHeight();
+            if ( height > 0 ) {
+                final float ov_corr = ( float ) ( ( ( getOvMaxWidth() - l ) - getOvXDistance() ) / height );
+                setOvXcorrectionFactor( ov_corr > 0 ? ov_corr : 0 );
+            }
+            else {
+                setOvXcorrectionFactor( 0 );
+            }
+        }
+        else {
+            setOvOn( false );
+        }
+    }
+
+    final void updateSubSuperTreeButton() {
+        if ( _subtree_index < 1 ) {
+            getControlPanel().deactivateButtonToReturnToSuperTree();
+        }
+        else {
+            getControlPanel().activateButtonToReturnToSuperTree( _subtree_index );
+        }
+    }
+
+    final void zoomInDomainStructure() {
+        if ( _domain_structure_width < 2000 ) {
+            _domain_structure_width *= 1.2;
+        }
+    }
+
+    final void zoomOutDomainStructure() {
+        if ( _domain_structure_width > 20 ) {
+            _domain_structure_width *= 0.8;
+        }
+    }
+
+    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 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 ) );
+    }
+
+    void setStatisticsForExpressionValues( final DescriptiveStatistics statistics_for_expression_values ) {
+        _statistics_for_vector_data = statistics_for_expression_values;
+    }
+
+    DescriptiveStatistics getStatisticsForExpressionValues() {
+        return _statistics_for_vector_data;
+    }
+
+    final private class SubtreeColorizationActionListener implements ActionListener {
+
+        JColorChooser _chooser;
+        PhylogenyNode _node;
+
+        SubtreeColorizationActionListener( final JColorChooser chooser, final PhylogenyNode node ) {
+            _chooser = chooser;
+            _node = node;
+        }
+
+        @Override
+        public void actionPerformed( final ActionEvent e ) {
+            final Color c = _chooser.getColor();
+            if ( c != null ) {
+                colorizeSubtree( c, _node );
+            }
+        }
+    }
+
+    synchronized void setImageMap( final Hashtable<String, BufferedImage> image_map ) {
+        getMainPanel().setImageMap( image_map );
+    }
+
+    synchronized Hashtable<String, BufferedImage> getImageMap() {
+        return getMainPanel().getImageMap();
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/UrlTreeReader.java b/forester/java/src/org/forester/archaeopteryx/UrlTreeReader.java
new file mode 100644 (file)
index 0000000..729d569
--- /dev/null
@@ -0,0 +1,242 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Date;
+
+import javax.swing.JOptionPane;
+
+import org.forester.archaeopteryx.webservices.PhylogeniesWebserviceClient;
+import org.forester.archaeopteryx.webservices.WebserviceUtil;
+import org.forester.archaeopteryx.webservices.WebservicesManager;
+import org.forester.io.parsers.PhylogenyParser;
+import org.forester.io.parsers.nexus.NexusPhylogeniesParser;
+import org.forester.io.parsers.nhx.NHXParser;
+import org.forester.io.parsers.phyloxml.PhyloXmlParser;
+import org.forester.io.parsers.tol.TolParser;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.phylogeny.data.Identifier;
+import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
+import org.forester.phylogeny.factories.PhylogenyFactory;
+import org.forester.util.ForesterUtil;
+
+public class UrlTreeReader implements Runnable {
+
+    private final MainFrame _main_frame;
+    private final int       _webservice_client_index;
+
+    UrlTreeReader( final MainFrame mf, final int webservice_client_index ) {
+        _main_frame = mf;
+        _webservice_client_index = webservice_client_index;
+    }
+
+    synchronized void readPhylogeniesFromWebservice() {
+        final long start_time = new Date().getTime();
+        URL url = null;
+        Phylogeny[] trees = null;
+        final WebservicesManager webservices_manager = WebservicesManager.getInstance();
+        final PhylogeniesWebserviceClient client = webservices_manager
+                .getAvailablePhylogeniesWebserviceClient( _webservice_client_index );
+        String identifier = JOptionPane.showInputDialog( _main_frame, client.getInstructions() + "\n(Reference: "
+                + client.getReference() + ")", client.getDescription(), JOptionPane.QUESTION_MESSAGE );
+        if ( ( identifier != null ) && ( identifier.trim().length() > 0 ) ) {
+            identifier = identifier.trim();
+            if ( client.isQueryInteger() ) {
+                identifier = identifier.replaceAll( "^\\D+", "" );
+                int id = -1;
+                try {
+                    id = Integer.parseInt( identifier );
+                }
+                catch ( final NumberFormatException e ) {
+                    id = -1;
+                }
+                if ( id < 1 ) {
+                    JOptionPane.showMessageDialog( _main_frame,
+                                                   "Identifier is expected to be a number",
+                                                   "Can not open URL",
+                                                   JOptionPane.ERROR_MESSAGE );
+                    return;
+                }
+                identifier = id + "";
+            }
+            try {
+                String url_str = client.getUrl();
+                url_str = url_str.replaceFirst( PhylogeniesWebserviceClient.QUERY_PLACEHOLDER, identifier );
+                url = new URL( url_str );
+                PhylogenyParser parser = null;
+                switch ( client.getReturnFormat() ) {
+                    case TOL_XML_RESPONSE:
+                        parser = new TolParser();
+                        break;
+                    case NEXUS:
+                        parser = new NexusPhylogeniesParser();
+                        ( ( NexusPhylogeniesParser ) parser ).setReplaceUnderscores( true );
+                        break;
+                    case NH:
+                        parser = new NHXParser();
+                        ( ( NHXParser ) parser ).setTaxonomyExtraction( ForesterUtil.TAXONOMY_EXTRACTION.NO );
+                        ( ( NHXParser ) parser ).setReplaceUnderscores( true );
+                        ( ( NHXParser ) parser ).setGuessRootedness( true );
+                        break;
+                    case NH_EXTRACT_TAXONOMY:
+                        parser = new NHXParser();
+                        ( ( NHXParser ) parser )
+                                .setTaxonomyExtraction( ForesterUtil.TAXONOMY_EXTRACTION.PFAM_STYLE_ONLY );
+                        ( ( NHXParser ) parser ).setReplaceUnderscores( false );
+                        ( ( NHXParser ) parser ).setGuessRootedness( true );
+                        break;
+                    case PFAM:
+                        parser = new NHXParser();
+                        ( ( NHXParser ) parser )
+                                .setTaxonomyExtraction( ForesterUtil.TAXONOMY_EXTRACTION.PFAM_STYLE_ONLY );
+                        ( ( NHXParser ) parser ).setReplaceUnderscores( false );
+                        ( ( NHXParser ) parser ).setGuessRootedness( true );
+                        break;
+                    case NHX:
+                        parser = new NHXParser();
+                        ( ( NHXParser ) parser ).setTaxonomyExtraction( ForesterUtil.TAXONOMY_EXTRACTION.NO );
+                        ( ( NHXParser ) parser ).setReplaceUnderscores( false );
+                        ( ( NHXParser ) parser ).setGuessRootedness( true );
+                        break;
+                    case PHYLOXML:
+                        parser = new PhyloXmlParser();
+                        break;
+                    default:
+                        throw new IllegalArgumentException( "unknown format: " + client.getReturnFormat() );
+                }
+                if ( _main_frame.getMainPanel().getCurrentTreePanel() != null ) {
+                    _main_frame.getMainPanel().getCurrentTreePanel().setWaitCursor();
+                }
+                else {
+                    _main_frame.getMainPanel().setWaitCursor();
+                }
+                final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance();
+                trees = factory.create( url.openStream(), parser );
+            }
+            catch ( final MalformedURLException e ) {
+                JOptionPane.showMessageDialog( _main_frame,
+                                               "Malformed URL: " + url + "\n" + e.getLocalizedMessage(),
+                                               "Malformed URL",
+                                               JOptionPane.ERROR_MESSAGE );
+            }
+            catch ( final IOException e ) {
+                JOptionPane.showMessageDialog( _main_frame, "Could not read from " + url + "\n"
+                        + e.getLocalizedMessage(), "Failed to read tree from " + client.getName() + " for "
+                        + identifier, JOptionPane.ERROR_MESSAGE );
+            }
+            catch ( final NumberFormatException e ) {
+                JOptionPane.showMessageDialog( _main_frame, "Could not read from " + url + "\n"
+                        + e.getLocalizedMessage(), "Failed to read tree from " + client.getName() + " for "
+                        + identifier, JOptionPane.ERROR_MESSAGE );
+            }
+            catch ( final Exception e ) {
+                e.printStackTrace();
+                JOptionPane.showMessageDialog( _main_frame,
+                                               e.getLocalizedMessage(),
+                                               "Unexpected Exception",
+                                               JOptionPane.ERROR_MESSAGE );
+            }
+            finally {
+                if ( _main_frame.getCurrentTreePanel() != null ) {
+                    _main_frame.getCurrentTreePanel().setArrowCursor();
+                }
+                else {
+                    _main_frame.getMainPanel().setArrowCursor();
+                }
+            }
+            if ( ( trees != null ) && ( trees.length > 0 ) ) {
+                for( final Phylogeny phylogeny : trees ) {
+                    if ( !phylogeny.isEmpty() ) {
+                        if ( client.getName().equals( WebserviceUtil.TREE_FAM_NAME ) ) {
+                            phylogeny.setRerootable( false );
+                            phylogeny.setRooted( true );
+                        }
+                        if ( client.getName().equals( WebserviceUtil.PFAM_NAME ) ) {
+                            phylogeny.setRerootable( false );
+                            phylogeny.setRooted( true );
+                            ForesterUtil.transferInternalNodeNamesToConfidence( phylogeny );
+                        }
+                        if ( client.getProcessingInstructions() != null ) {
+                            WebserviceUtil.processInstructions( client, phylogeny );
+                        }
+                        if ( client.getNodeField() != null ) {
+                            ForesterUtil.transferNodeNameToField( phylogeny, client.getNodeField() );
+                        }
+                        phylogeny.setIdentifier( new Identifier( identifier, client.getName() ) );
+                        _main_frame.getJMenuBar().remove( _main_frame.getHelpMenu() );
+                        _main_frame.getMenuBarOfMainFrame().add( _main_frame.getHelpMenu() );
+                        _main_frame.getMainPanel().addPhylogenyInNewTab( phylogeny,
+                                                                         _main_frame.getConfiguration(),
+                                                                         new File( url.getFile() ).getName(),
+                                                                         url.toString() );
+                        String my_name_for_file = "";
+                        if ( !ForesterUtil.isEmpty( phylogeny.getName() ) ) {
+                            my_name_for_file = new String( phylogeny.getName() ).replaceAll( " ", "_" );
+                        }
+                        else if ( phylogeny.getIdentifier() != null ) {
+                            final StringBuffer sb = new StringBuffer();
+                            if ( !ForesterUtil.isEmpty( phylogeny.getIdentifier().getProvider() ) ) {
+                                sb.append( phylogeny.getIdentifier().getProvider() );
+                                sb.append( "_" );
+                            }
+                            sb.append( phylogeny.getIdentifier().getValue() );
+                            my_name_for_file = new String( sb.toString().replaceAll( " ", "_" ) );
+                        }
+                        _main_frame.getMainPanel().getCurrentTreePanel().setTreeFile( new File( my_name_for_file ) );
+                        Util.lookAtSomeTreePropertiesForAptxControlSettings( phylogeny, _main_frame.getMainPanel()
+                                .getControlPanel(), _main_frame.getConfiguration() );
+                        _main_frame.getMainPanel().getControlPanel().showWhole();
+                    }
+                }
+            }
+            _main_frame.getContentPane().repaint();
+            if ( ( ( trees != null ) && ( trees.length > 0 ) ) && ( ( new Date().getTime() - start_time ) > 20000 ) ) {
+                try {
+                    JOptionPane.showMessageDialog( null,
+                                                   ForesterUtil.wordWrap( "Successfully read in " + trees.length
+                                                           + " evolutionry tree(s) from [" + url + "]", 80 ),
+                                                   "Success",
+                                                   JOptionPane.INFORMATION_MESSAGE );
+                }
+                catch ( final Exception e ) {
+                    // Not important if this fails, do nothing.
+                }
+                _main_frame.getContentPane().repaint();
+            }
+        }
+        _main_frame.activateSaveAllIfNeeded();
+        System.gc();
+    }
+
+    @Override
+    public void run() {
+        readPhylogeniesFromWebservice();
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/Util.java b/forester/java/src/org/forester/archaeopteryx/Util.java
new file mode 100644 (file)
index 0000000..3f7a50e
--- /dev/null
@@ -0,0 +1,779 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics2D;
+import java.awt.GraphicsEnvironment;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URL;
+import java.text.ParseException;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.imageio.IIOImage;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.stream.ImageOutputStream;
+import javax.swing.JApplet;
+import javax.swing.JOptionPane;
+import javax.swing.text.MaskFormatter;
+
+import org.forester.io.parsers.PhylogenyParser;
+import org.forester.io.parsers.tol.TolParser;
+import org.forester.io.parsers.util.PhylogenyParserException;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.phylogeny.PhylogenyMethods;
+import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.BranchColor;
+import org.forester.phylogeny.data.Taxonomy;
+import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
+import org.forester.phylogeny.factories.PhylogenyFactory;
+import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
+import org.forester.phylogeny.iterators.PreorderTreeIterator;
+import org.forester.util.ForesterUtil;
+
+final class Util {
+
+    private final static String[] AVAILABLE_FONT_FAMILIES_SORTED = GraphicsEnvironment.getLocalGraphicsEnvironment()
+                                                                         .getAvailableFontFamilyNames();
+    static {
+        Arrays.sort( AVAILABLE_FONT_FAMILIES_SORTED );
+    }
+
+    public static MaskFormatter createMaskFormatter( final String s ) {
+        MaskFormatter formatter = null;
+        try {
+            formatter = new MaskFormatter( s );
+        }
+        catch ( final ParseException e ) {
+            throw new IllegalArgumentException( e );
+        }
+        return formatter;
+    }
+
+    final static void addPhylogeniesToTabs( final Phylogeny[] phys,
+                                            final String default_name,
+                                            final String full_path,
+                                            final Configuration configuration,
+                                            final MainPanel main_panel ) {
+        if ( phys.length > Constants.MAX_TREES_TO_LOAD ) {
+            JOptionPane.showMessageDialog( main_panel, "Attempt to load " + phys.length
+                    + " phylogenies,\ngoing to load only the first " + Constants.MAX_TREES_TO_LOAD, Constants.PRG_NAME
+                    + " more than " + Constants.MAX_TREES_TO_LOAD + " phylogenies", JOptionPane.WARNING_MESSAGE );
+        }
+        int i = 1;
+        for( final Phylogeny phy : phys ) {
+            if ( !phy.isEmpty() ) {
+                if ( i <= Constants.MAX_TREES_TO_LOAD ) {
+                    String my_name = "";
+                    String my_name_for_file = "";
+                    if ( phys.length > 1 ) {
+                        if ( !ForesterUtil.isEmpty( default_name ) ) {
+                            my_name = new String( default_name );
+                        }
+                        if ( !ForesterUtil.isEmpty( full_path ) ) {
+                            my_name_for_file = new String( full_path );
+                        }
+                        else if ( !ForesterUtil.isEmpty( default_name ) ) {
+                            my_name_for_file = new String( default_name );
+                        }
+                        String suffix = "";
+                        if ( my_name_for_file.indexOf( '.' ) > 0 ) {
+                            suffix = my_name_for_file.substring( my_name_for_file.lastIndexOf( '.' ), my_name_for_file
+                                    .length() );
+                            my_name_for_file = my_name_for_file.substring( 0, my_name_for_file.lastIndexOf( '.' ) );
+                        }
+                        if ( !ForesterUtil.isEmpty( my_name_for_file ) ) {
+                            my_name_for_file += "_";
+                        }
+                        if ( !ForesterUtil.isEmpty( phy.getName() ) ) {
+                            my_name_for_file += phy.getName().replaceAll( " ", "_" );
+                        }
+                        else if ( phy.getIdentifier() != null ) {
+                            final StringBuffer sb = new StringBuffer();
+                            if ( !ForesterUtil.isEmpty( phy.getIdentifier().getProvider() ) ) {
+                                sb.append( phy.getIdentifier().getProvider() );
+                                sb.append( "_" );
+                            }
+                            sb.append( phy.getIdentifier().getValue() );
+                            my_name_for_file += sb;
+                        }
+                        else {
+                            my_name_for_file += i;
+                        }
+                        if ( !ForesterUtil.isEmpty( my_name ) && ForesterUtil.isEmpty( phy.getName() )
+                                && ( phy.getIdentifier() == null ) ) {
+                            my_name = my_name + " [" + i + "]";
+                        }
+                        if ( !ForesterUtil.isEmpty( suffix ) ) {
+                            my_name_for_file += suffix;
+                        }
+                    }
+                    else {
+                        if ( !ForesterUtil.isEmpty( default_name ) ) {
+                            my_name = new String( default_name );
+                        }
+                        my_name_for_file = "";
+                        if ( !ForesterUtil.isEmpty( full_path ) ) {
+                            my_name_for_file = new String( full_path );
+                        }
+                        else if ( !ForesterUtil.isEmpty( default_name ) ) {
+                            my_name_for_file = new String( default_name );
+                        }
+                        if ( ForesterUtil.isEmpty( my_name_for_file ) ) {
+                            if ( !ForesterUtil.isEmpty( phy.getName() ) ) {
+                                my_name_for_file = new String( phy.getName() ).replaceAll( " ", "_" );
+                            }
+                            else if ( phy.getIdentifier() != null ) {
+                                final StringBuffer sb = new StringBuffer();
+                                if ( !ForesterUtil.isEmpty( phy.getIdentifier().getProvider() ) ) {
+                                    sb.append( phy.getIdentifier().getProvider() );
+                                    sb.append( "_" );
+                                }
+                                sb.append( phy.getIdentifier().getValue() );
+                                my_name_for_file = new String( sb.toString().replaceAll( " ", "_" ) );
+                            }
+                        }
+                    }
+                    main_panel.addPhylogenyInNewTab( phy, configuration, my_name, full_path );
+                    main_panel.getCurrentTreePanel().setTreeFile( new File( my_name_for_file ) );
+                    lookAtSomeTreePropertiesForAptxControlSettings( phy, main_panel.getControlPanel(), configuration );
+                    ++i;
+                }
+            }
+        }
+    }
+
+    final static void addPhylogenyToPanel( final Phylogeny[] phys,
+                                           final Configuration configuration,
+                                           final MainPanel main_panel ) {
+        final Phylogeny phy = phys[ 0 ];
+        main_panel.addPhylogenyInPanel( phy, configuration );
+        lookAtSomeTreePropertiesForAptxControlSettings( phy, main_panel.getControlPanel(), configuration );
+    }
+
+    final static Color calculateColorFromString( final String str ) {
+        final String species_uc = str.toUpperCase();
+        char first = species_uc.charAt( 0 );
+        char second = ' ';
+        char third = ' ';
+        if ( species_uc.length() > 1 ) {
+            second = species_uc.charAt( 1 );
+            if ( species_uc.length() > 2 ) {
+                if ( species_uc.indexOf( " " ) > 0 ) {
+                    third = species_uc.charAt( species_uc.indexOf( " " ) + 1 );
+                }
+                else {
+                    third = species_uc.charAt( 2 );
+                }
+            }
+        }
+        first = Util.normalizeCharForRGB( first );
+        second = Util.normalizeCharForRGB( second );
+        third = Util.normalizeCharForRGB( third );
+        if ( ( first > 235 ) && ( second > 235 ) && ( third > 235 ) ) {
+            first = 0;
+        }
+        else if ( ( first < 80 ) && ( second < 80 ) && ( third < 80 ) ) {
+            second = 255;
+        }
+        return new Color( first, second, third );
+    }
+
+    // Returns true if the specified format name can be written
+    final static boolean canWriteFormat( final String format_name ) {
+        final Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName( format_name );
+        return iter.hasNext();
+    }
+
+    final public static void collapseSpeciesSpecificSubtrees( final Phylogeny phy ) {
+        boolean inferred = false;
+        for( final PhylogenyNodeIterator it = phy.iteratorPreorder(); it.hasNext(); ) {
+            final PhylogenyNode n = it.next();
+            if ( !n.isExternal() && !n.isCollapse() && ( n.getNumberOfDescendants() > 1 ) ) {
+                final Set<Taxonomy> taxs = PhylogenyMethods.obtainDistinctTaxonomies( n );
+                if ( ( taxs != null ) && ( taxs.size() == 1 ) ) {
+                    Util.collapseSubtree( n, true );
+                    if ( !n.getNodeData().isHasTaxonomy() ) {
+                        n.getNodeData().setTaxonomy( ( Taxonomy ) n.getAllExternalDescendants().get( 0 ).getNodeData()
+                                .getTaxonomy().copy() );
+                    }
+                    inferred = true;
+                }
+                else {
+                    n.setCollapse( false );
+                }
+            }
+        }
+        if ( inferred ) {
+            phy.setRerootable( false );
+        }
+    }
+
+    final static void collapseSubtree( final PhylogenyNode node, final boolean collapse ) {
+        node.setCollapse( collapse );
+        if ( node.isExternal() ) {
+            return;
+        }
+        final PhylogenyNodeIterator it = new PreorderTreeIterator( node );
+        while ( it.hasNext() ) {
+            it.next().setCollapse( collapse );
+        }
+    }
+
+    final static void colorPhylogenyAccordingToConfidenceValues( final Phylogeny tree, final TreePanel tree_panel ) {
+        double max_conf = 0.0;
+        for( final PhylogenyNodeIterator it = tree.iteratorPreorder(); it.hasNext(); ) {
+            final PhylogenyNode n = it.next();
+            n.getBranchData().setBranchColor( null );
+            if ( n.getBranchData().isHasConfidences() ) {
+                final double conf = PhylogenyMethods.getConfidenceValue( n );
+                if ( conf > max_conf ) {
+                    max_conf = conf;
+                }
+            }
+        }
+        if ( max_conf > 0.0 ) {
+            final Color bg = tree_panel.getTreeColorSet().getBackgroundColor();
+            final Color br = tree_panel.getTreeColorSet().getBranchColor();
+            for( final PhylogenyNodeIterator it = tree.iteratorPreorder(); it.hasNext(); ) {
+                final PhylogenyNode n = it.next();
+                if ( n.getBranchData().isHasConfidences() ) {
+                    final double conf = PhylogenyMethods.getConfidenceValue( n );
+                    final BranchColor c = new BranchColor( ForesterUtil.calcColor( conf, 0.0, max_conf, bg, br ) );
+                    n.getBranchData().setBranchColor( c );
+                    final List<PhylogenyNode> descs = PhylogenyMethods.getAllDescendants( n );
+                    for( final PhylogenyNode desc : descs ) {
+                        desc.getBranchData().setBranchColor( c );
+                    }
+                }
+            }
+        }
+    }
+
+    final static void colorPhylogenyAccordingToExternalTaxonomy( final Phylogeny tree, final TreePanel tree_panel ) {
+        for( final PhylogenyNodeIterator it = tree.iteratorPreorder(); it.hasNext(); ) {
+            it.next().getBranchData().setBranchColor( null );
+        }
+        for( final PhylogenyNodeIterator it = tree.iteratorPreorder(); it.hasNext(); ) {
+            final PhylogenyNode n = it.next();
+            if ( !n.getBranchData().isHasBranchColor() ) {
+                final Taxonomy tax = PhylogenyMethods.getExternalDescendantsTaxonomy( n );
+                if ( tax != null ) {
+                    n.getBranchData().setBranchColor( new BranchColor( tree_panel.calculateTaxonomyBasedColor( tax ) ) );
+                    final List<PhylogenyNode> descs = PhylogenyMethods.getAllDescendants( n );
+                    for( final PhylogenyNode desc : descs ) {
+                        desc.getBranchData().setBranchColor( new BranchColor( tree_panel
+                                .calculateTaxonomyBasedColor( tax ) ) );
+                    }
+                }
+            }
+        }
+    }
+
+    final static String createDescriptionForTab( final Phylogeny phy, final String full_path ) {
+        final StringBuilder desc = new StringBuilder();
+        if ( ( phy != null ) && !phy.isEmpty() ) {
+            if ( !ForesterUtil.isEmpty( phy.getName() ) ) {
+                desc.append( "name: " );
+                desc.append( phy.getName() );
+                desc.append( "; " );
+            }
+            if ( phy.getIdentifier() != null ) {
+                desc.append( "id: " );
+                desc.append( phy.getIdentifier() );
+                desc.append( "; " );
+            }
+            desc.append( "rooted: " );
+            desc.append( phy.isRooted() );
+            desc.append( "; " );
+            desc.append( "rerootable: " );
+            desc.append( phy.isRerootable() );
+            desc.append( "; " );
+            desc.append( "external nodes: " );
+            desc.append( phy.getNumberOfExternalNodes() );
+            desc.append( "; " );
+            desc.append( "branches: " );
+            desc.append( phy.getNumberOfBranches() );
+            desc.append( "; " );
+            desc.append( "maximum descendants: " );
+            desc.append( PhylogenyMethods.calculateMaximumNumberOfDescendantsPerNode( phy ) );
+            if ( !ForesterUtil.isEmpty( full_path ) && ( full_path.length() <= 50 ) ) {
+                desc.append( "; " );
+                desc.append( "path: " );
+                desc.append( full_path );
+            }
+        }
+        return desc.toString();
+    }
+
+    /**
+     * Exits with -1.
+     * 
+     * 
+     * @param message
+     *            to message to be printed
+     */
+    final static void dieWithSystemError( final String message ) {
+        System.out.println();
+        System.out.println( Constants.PRG_NAME + " encountered the following system error: " + message );
+        System.out.println( "Please contact the authors." );
+        System.out.println( Constants.PRG_NAME + " needs to close." );
+        System.out.println();
+        System.exit( -1 );
+    }
+
+    final static String[] getAvailableFontFamiliesSorted() {
+        return AVAILABLE_FONT_FAMILIES_SORTED;
+    }
+
+    final static void inferCommonPartOfScientificNames( final Phylogeny tree ) {
+        boolean inferred = false;
+        for( final PhylogenyNodeIterator it = tree.iteratorPostorder(); it.hasNext(); ) {
+            final PhylogenyNode n = it.next();
+            if ( !n.getNodeData().isHasTaxonomy() && !n.isExternal() ) {
+                final String sn = PhylogenyMethods.inferCommonPartOfScientificNameOfDescendants( n );
+                if ( !ForesterUtil.isEmpty( sn ) ) {
+                    n.getNodeData().setTaxonomy( new Taxonomy() );
+                    n.getNodeData().getTaxonomy().setScientificName( sn );
+                    inferred = true;
+                }
+            }
+        }
+        if ( inferred ) {
+            tree.setRerootable( false );
+        }
+    }
+
+    final static boolean isHasAssignedEvent( final PhylogenyNode node ) {
+        if ( !node.getNodeData().isHasEvent() ) {
+            return false;
+        }
+        if ( ( node.getNodeData().getEvent() ).isUnassigned() ) {
+            return false;
+        }
+        return true;
+    }
+
+    final static boolean isJava15() {
+        try {
+            final String s = ForesterUtil.JAVA_VERSION;
+            return s.startsWith( "1.5" );
+        }
+        catch ( final Exception e ) {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME, "minor error: " + e );
+            return false;
+        }
+    }
+
+    final static boolean isMac() {
+        try {
+            final String s = ForesterUtil.OS_NAME.toLowerCase();
+            return s.startsWith( "mac" );
+        }
+        catch ( final Exception e ) {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME, "minor error: " + e );
+            return false;
+        }
+    }
+
+    final static boolean isUsOrCanada() {
+        try {
+            if ( ( Locale.getDefault().equals( Locale.CANADA ) ) || ( Locale.getDefault().equals( Locale.US ) ) ) {
+                return true;
+            }
+        }
+        catch ( final Exception e ) {
+            return false;
+        }
+        return false;
+    }
+
+    final static boolean isWindows() {
+        try {
+            final String s = ForesterUtil.OS_NAME.toLowerCase();
+            return s.indexOf( "win" ) > -1;
+        }
+        catch ( final Exception e ) {
+            ForesterUtil.printWarningMessage( Constants.PRG_NAME, "minor error: " + e );
+            return false;
+        }
+    }
+
+    final static void launchWebBrowser( final URI uri,
+                                        final boolean is_applet,
+                                        final JApplet applet,
+                                        final String frame_name ) throws IOException {
+        if ( is_applet ) {
+            applet.getAppletContext().showDocument( uri.toURL(), frame_name );
+        }
+        else {
+            // This requires Java 1.6:
+            // =======================
+            // boolean no_desktop = false;
+            // try {
+            // if ( Desktop.isDesktopSupported() ) {
+            // System.out.println( "desktop supported" );
+            // final Desktop dt = Desktop.getDesktop();
+            // dt.browse( uri );
+            // }
+            // else {
+            // no_desktop = true;
+            // }
+            // }
+            // catch ( final Exception ex ) {
+            // ex.printStackTrace();
+            // no_desktop = true;
+            // }
+            // catch ( final Error er ) {
+            // er.printStackTrace();
+            // no_desktop = true;
+            // }
+            // if ( no_desktop ) {
+            // System.out.println( "desktop not supported" );
+            try {
+                openUrlInWebBrowser( uri.toString() );
+            }
+            catch ( final Exception e ) {
+                throw new IOException( e );
+            }
+            // }
+        }
+    }
+
+    final static void lookAtSomeTreePropertiesForAptxControlSettings( final Phylogeny t,
+                                                                      final ControlPanel atv_control,
+                                                                      final Configuration configuration ) {
+        if ( ( t != null ) && !t.isEmpty() ) {
+            if ( !ForesterUtil.isHasAtLeastOneBranchLengthLargerThanZero( t ) ) {
+                atv_control.setDrawPhylogram( false );
+                atv_control.setDrawPhylogramEnabled( false );
+            }
+            if ( configuration.doGuessCheckOption( Configuration.display_as_phylogram ) ) {
+                if ( atv_control.getDisplayAsPhylogramCb() != null ) {
+                    if ( ForesterUtil.isHasAtLeastOneBranchLengthLargerThanZero( t ) ) {
+                        atv_control.setDrawPhylogram( true );
+                        atv_control.setDrawPhylogramEnabled( true );
+                    }
+                    else {
+                        atv_control.setDrawPhylogram( false );
+                    }
+                }
+            }
+            if ( configuration.doGuessCheckOption( Configuration.write_confidence_values ) ) {
+                if ( atv_control.getWriteConfidenceCb() != null ) {
+                    if ( ForesterUtil.isHasAtLeastOneBranchWithSupportValues( t ) ) {
+                        atv_control.setCheckbox( Configuration.write_confidence_values, true );
+                    }
+                    else {
+                        atv_control.setCheckbox( Configuration.write_confidence_values, false );
+                    }
+                }
+            }
+            if ( configuration.doGuessCheckOption( Configuration.write_events ) ) {
+                if ( atv_control.getShowEventsCb() != null ) {
+                    if ( ForesterUtil.isHasAtLeastNodeWithEvent( t ) ) {
+                        atv_control.setCheckbox( Configuration.write_events, true );
+                    }
+                    else {
+                        atv_control.setCheckbox( Configuration.write_events, false );
+                    }
+                }
+            }
+        }
+    }
+
+    final private static char normalizeCharForRGB( char c ) {
+        c -= 65;
+        c *= 10.2;
+        c = c > 255 ? 255 : c;
+        c = c < 0 ? 0 : c;
+        return c;
+    }
+
+    final private static void openUrlInWebBrowser( final String url ) throws IOException, ClassNotFoundException,
+            SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException,
+            InvocationTargetException, InterruptedException {
+        final String os = System.getProperty( "os.name" );
+        final Runtime runtime = Runtime.getRuntime();
+        if ( os.toLowerCase().startsWith( "win" ) ) {
+            Runtime.getRuntime().exec( "rundll32 url.dll,FileProtocolHandler " + url );
+        }
+        else if ( isMac() ) {
+            final Class<?> file_mgr = Class.forName( "com.apple.eio.FileManager" );
+            final Method open_url = file_mgr.getDeclaredMethod( "openURL", new Class[] { String.class } );
+            open_url.invoke( null, new Object[] { url } );
+        }
+        else {
+            final String[] browsers = { "firefox", "opera", "konqueror", "mozilla", "netscape", "epiphany" };
+            String browser = null;
+            for( int i = 0; ( i < browsers.length ) && ( browser == null ); ++i ) {
+                if ( runtime.exec( new String[] { "which", browsers[ i ] } ).waitFor() == 0 ) {
+                    browser = browsers[ i ];
+                }
+            }
+            if ( browser == null ) {
+                throw new IOException( "could not find a web browser to open [" + url + "] in" );
+            }
+            else {
+                runtime.exec( new String[] { browser, url } );
+            }
+        }
+    }
+
+    final static void openWebsite( final String url, final boolean is_applet, final JApplet applet ) throws IOException {
+        try {
+            Util.launchWebBrowser( new URI( url ), is_applet, applet, Constants.PRG_NAME );
+        }
+        catch ( final Exception e ) {
+            throw new IOException( e );
+        }
+    }
+
+    final static void printAppletMessage( final String applet_name, final String message ) {
+        System.out.println( "[" + applet_name + "] > " + message );
+    }
+
+    final static void printWarningMessage( final String name, final String message ) {
+        System.out.println( "[" + name + "] > " + message );
+    }
+
+    final static Phylogeny[] readPhylogenies( final PhylogenyParser parser, final File file ) throws IOException {
+        final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance();
+        final Phylogeny[] trees = factory.create( file, parser );
+        if ( ( trees == null ) || ( trees.length == 0 ) ) {
+            throw new PhylogenyParserException( "Unable to parse phylogeny from file: " + file );
+        }
+        return trees;
+    }
+
+    final static Phylogeny[] readPhylogeniesFromUrl( final URL url, final boolean phyloxml_validate_against_xsd )
+            throws FileNotFoundException, IOException {
+        final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance();
+        PhylogenyParser parser = null;
+        if ( url.getHost().toLowerCase().indexOf( "tolweb" ) >= 0 ) {
+            parser = new TolParser();
+        }
+        else {
+            parser = ForesterUtil.createParserDependingOnUrlContents( url, phyloxml_validate_against_xsd );
+        }
+        return factory.create( url.openStream(), parser );
+    }
+
+    final static void removeBranchColors( final Phylogeny phy ) {
+        for( final PhylogenyNodeIterator it = phy.iteratorPreorder(); it.hasNext(); ) {
+            it.next().getBranchData().setBranchColor( null );
+        }
+    }
+
+    final static void showErrorMessage( final Component parent, final String error_msg ) {
+        printAppletMessage( Constants.PRG_NAME, error_msg );
+        JOptionPane.showMessageDialog( parent, error_msg, "[" + Constants.PRG_NAME + " " + Constants.VERSION
+                + "] Error", JOptionPane.ERROR_MESSAGE );
+    }
+
+    final static void unexpectedError( final Error err ) {
+        err.printStackTrace();
+        final StringBuffer sb = new StringBuffer();
+        for( final StackTraceElement s : err.getStackTrace() ) {
+            sb.append( s + "\n" );
+        }
+        JOptionPane
+                .showMessageDialog( null,
+                                    "An unexpected (possibly severe) error has occured - terminating. \nPlease contact: "
+                                            + Constants.AUTHOR_EMAIL + " \nError: " + err + "\n" + sb,
+                                    "Unexpected Severe Error [" + Constants.PRG_NAME + " " + Constants.VERSION + "]",
+                                    JOptionPane.ERROR_MESSAGE );
+        System.exit( -1 );
+    }
+
+    final static void unexpectedException( final Exception ex ) {
+        ex.printStackTrace();
+        final StringBuffer sb = new StringBuffer();
+        for( final StackTraceElement s : ex.getStackTrace() ) {
+            sb.append( s + "\n" );
+        }
+        JOptionPane.showMessageDialog( null, "An unexpected exception has occured. \nPlease contact: "
+                + Constants.AUTHOR_EMAIL + " \nException: " + ex + "\n" + sb, "Unexpected Exception ["
+                + Constants.PRG_NAME + Constants.VERSION + "]", JOptionPane.ERROR_MESSAGE );
+    }
+
+    final static String writePhylogenyToGraphicsFile( final String file_name,
+                                                      int width,
+                                                      int height,
+                                                      final TreePanel tree_panel,
+                                                      final ControlPanel ac,
+                                                      final GraphicsExportType type,
+                                                      final Options options ) throws IOException {
+        if ( !options.isGraphicsExportUsingActualSize() ) {
+            if ( options.isGraphicsExportVisibleOnly() ) {
+                throw new IllegalArgumentException( "cannot export visible rectangle only without exporting in actual size" );
+            }
+            tree_panel.setParametersForPainting( options.getPrintSizeX(), options.getPrintSizeY(), true );
+            tree_panel.resetPreferredSize();
+            tree_panel.repaint();
+        }
+        final RenderingHints rendering_hints = new RenderingHints( RenderingHints.KEY_RENDERING,
+                                                                   RenderingHints.VALUE_RENDER_QUALITY );
+        rendering_hints.put( RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY );
+        if ( options.isAntialiasPrint() ) {
+            rendering_hints.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
+            rendering_hints.put( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
+        }
+        else {
+            rendering_hints.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF );
+            rendering_hints.put( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
+        }
+        final Phylogeny phylogeny = tree_panel.getPhylogeny();
+        if ( ( phylogeny == null ) || phylogeny.isEmpty() ) {
+            return "";
+        }
+        final File file = new File( file_name );
+        if ( file.isDirectory() ) {
+            throw new IOException( "\"" + file_name + "\" is a directory" );
+        }
+        Rectangle visible = null;
+        if ( !options.isGraphicsExportUsingActualSize() ) {
+            width = options.getPrintSizeX();
+            height = options.getPrintSizeY();
+        }
+        else if ( options.isGraphicsExportVisibleOnly() ) {
+            visible = tree_panel.getVisibleRect();
+            width = visible.width;
+            height = visible.height;
+        }
+        final BufferedImage buffered_img = new BufferedImage( width, height, BufferedImage.TYPE_INT_RGB );
+        Graphics2D g2d = buffered_img.createGraphics();
+        g2d.setRenderingHints( rendering_hints );
+        int x = 0;
+        int y = 0;
+        if ( options.isGraphicsExportVisibleOnly() ) {
+            g2d = ( Graphics2D ) g2d.create( -visible.x, -visible.y, visible.width, visible.height );
+            g2d.setClip( null );
+            x = visible.x;
+            y = visible.y;
+        }
+        tree_panel.paintPhylogeny( g2d, false, true, width, height, x, y );
+        if ( type == GraphicsExportType.TIFF ) {
+            writeToTiff( file, buffered_img );
+        }
+        else {
+            ImageIO.write( buffered_img, type.toString(), file );
+        }
+        g2d.dispose();
+        System.gc();
+        if ( !options.isGraphicsExportUsingActualSize() ) {
+            tree_panel.getMainPanel().getControlPanel().showWhole();
+        }
+        String msg = file.toString();
+        if ( ( width > 0 ) && ( height > 0 ) ) {
+            msg += " [size: " + width + ", " + height + "]";
+        }
+        return msg;
+    }
+
+    final static void writeToTiff( final File file, final BufferedImage image ) throws IOException {
+        // See: http://log.robmeek.com/2005/08/write-tiff-in-java.html
+        ImageWriter writer = null;
+        ImageOutputStream ios = null;
+        // Find an appropriate writer:
+        final Iterator<ImageWriter> it = ImageIO.getImageWritersByFormatName( "TIF" );
+        if ( it.hasNext() ) {
+            writer = it.next();
+        }
+        else {
+            throw new IOException( "failed to get TIFF image writer" );
+        }
+        // Setup writer:
+        ios = ImageIO.createImageOutputStream( file );
+        writer.setOutput( ios );
+        final ImageWriteParam image_write_param = new ImageWriteParam( Locale.getDefault() );
+        image_write_param.setCompressionMode( ImageWriteParam.MODE_EXPLICIT );
+        // see writeParam.getCompressionTypes() for available compression type
+        // strings.
+        image_write_param.setCompressionType( "PackBits" );
+        final String t[] = image_write_param.getCompressionTypes();
+        for( final String string : t ) {
+            System.out.println( string );
+        }
+        // Convert to an IIOImage:
+        final IIOImage iio_image = new IIOImage( image, null, null );
+        writer.write( null, iio_image, image_write_param );
+    }
+
+    // See: http://www.xml.nig.ac.jp/tutorial/rest/index.html#2.2
+    // static void openDDBJRest() throws IOException {
+    // //set URL
+    // URL url = new URL( "http://xml.nig.ac.jp/rest/Invoke" );
+    // //set parameter
+    // String query = "service=GetEntry&method=getDDBJEntry&accession=AB000100";
+    // //make connection
+    // URLConnection urlc = url.openConnection();
+    // //use post mode
+    // urlc.setDoOutput( true );
+    // urlc.setAllowUserInteraction( false );
+    // //send query
+    // PrintStream ps = new PrintStream( urlc.getOutputStream() );
+    // ps.print( query );
+    // ps.close();
+    // //get result
+    // BufferedReader br = new BufferedReader( new InputStreamReader(
+    // urlc.getInputStream() ) );
+    // String l = null;
+    // while ( ( l = br.readLine() ) != null ) {
+    // System.out.println( l );
+    // }
+    // br.close();
+    // }
+    static enum GraphicsExportType {
+        GIF( "gif" ), JPG( "jpg" ), PDF( "pdf" ), PNG( "png" ), TIFF( "tif" ), BMP( "bmp" );
+
+        private final String _suffix;
+
+        private GraphicsExportType( final String suffix ) {
+            _suffix = suffix;
+        }
+
+        @Override
+        public String toString() {
+            return _suffix;
+        }
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/WebLink.java b/forester/java/src/org/forester/archaeopteryx/WebLink.java
new file mode 100644 (file)
index 0000000..ae18572
--- /dev/null
@@ -0,0 +1,64 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx;
+
+import java.net.URL;
+
+class WebLink {
+
+    private final URL    _url;
+    private final String _desc;
+    private final String _source_identifier;
+
+    WebLink( final URL url, final String desc, final String source_identifier ) {
+        _url = url;
+        _desc = desc;
+        _source_identifier = source_identifier;
+    }
+
+    String getDesc() {
+        return _desc;
+    }
+
+    String getSourceIdentifier() {
+        return _source_identifier;
+    }
+
+    URL getUrl() {
+        return _url;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder();
+        sb.append( getDesc() );
+        sb.append( " [" );
+        sb.append( getSourceIdentifier() );
+        sb.append( "]: " );
+        sb.append( getUrl().toString() );
+        return sb.toString();
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/phylogeny/data/RenderableDomainArchitecture.java b/forester/java/src/org/forester/archaeopteryx/phylogeny/data/RenderableDomainArchitecture.java
new file mode 100644 (file)
index 0000000..df45fe5
--- /dev/null
@@ -0,0 +1,226 @@
+// $Id:
+// $
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx.phylogeny.data;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+import java.util.SortedMap;
+
+import org.forester.archaeopteryx.Configuration;
+import org.forester.archaeopteryx.TreePanel;
+import org.forester.phylogeny.data.DomainArchitecture;
+import org.forester.phylogeny.data.PhylogenyData;
+import org.forester.phylogeny.data.PhylogenyDataUtil;
+import org.forester.phylogeny.data.ProteinDomain;
+import org.forester.util.ForesterUtil;
+
+public final class RenderableDomainArchitecture extends DomainArchitecture implements RenderablePhylogenyData {
+
+    static private Map<String, Color> Domain_colors;
+    final static private int          BRIGHTEN_COLOR_BY             = 200;
+    final static private int          E_VALUE_THRESHOLD_EXP_DEFAULT = 0;
+    private static int                _Next_default_domain_color    = 0;
+    private final static String[]     DEFAULT_DOMAINS_COLORS        = { "0xFF0000", "0x0000FF", "0xAAAA00", "0xFF00FF",
+            "0x00FFFF", "0x800000", "0x000080", "0x808000", "0x800080", "0x008080", "0xE1B694" };
+    private int                       _e_value_threshold_exp        = RenderableDomainArchitecture.E_VALUE_THRESHOLD_EXP_DEFAULT;
+    private double                    _rendering_factor_width       = 1.0;
+    private double                    _rendering_height             = 0;
+    private final DomainArchitecture  _domain_structure;
+    private final Rectangle2D         _rectangle                    = new Rectangle2D.Float();
+    private final Configuration       _configuration;
+
+    public RenderableDomainArchitecture( final DomainArchitecture domain_structure, final Configuration configuration ) {
+        _domain_structure = domain_structure;
+        _configuration = configuration;
+    }
+
+    private Configuration getConfiguration() {
+        return _configuration;
+    }
+
+    @Override
+    public StringBuffer asSimpleText() {
+        return _domain_structure.asSimpleText();
+    }
+
+    @Override
+    public StringBuffer asText() {
+        return _domain_structure.asText();
+    }
+
+    @Override
+    public PhylogenyData copy() {
+        return _domain_structure.copy();
+    }
+
+    private final void drawDomain( final double x,
+                                   final double y,
+                                   final double width,
+                                   final double heigth,
+                                   final String name,
+                                   final Graphics2D g,
+                                   final boolean to_pdf ) {
+        final double h2 = heigth / 2.0;
+        final Color color_one = getColorOne( name );
+        final Color color_two = getColorTwo( color_one );
+        double step = 1;
+        if ( to_pdf ) {
+            step = 0.1;
+        }
+        for( double i = 0; i < heigth; i += step ) {
+            g.setColor( org.forester.util.ForesterUtil
+                    .calcColor( i >= h2 ? heigth - i : i, 0, h2, color_one, color_two ) );
+            _rectangle.setFrame( x, i + y, width, step );
+            g.fill( _rectangle );
+        }
+    }
+
+    private Color getColorOne( final String name ) {
+        Color c = getConfiguration().getDomainStructureBaseColor();
+        if ( RenderableDomainArchitecture.Domain_colors != null ) {
+            c = RenderableDomainArchitecture.Domain_colors.get( name );
+            if ( c == null ) {
+                if ( RenderableDomainArchitecture._Next_default_domain_color < RenderableDomainArchitecture.DEFAULT_DOMAINS_COLORS.length ) {
+                    c = Color
+                            .decode( RenderableDomainArchitecture.DEFAULT_DOMAINS_COLORS[ RenderableDomainArchitecture._Next_default_domain_color++ ] );
+                    RenderableDomainArchitecture.Domain_colors.put( name, c );
+                }
+                else {
+                    c = getConfiguration().getDomainStructureBaseColor();
+                }
+            }
+        }
+        return c;
+    }
+
+    private Color getColorTwo( final Color color_one ) {
+        final int red = color_one.getRed() + RenderableDomainArchitecture.BRIGHTEN_COLOR_BY;
+        final int green = color_one.getGreen() + RenderableDomainArchitecture.BRIGHTEN_COLOR_BY;
+        final int blue = color_one.getBlue() + RenderableDomainArchitecture.BRIGHTEN_COLOR_BY;
+        return new Color( red > 255 ? 255 : red, green > 255 ? 255 : green, blue > 255 ? 255 : blue );
+    }
+
+    @Override
+    public ProteinDomain getDomain( final int i ) {
+        return _domain_structure.getDomain( i );
+    }
+
+    @Override
+    public SortedMap<Double, ProteinDomain> getDomains() {
+        return _domain_structure.getDomains();
+    }
+
+    @Override
+    public int getNumberOfDomains() {
+        return _domain_structure.getNumberOfDomains();
+    }
+
+    public Dimension getOriginalSize() {
+        return new Dimension( _domain_structure.getTotalLength(), ForesterUtil.roundToInt( _rendering_height ) );
+    }
+
+    public Object getParameter() {
+        return new Integer( _e_value_threshold_exp );
+    }
+
+    public double getRenderingFactorWidth() {
+        return _rendering_factor_width;
+    }
+
+    public Dimension getRenderingSize() {
+        return new Dimension( ForesterUtil.roundToInt( _domain_structure.getTotalLength() * _rendering_factor_width ),
+                              ForesterUtil.roundToInt( _rendering_height ) );
+    }
+
+    @Override
+    public int getTotalLength() {
+        return _domain_structure.getTotalLength();
+    }
+
+    @Override
+    public boolean isEqual( final PhylogenyData data ) {
+        return _domain_structure.isEqual( data );
+    }
+
+    public void render( final double x1,
+                        final double y1,
+                        final Graphics2D g,
+                        final TreePanel tree_panel,
+                        final boolean to_pdf ) {
+        final double f = getRenderingFactorWidth();
+        final double y = y1 + ( _rendering_height / 2 );
+        final double start = x1 + 20.0;
+        g.setColor( getConfiguration().getDomainStructureFontColor() );
+        _rectangle.setFrame( start, y - 0.5, _domain_structure.getTotalLength() * f, 1 );
+        g.fill( _rectangle );
+        for( int i = 0; i < _domain_structure.getDomains().size(); ++i ) {
+            final ProteinDomain d = _domain_structure.getDomain( i );
+            if ( d.getConfidence() <= Math.pow( 10, _e_value_threshold_exp ) ) {
+                final double xa = start + d.getFrom() * f;
+                final double xb = xa + d.getLength() * f;
+                if ( tree_panel.getMainPanel().getOptions().isShowDomainLabels() ) {
+                    g.setFont( tree_panel.getMainPanel().getTreeFontSet().getSmallFont() );
+                    g.setColor( getConfiguration().getDomainStructureFontColor() );
+                    PhylogenyDataUtil.drawString( d.getName(), xa, y1
+                            + tree_panel.getMainPanel().getTreeFontSet()._fm_small.getAscent() + 6, g );
+                }
+                drawDomain( xa, y1, xb - xa, _rendering_height, d.getName(), g, to_pdf );
+            }
+        }
+    }
+
+    public void setParameter( final double e_value_threshold_exp ) {
+        _e_value_threshold_exp = ( int ) e_value_threshold_exp;
+    }
+
+    public void setRenderingFactorWidth( final double rendering_factor_width ) {
+        _rendering_factor_width = rendering_factor_width;
+    }
+
+    public void setRenderingHeight( final double rendering_height ) {
+        _rendering_height = rendering_height;
+    }
+
+    @Override
+    public StringBuffer toNHX() {
+        return _domain_structure.toNHX();
+    }
+
+    @Override
+    public void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException {
+        _domain_structure.toPhyloXML( writer, level, indentation );
+    }
+
+    public static void setColorMap( final Map<String, Color> domain_colors ) {
+        RenderableDomainArchitecture.Domain_colors = domain_colors;
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/phylogeny/data/RenderablePhylogenyData.java b/forester/java/src/org/forester/archaeopteryx/phylogeny/data/RenderablePhylogenyData.java
new file mode 100644 (file)
index 0000000..1755671
--- /dev/null
@@ -0,0 +1,55 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx.phylogeny.data;
+
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+
+import org.forester.archaeopteryx.TreePanel;
+import org.forester.phylogeny.data.PhylogenyData;
+
+public interface RenderablePhylogenyData extends PhylogenyData {
+
+    public Dimension getOriginalSize();
+
+    public Object getParameter();
+
+    public Dimension getRenderingSize();
+
+    /**
+     * This can be used to render phylogeny data as graphics (for example,
+     * display of the domain structure). In most Renderable implementations this
+     * will do nothing (i.e. just return).
+     * 
+     * @param g
+     *            the Graphics to render to
+     */
+    public void render( final double x, final double y, final Graphics2D g, final TreePanel tree_panel, boolean to_pdf );
+
+    public void setParameter( final double parameter );
+
+    public void setRenderingHeight( final double rendering_height );
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/phylogeny/data/RenderableVector.java b/forester/java/src/org/forester/archaeopteryx/phylogeny/data/RenderableVector.java
new file mode 100644 (file)
index 0000000..c22b645
--- /dev/null
@@ -0,0 +1,171 @@
+// $Id:
+// $
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2009 Christian M. Zmasek
+// Copyright (C) 2008-2009 Burnham Institute for Medical Research
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx.phylogeny.data;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.List;
+
+import org.forester.archaeopteryx.Configuration;
+import org.forester.archaeopteryx.TreePanel;
+import org.forester.phylogeny.data.PhylogenyData;
+import org.forester.util.DescriptiveStatistics;
+import org.forester.util.ForesterUtil;
+
+public final class RenderableVector implements RenderablePhylogenyData {
+
+    final static public int         DEFAULT_HEIGHT          = 12;
+    final static public int         DEFAULT_WIDTH           = 120;
+    private double                  _rendering_factor_width = 1.0;
+    private List<Double>            _values;
+    private final Rectangle2D       _rectangle              = new Rectangle2D.Float();
+    private Configuration           _configuration;
+    private double                  _height;
+    private double                  _min;
+    private double                  _max;
+    private double                  _mean;
+    private static RenderableVector _instance               = null;
+
+    public static RenderableVector createInstance( final List<Double> values,
+                                                   final DescriptiveStatistics stats,
+                                                   final Configuration configuration ) {
+        if ( _instance == null ) {
+            _instance = new RenderableVector();
+        }
+        _instance.setRenderingHeight( DEFAULT_HEIGHT );
+        _instance._values = values;
+        _instance._configuration = configuration;
+        _instance._min = stats.getMin();
+        _instance._max = stats.getMax();
+        _instance._mean = stats.arithmeticMean();
+        return _instance;
+    }
+
+    @Override
+    public Object clone() {
+        throw new NoSuchMethodError();
+    }
+
+    private RenderableVector() {
+        _values = null;
+        _configuration = null;
+    }
+
+    @Override
+    public StringBuffer asSimpleText() {
+        return new StringBuffer( _values.toString() );
+    }
+
+    @Override
+    public StringBuffer asText() {
+        return asSimpleText();
+    }
+
+    public double getRenderingFactorWidth() {
+        return _rendering_factor_width;
+    }
+
+    public int getTotalLength() {
+        return ( int ) ( _values.size() * getRenderingHeight() );
+    }
+
+    @Override
+    public boolean isEqual( final PhylogenyData data ) {
+        throw new NoSuchMethodError();
+    }
+
+    public void render( final double x1,
+                        final double y1,
+                        final Graphics2D g,
+                        final TreePanel tree_panel,
+                        final boolean to_pdf ) {
+        final double y = y1;
+        final double start = x1 + 20.0;
+        final double width = ( double ) DEFAULT_WIDTH / _values.size();
+        for( int i = 0; i < _values.size(); ++i ) {
+            g.setColor( calculateColor( _values.get( i ) ) );
+            _rectangle.setFrame( start + i * width, y - 0.5, width, getRenderingHeight() );
+            g.fill( _rectangle );
+        }
+    }
+
+    private Color calculateColor( final double v ) {
+        return ForesterUtil.calcColor( v, _min, _max, _mean, Color.MAGENTA, Color.GREEN, Color.WHITE );
+    }
+
+    public void setRenderingFactorWidth( final double rendering_factor_width ) {
+        _rendering_factor_width = rendering_factor_width;
+    }
+
+    @Override
+    public StringBuffer toNHX() {
+        throw new NoSuchMethodError();
+    }
+
+    @Override
+    public void toPhyloXML( final Writer writer, final int level, final String indentation ) throws IOException {
+        throw new NoSuchMethodError();
+    }
+
+    @Override
+    public PhylogenyData copy() {
+        throw new NoSuchMethodError();
+    }
+
+    @Override
+    public Dimension getOriginalSize() {
+        return new Dimension( getTotalLength(), ( int ) getRenderingHeight() );
+    }
+
+    @Override
+    public Object getParameter() {
+        return null;
+    }
+
+    @Override
+    public Dimension getRenderingSize() {
+        return getOriginalSize();
+    }
+
+    @Override
+    public void setParameter( final double parameter ) {
+        throw new NoSuchMethodError();
+    }
+
+    @Override
+    public void setRenderingHeight( final double height ) {
+        _height = height;
+    }
+
+    private double getRenderingHeight() {
+        return _height;
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/webservices/BasicPhylogeniesWebserviceClient.java b/forester/java/src/org/forester/archaeopteryx/webservices/BasicPhylogeniesWebserviceClient.java
new file mode 100644 (file)
index 0000000..3e613e2
--- /dev/null
@@ -0,0 +1,116 @@
+// $Id:
+// Exp $
+// forester -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2010 Christian M. Zmasek
+// Copyright (C) 2008-2010 Burnham Institute for Medical Research
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org
+
+package org.forester.archaeopteryx.webservices;
+
+import org.forester.archaeopteryx.webservices.WebservicesManager.WsPhylogenyFormat;
+import org.forester.util.ForesterUtil.PhylogenyNodeField;
+
+public class BasicPhylogeniesWebserviceClient implements PhylogeniesWebserviceClient {
+
+    private final String             _desc;
+    private final String             _instructions;
+    private final String             _menu_name;
+    private final String             _name;
+    private final WsPhylogenyFormat  _format;
+    private final String             _url;
+    private final boolean            _integer;
+    private final PhylogenyNodeField _node_field;
+    private final Object             _proc_inst;
+    private final String             _ref;
+
+    public BasicPhylogeniesWebserviceClient( final String name,
+                                             final String menu_name,
+                                             final String desc,
+                                             final String instructions,
+                                             final WsPhylogenyFormat format,
+                                             final PhylogenyNodeField node_field,
+                                             final String url,
+                                             final boolean integer,
+                                             final String ref,
+                                             final Object proc_inst ) {
+        super();
+        _desc = desc;
+        _instructions = instructions;
+        _menu_name = menu_name;
+        _name = name;
+        _format = format;
+        _node_field = node_field;
+        _url = url;
+        _integer = integer;
+        _ref = ref;
+        _proc_inst = proc_inst;
+    }
+
+    @Override
+    public String getDescription() {
+        return _desc;
+    }
+
+    @Override
+    public String getInstructions() {
+        return _instructions;
+    }
+
+    @Override
+    public String getMenuName() {
+        return _menu_name;
+    }
+
+    @Override
+    public String getName() {
+        return _name;
+    }
+
+    @Override
+    public PhylogenyNodeField getNodeField() {
+        return _node_field;
+    }
+
+    @Override
+    public Object getProcessingInstructions() {
+        return _proc_inst;
+    }
+
+    @Override
+    public String getReference() {
+        return _ref;
+    }
+
+    @Override
+    public WsPhylogenyFormat getReturnFormat() {
+        return _format;
+    }
+
+    @Override
+    public String getUrl() {
+        return _url;
+    }
+
+    @Override
+    public boolean isQueryInteger() {
+        return _integer;
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/webservices/PhylogeniesWebserviceClient.java b/forester/java/src/org/forester/archaeopteryx/webservices/PhylogeniesWebserviceClient.java
new file mode 100644 (file)
index 0000000..f8e833e
--- /dev/null
@@ -0,0 +1,111 @@
+// $Id:
+// FORESTER -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2010 Christian M. Zmasek
+// All rights reserved
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx.webservices;
+
+import org.forester.archaeopteryx.webservices.WebservicesManager.WsPhylogenyFormat;
+import org.forester.util.ForesterUtil.PhylogenyNodeField;
+
+/*
+ * Webservices which return phylogenies.
+ */
+public interface PhylogeniesWebserviceClient {
+
+    public final static String QUERY_PLACEHOLDER = "__query__";
+
+    /**
+     * A short description of the webservice (~20 characters).
+     *  
+     * @return a short description of the webservice (~20 characters)
+     */
+    public String getDescription();
+
+    /**
+     * Instructions (and examples) on how to use the webservice.
+     * 
+     * @return instructions (and examples) on how to use the webservice
+     */
+    public String getInstructions();
+
+    /**
+     * A name/description which can appear on a menu.
+     * 
+     * @return A name/description which can appear on a menu
+     */
+    public String getMenuName();
+
+    /**
+     * The name of the webservice.
+     * 
+     * 
+     * @return the name of the webservice
+     */
+    public String getName();
+
+    /**
+     * The node data field in which to place node names from simple unannotated formats
+     * (such as Newick). Null means avoiding any such postprocessing.  
+     * 
+     * @return the field code
+     */
+    public PhylogenyNodeField getNodeField();
+
+    /**
+     * This is used to indicate any kind of special processing.
+     * 
+     * 
+     * @return a reference
+     */
+    public Object getProcessingInstructions();
+
+    /**
+     * To get a type of reference for the webservice (an URL or citation, for example).
+     * 
+     * 
+     * @return a reference
+     */
+    public String getReference();
+
+    /**
+     * The expected format of the response.
+     * 
+     * @return the expected format of the response
+     */
+    public WsPhylogenyFormat getReturnFormat();
+
+    /**
+     * Use QUERY_PLACEHOLDER to indicate position of query variable.
+     * 
+     * @return the URL
+     */
+    public String getUrl();
+
+    /**
+     * Is the query a number?
+     * 
+     * 
+     * @return
+     */
+    public boolean isQueryInteger();
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/webservices/WebserviceUtil.java b/forester/java/src/org/forester/archaeopteryx/webservices/WebserviceUtil.java
new file mode 100644 (file)
index 0000000..9ca03a1
--- /dev/null
@@ -0,0 +1,224 @@
+// $Id:
+// forester -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2010 Christian M. Zmasek
+// Copyright (C) 2008-2010 Burnham Institute for Medical Research
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org/forester
+
+package org.forester.archaeopteryx.webservices;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.forester.archaeopteryx.webservices.WebservicesManager.WsPhylogenyFormat;
+import org.forester.io.parsers.phyloxml.PhyloXmlUtil;
+import org.forester.phylogeny.Phylogeny;
+import org.forester.phylogeny.PhylogenyNode;
+import org.forester.phylogeny.data.Accession;
+import org.forester.phylogeny.data.Identifier;
+import org.forester.phylogeny.data.Sequence;
+import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
+import org.forester.phylogeny.iterators.PreorderTreeIterator;
+import org.forester.util.ForesterUtil;
+import org.forester.util.ForesterUtil.PhylogenyNodeField;
+
+public final class WebserviceUtil {
+
+    public static final String TAX_CODE_TO_SCI_NAME = "tax_code_to_sci_name";
+    public static final String TREE_FAM_INST        = "tree_fam";
+    public static final String PFAM_INST            = "pfam";
+    public static final String TOL_WEBSERVER        = "http://tolweb.org/onlinecontributors/app?service=external&page=xml/TreeStructureService&node_id="
+                                                            + PhylogeniesWebserviceClient.QUERY_PLACEHOLDER;
+    public static final String TOL_NAME             = "Tree of Life";
+    public static final String TREE_BASE_NAME       = "TreeBASE";
+    public static final String TREE_FAM_NAME        = "TreeFam";
+    public static final String PFAM_NAME            = "Pfam";
+    public static final String PFAM_SERVER          = "http://pfam.janelia.org";
+
+    public static List<PhylogeniesWebserviceClient> createDefaultClients() {
+        final List<PhylogeniesWebserviceClient> clients = new ArrayList<PhylogeniesWebserviceClient>();
+        clients
+                .add( new BasicPhylogeniesWebserviceClient( TOL_NAME,
+                                                            "Read Tree from Tree of Life...",
+                                                            "Use ToL webservice to obtain a phylogeny",
+                                                            "Please enter a Tree of Life node identifier\n(Examples: "
+                                                                    + "19386 for Cephalopoda, 2461 for Cnidaria, 2466 for Deuterostomia)",
+                                                            WsPhylogenyFormat.TOL_XML_RESPONSE,
+                                                            PhylogenyNodeField.TAXONOMY_SCIENTIFIC_NAME,
+                                                            WebserviceUtil.TOL_WEBSERVER,
+                                                            true,
+                                                            "http://tolweb.org",
+                                                            null ) );
+        clients
+                .add( new BasicPhylogeniesWebserviceClient( TREE_BASE_NAME,
+                                                            "Read Tree from TreeBASE...",
+                                                            "Use TreeBASE to obtain a phylogeny",
+                                                            "Please enter a TreeBASE tree identifier\n(Examples: 2654, 825, 4931, 2518, 2406, 4934)",
+                                                            WsPhylogenyFormat.NEXUS,
+                                                            PhylogenyNodeField.TAXONOMY_SCIENTIFIC_NAME,
+                                                            "http://purl.org/phylo/treebase/phylows/tree/TB2:Tr"
+                                                                    + PhylogeniesWebserviceClient.QUERY_PLACEHOLDER
+                                                                    + "?format=nexus",
+                                                            true,
+                                                            "http://treebase.nescent.org",
+                                                            null ) );
+        clients
+                .add( new BasicPhylogeniesWebserviceClient( PFAM_NAME,
+                                                            "Read Gene Tree from Pfam...",
+                                                            "Use  Pfam to obtain a (full) gene tree",
+                                                            "Please enter a Pfam (PF) accession number\n(Examples: 01849 for NAC, 00452 for Bcl-2, 00046 for Homeobox)",
+                                                            WsPhylogenyFormat.PFAM,
+                                                            null,
+                                                            PFAM_SERVER + "/family/tree/download?alnType=full&acc=PF"
+                                                                    + PhylogeniesWebserviceClient.QUERY_PLACEHOLDER,
+                                                            false,
+                                                            PFAM_SERVER,
+                                                            PFAM_INST ) );
+        clients
+                .add( new BasicPhylogeniesWebserviceClient( TREE_FAM_NAME,
+                                                            "Read Full Gene Tree from TreeFam...",
+                                                            "Use TreeFam to obtain a (full) gene tree",
+                                                            "Please enter a TreeFam (TF) accession number\n(Examples: 101004 for Cyclin D, 315938 for Hox, 105310 for Wnt)",
+                                                            WsPhylogenyFormat.NHX,
+                                                            null,
+                                                            "http://www.treefam.org/cgi-bin/getdata.pl?ac=TF"
+                                                                    + PhylogeniesWebserviceClient.QUERY_PLACEHOLDER
+                                                                    + "&f=full.nhx",
+                                                            true,
+                                                            "http://www.treefam.org",
+                                                            TREE_FAM_INST ) );
+        clients
+                .add( new BasicPhylogeniesWebserviceClient( TREE_FAM_NAME,
+                                                            "Read Clean Gene Tree from TreeFam...",
+                                                            "Use TreeFam to obtain a (\"clean\") gene tree",
+                                                            "Please enter a TreeFam (TF) accession number\n(Examples: 101004 for Cyclin D, 315938 for Hox, 105310 for Wnt)",
+                                                            WsPhylogenyFormat.NHX,
+                                                            null,
+                                                            "http://www.treefam.org/cgi-bin/getdata.pl?ac=TF"
+                                                                    + PhylogeniesWebserviceClient.QUERY_PLACEHOLDER
+                                                                    + "&f=clean.nhx",
+                                                            true,
+                                                            "http://www.treefam.org",
+                                                            TREE_FAM_INST ) );
+        return clients;
+    }
+
+    static void extractSpTremblAccFromNodeName( final Phylogeny phy, final String source ) {
+        final PreorderTreeIterator it = new PreorderTreeIterator( phy );
+        while ( it.hasNext() ) {
+            final PhylogenyNode n = it.next();
+            if ( !ForesterUtil.isEmpty( n.getName() ) ) {
+                final String name = n.getName();
+                final int i = name.lastIndexOf( "/" );
+                if ( i > 0 ) {
+                    final String acc_str = name.substring( 0, i );
+                    if ( !ForesterUtil.isEmpty( acc_str ) ) {
+                        final Sequence seq = new Sequence();
+                        final Accession acc = new Accession( acc_str, source );
+                        seq.setAccession( acc );
+                        n.getNodeData().setSequence( seq );
+                    }
+                }
+            }
+        }
+    }
+
+    public static void processInstructions( final PhylogeniesWebserviceClient client, final Phylogeny phylogeny ) {
+        if ( client.getProcessingInstructions().equals( WebserviceUtil.TAX_CODE_TO_SCI_NAME ) ) {
+            WebserviceUtil.transferTaxonomyCodeToScientificName( phylogeny );
+        }
+        else if ( client.getProcessingInstructions().equals( WebserviceUtil.TREE_FAM_INST ) ) {
+            WebserviceUtil.transferInternalTaxonomyCodeToScientificName( phylogeny );
+            WebserviceUtil.transferExternalScientificNameToTaxonomyCode( phylogeny );
+            WebserviceUtil.transferSequenceNameToSequenceAccession( phylogeny, "ensembl" );
+            WebserviceUtil.setTaxonomyIdentifierType( phylogeny, "ncbi" );
+        }
+        else if ( client.getProcessingInstructions().equals( WebserviceUtil.PFAM_INST ) ) {
+            WebserviceUtil.extractSpTremblAccFromNodeName( phylogeny, "sptrembl" );
+        }
+    }
+
+    static void setTaxonomyIdentifierType( final Phylogeny phy, final String type ) {
+        final PhylogenyNodeIterator it = phy.iteratorPostorder();
+        while ( it.hasNext() ) {
+            final PhylogenyNode n = it.next();
+            if ( n.getNodeData().isHasTaxonomy() && ( n.getNodeData().getTaxonomy().getIdentifier() != null ) ) {
+                n.getNodeData().getTaxonomy().setIdentifier( new Identifier( n.getNodeData().getTaxonomy()
+                        .getIdentifier().getValue(), type ) );
+            }
+        }
+    }
+
+    static void transferExternalScientificNameToTaxonomyCode( final Phylogeny phy ) {
+        final PhylogenyNodeIterator it = phy.iteratorPostorder();
+        while ( it.hasNext() ) {
+            final PhylogenyNode n = it.next();
+            if ( n.isExternal() && n.getNodeData().isHasTaxonomy() ) {
+                final String name = n.getNodeData().getTaxonomy().getScientificName();
+                if ( !ForesterUtil.isEmpty( name ) && PhyloXmlUtil.TAXOMONY_CODE_PATTERN.matcher( name ).matches() ) {
+                    n.getNodeData().getTaxonomy().setScientificName( "" );
+                    n.getNodeData().getTaxonomy().setTaxonomyCode( name );
+                }
+            }
+        }
+    }
+
+    static void transferInternalTaxonomyCodeToScientificName( final Phylogeny phy ) {
+        final PhylogenyNodeIterator it = phy.iteratorPostorder();
+        while ( it.hasNext() ) {
+            final PhylogenyNode n = it.next();
+            if ( !n.isExternal() && n.getNodeData().isHasTaxonomy() ) {
+                final String name = n.getNodeData().getTaxonomy().getTaxonomyCode();
+                if ( !ForesterUtil.isEmpty( name ) ) {
+                    n.getNodeData().getTaxonomy().setScientificName( name );
+                    n.getNodeData().getTaxonomy().setTaxonomyCode( "" );
+                }
+            }
+        }
+    }
+
+    static void transferSequenceNameToSequenceAccession( final Phylogeny phy, final String source ) {
+        final PhylogenyNodeIterator it = phy.iteratorPostorder();
+        while ( it.hasNext() ) {
+            final PhylogenyNode n = it.next();
+            if ( n.getNodeData().isHasSequence() ) {
+                final String name = n.getNodeData().getSequence().getName();
+                if ( !ForesterUtil.isEmpty( name ) ) {
+                    n.getNodeData().getSequence().setName( "" );
+                    n.getNodeData().getSequence().setAccession( new Accession( name, source ) );
+                }
+            }
+        }
+    }
+
+    static void transferTaxonomyCodeToScientificName( final Phylogeny phy ) {
+        final PhylogenyNodeIterator it = phy.iteratorPostorder();
+        while ( it.hasNext() ) {
+            final PhylogenyNode n = it.next();
+            if ( n.getNodeData().isHasTaxonomy() ) {
+                final String name = n.getNodeData().getTaxonomy().getTaxonomyCode();
+                if ( !ForesterUtil.isEmpty( name ) ) {
+                    n.getNodeData().getTaxonomy().setScientificName( name );
+                    n.getNodeData().getTaxonomy().setTaxonomyCode( "" );
+                }
+            }
+        }
+    }
+}
diff --git a/forester/java/src/org/forester/archaeopteryx/webservices/WebservicesManager.java b/forester/java/src/org/forester/archaeopteryx/webservices/WebservicesManager.java
new file mode 100644 (file)
index 0000000..181439b
--- /dev/null
@@ -0,0 +1,63 @@
+// $Id:
+// forester -- software libraries and applications
+// for evolutionary biology research and applications.
+//
+// Copyright (C) 2008-2010 Christian M. Zmasek
+// Copyright (C) 2008-2010 Burnham Institute for Medical Research
+// 
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+// 
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// Contact: phylosoft @ gmail . com
+// WWW: www.phylosoft.org
+
+package org.forester.archaeopteryx.webservices;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class WebservicesManager {
+
+    private static WebservicesManager               _instance;
+    private final List<PhylogeniesWebserviceClient> _clients;
+
+    private WebservicesManager() {
+        _clients = new ArrayList<PhylogeniesWebserviceClient>();
+        _clients.addAll( WebserviceUtil.createDefaultClients() );
+    }
+
+    @Override
+    public Object clone() throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+    public PhylogeniesWebserviceClient getAvailablePhylogeniesWebserviceClient( final int i ) {
+        return getAvailablePhylogeniesWebserviceClients().get( i );
+    }
+
+    public List<PhylogeniesWebserviceClient> getAvailablePhylogeniesWebserviceClients() {
+        return _clients;
+    }
+
+    public static WebservicesManager getInstance() {
+        if ( _instance == null ) {
+            _instance = new WebservicesManager();
+        }
+        return _instance;
+    }
+
+    public enum WsPhylogenyFormat {
+        NH, NHX, NEXUS, TOL_XML_RESPONSE, PHYLOXML, NH_EXTRACT_TAXONOMY, PFAM
+    }
+}