cleanup
[jalview.git] / forester / java / src / org / forester / archaeopteryx / TreePanel.java
1 // $Id:
2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
4 //
5 // Copyright (C) 2008-2009 Christian M. Zmasek
6 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
7 // All rights reserved
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 //
23 // Contact: phylosoft @ gmail . com
24 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
25
26 package org.forester.archaeopteryx;
27
28 import java.awt.BasicStroke;
29 import java.awt.Color;
30 import java.awt.Cursor;
31 import java.awt.Dimension;
32 import java.awt.Font;
33 import java.awt.GradientPaint;
34 import java.awt.Graphics;
35 import java.awt.Graphics2D;
36 import java.awt.Point;
37 import java.awt.Rectangle;
38 import java.awt.RenderingHints;
39 import java.awt.Stroke;
40 import java.awt.event.ActionEvent;
41 import java.awt.event.ActionListener;
42 import java.awt.event.FocusAdapter;
43 import java.awt.event.FocusEvent;
44 import java.awt.event.InputEvent;
45 import java.awt.event.KeyAdapter;
46 import java.awt.event.KeyEvent;
47 import java.awt.event.MouseEvent;
48 import java.awt.event.MouseWheelEvent;
49 import java.awt.event.MouseWheelListener;
50 import java.awt.font.FontRenderContext;
51 import java.awt.font.TextLayout;
52 import java.awt.geom.AffineTransform;
53 import java.awt.geom.Arc2D;
54 import java.awt.geom.CubicCurve2D;
55 import java.awt.geom.Ellipse2D;
56 import java.awt.geom.Line2D;
57 import java.awt.geom.Path2D;
58 import java.awt.geom.QuadCurve2D;
59 import java.awt.geom.Rectangle2D;
60 import java.awt.image.BufferedImage;
61 import java.awt.print.PageFormat;
62 import java.awt.print.Printable;
63 import java.awt.print.PrinterException;
64 import java.io.File;
65 import java.io.IOException;
66 import java.io.UnsupportedEncodingException;
67 import java.net.URI;
68 import java.net.URISyntaxException;
69 import java.net.URLEncoder;
70 import java.text.DecimalFormat;
71 import java.text.DecimalFormatSymbols;
72 import java.text.NumberFormat;
73 import java.util.ArrayList;
74 import java.util.Collections;
75 import java.util.HashMap;
76 import java.util.HashSet;
77 import java.util.Hashtable;
78 import java.util.List;
79 import java.util.Set;
80 import java.util.SortedSet;
81
82 import javax.swing.BorderFactory;
83 import javax.swing.JApplet;
84 import javax.swing.JColorChooser;
85 import javax.swing.JDialog;
86 import javax.swing.JMenuItem;
87 import javax.swing.JOptionPane;
88 import javax.swing.JPanel;
89 import javax.swing.JPopupMenu;
90 import javax.swing.JTextArea;
91 import javax.swing.Popup;
92 import javax.swing.PopupFactory;
93
94 import org.forester.archaeopteryx.Configuration.EXT_NODE_DATA_RETURN_ON;
95 import org.forester.archaeopteryx.ControlPanel.NodeClickAction;
96 import org.forester.archaeopteryx.Options.CLADOGRAM_TYPE;
97 import org.forester.archaeopteryx.Options.NODE_LABEL_DIRECTION;
98 import org.forester.archaeopteryx.Options.PHYLOGENY_GRAPHICS_TYPE;
99 import org.forester.archaeopteryx.phylogeny.data.RenderableDomainArchitecture;
100 import org.forester.archaeopteryx.phylogeny.data.RenderableVector;
101 import org.forester.archaeopteryx.tools.Blast;
102 import org.forester.archaeopteryx.tools.ImageLoader;
103 import org.forester.io.parsers.phyloxml.PhyloXmlUtil;
104 import org.forester.io.writers.SequenceWriter;
105 import org.forester.phylogeny.Phylogeny;
106 import org.forester.phylogeny.PhylogenyMethods;
107 import org.forester.phylogeny.PhylogenyMethods.DESCENDANT_SORT_PRIORITY;
108 import org.forester.phylogeny.PhylogenyNode;
109 import org.forester.phylogeny.data.Accession;
110 import org.forester.phylogeny.data.Annotation;
111 import org.forester.phylogeny.data.BranchColor;
112 import org.forester.phylogeny.data.Confidence;
113 import org.forester.phylogeny.data.Event;
114 import org.forester.phylogeny.data.NodeData.NODE_DATA;
115 import org.forester.phylogeny.data.NodeVisualization;
116 import org.forester.phylogeny.data.NodeVisualization.NodeFill;
117 import org.forester.phylogeny.data.NodeVisualization.NodeShape;
118 import org.forester.phylogeny.data.PhylogenyDataUtil;
119 import org.forester.phylogeny.data.PropertiesMap;
120 import org.forester.phylogeny.data.Property;
121 import org.forester.phylogeny.data.Sequence;
122 import org.forester.phylogeny.data.SequenceRelation;
123 import org.forester.phylogeny.data.Taxonomy;
124 import org.forester.phylogeny.data.Uri;
125 import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
126 import org.forester.phylogeny.iterators.PreorderTreeIterator;
127 import org.forester.util.BasicDescriptiveStatistics;
128 import org.forester.util.DescriptiveStatistics;
129 import org.forester.util.ForesterConstants;
130 import org.forester.util.ForesterUtil;
131 import org.forester.util.SequenceAccessionTools;
132 import org.forester.util.TaxonomyUtil;
133
134 public final class TreePanel extends JPanel implements ActionListener, MouseWheelListener, Printable {
135
136     final static Cursor                  ARROW_CURSOR                                       = Cursor.getPredefinedCursor( Cursor.DEFAULT_CURSOR );
137     final static Cursor                  CUT_CURSOR                                         = Cursor.getPredefinedCursor( Cursor.CROSSHAIR_CURSOR );
138     final static Cursor                  HAND_CURSOR                                        = Cursor.getPredefinedCursor( Cursor.HAND_CURSOR );
139     final static Cursor                  MOVE_CURSOR                                        = Cursor.getPredefinedCursor( Cursor.MOVE_CURSOR );
140     final static Cursor                  WAIT_CURSOR                                        = Cursor.getPredefinedCursor( Cursor.WAIT_CURSOR );
141     final private static double          _180_OVER_PI                                       = 180.0 / Math.PI;
142     private static final float           ANGLE_ROTATION_UNIT                                = ( float ) ( Math.PI / 32 );
143     private final static int             CONFIDENCE_LEFT_MARGIN                             = 4;
144     private final static int             EURO_D                                             = 10;
145     private final static NumberFormat    FORMATTER_BRANCH_LENGTH;
146     private final static NumberFormat    FORMATTER_CONFIDENCE;
147     private static final float           HALF_PI                                            = ( float ) ( Math.PI / 2.0 );
148     private final static int             LIMIT_FOR_HQ_RENDERING                             = 2000;
149     private final static int             MAX_NODE_FRAMES                                    = 10;
150     private final static int             MAX_SUBTREES                                       = 100;
151     private final static int             MIN_ROOT_LENGTH                                    = 3;
152     private final static int             MOVE                                               = 20;
153     private final static String          NODE_POPMENU_NODE_CLIENT_PROPERTY                  = "node";
154     private static final float           ONEHALF_PI                                         = ( float ) ( 1.5 * Math.PI );
155     private static final short           OV_BORDER                                          = 10;
156     private static final float           PI                                                 = ( float ) ( Math.PI );
157     final private static Font            POPUP_FONT                                         = new Font( Configuration.getDefaultFontFamilyName(),
158                                                                                                         Font.PLAIN,
159                                                                                                         12 );
160     private static final float           ROUNDED_D                                          = 8;
161     private final static long            serialVersionUID                                   = -978349745916505029L;
162     private static final BasicStroke     STROKE_005                                         = new BasicStroke( 0.05f );
163     private static final BasicStroke     STROKE_01                                          = new BasicStroke( 0.1f );
164     private static final BasicStroke     STROKE_025                                         = new BasicStroke( 0.25f );
165     private static final BasicStroke     STROKE_05                                          = new BasicStroke( 0.5f );
166     private static final BasicStroke     STROKE_075                                         = new BasicStroke( 0.75f );
167     private static final BasicStroke     STROKE_1                                           = new BasicStroke( 1f );
168     private static final BasicStroke     STROKE_2                                           = new BasicStroke( 2f );
169     private static final double          TWO_PI                                             = 2 * Math.PI;
170     private final static int             WIGGLE                                             = 2;
171     HashMap<Long, Short>                 _nodeid_dist_to_leaf                               = new HashMap<Long, Short>();
172     final private Arc2D                  _arc                                               = new Arc2D.Double();
173     private AffineTransform              _at;
174     private int                          _circ_max_depth;
175     final private Set<Long>              _collapsed_external_nodeid_set                     = new HashSet<Long>();
176     private JColorChooser                _color_chooser                                     = null;
177     private Configuration                _configuration                                     = null;
178     private ControlPanel                 _control_panel                                     = null;
179     private final CubicCurve2D           _cubic_curve                                       = new CubicCurve2D.Float();
180     private Set<Long>                    _current_external_nodes                            = null;
181     private StringBuilder                _current_external_nodes_data_buffer                = new StringBuilder();
182     private int                          _current_external_nodes_data_buffer_change_counter = 0;
183     private int                          _domain_structure_e_value_thr_exp                  = Constants.DOMAIN_STRUCTURE_E_VALUE_THR_DEFAULT_EXP;
184     private double                       _domain_structure_width                            = Constants.DOMAIN_STRUCTURE_DEFAULT_WIDTH;
185     private int                          _dynamic_hiding_factor                             = 0;
186     private boolean                      _edited                                            = false;
187     private final Ellipse2D              _ellipse                                           = new Ellipse2D.Float();
188     private int                          _external_node_index                               = 0;
189     private Set<Long>                    _found_nodes_0                                     = null;
190     private Set<Long>                    _found_nodes_1                                     = null;
191     private final FontRenderContext      _frc                                               = new FontRenderContext( null,
192                                                                                                                      false,
193                                                                                                                      false );
194     private PHYLOGENY_GRAPHICS_TYPE      _graphics_type                                     = PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR;
195     private PhylogenyNode                _highlight_node                                    = null;
196     private boolean                      _in_ov                                             = false;
197     private boolean                      _in_ov_rect                                        = false;
198     private float                        _last_drag_point_x                                 = 0;
199     private float                        _last_drag_point_y                                 = 0;
200     private final Line2D                 _line                                              = new Line2D.Float();
201     private int                          _longest_ext_node_info                             = 0;
202     private MainPanel                    _main_panel                                        = null;
203     private double                       _max_distance_to_root                              = -1;
204     private Popup                        _node_desc_popup;
205     private int                          _node_frame_index                                  = 0;
206     private final NodeFrame[]            _node_frames                                       = new NodeFrame[ TreePanel.MAX_NODE_FRAMES ];
207     private JPopupMenu                   _node_popup_menu                                   = null;
208     private JMenuItem                    _node_popup_menu_items[]                           = null;
209     private PhylogenyNode[]              _nodes_in_preorder                                 = null;
210     private Options                      _options                                           = null;
211     private float                        _ov_max_height                                     = 0;
212     private float                        _ov_max_width                                      = 0;
213     private boolean                      _ov_on                                             = false;
214     private final Rectangle2D            _ov_rectangle                                      = new Rectangle2D.Float();
215     private final Rectangle              _ov_virtual_rectangle                              = new Rectangle();
216     private float                        _ov_x_correction_factor                            = 0.0f;
217     private float                        _ov_x_distance                                     = 0;
218     private int                          _ov_x_position                                     = 0;
219     private float                        _ov_y_distance                                     = 0;
220     private int                          _ov_y_position                                     = 0;
221     private int                          _ov_y_start                                        = 0;
222     private final boolean                _phy_has_branch_lengths;
223     private Phylogeny                    _phylogeny                                         = null;
224     private final Path2D.Float           _polygon                                           = new Path2D.Float();
225     private final StringBuffer           _popup_buffer                                      = new StringBuffer();
226     private final QuadCurve2D            _quad_curve                                        = new QuadCurve2D.Float();
227     private Sequence                     _query_sequence                                    = null;
228     private final Rectangle2D            _rectangle                                         = new Rectangle2D.Float();
229     private final RenderingHints         _rendering_hints                                   = new RenderingHints( RenderingHints.KEY_RENDERING,
230                                                                                                                   RenderingHints.VALUE_RENDER_DEFAULT );
231     private JTextArea                    _rollover_popup;
232     private PhylogenyNode                _root;
233     private final StringBuilder          _sb                                                = new StringBuilder();
234     private double                       _scale_distance                                    = 0.0;
235     private String                       _scale_label                                       = null;
236     // expression values menu:
237     private DescriptiveStatistics        _statistics_for_vector_data;
238     private final Phylogeny[]            _sub_phylogenies                                   = new Phylogeny[ TreePanel.MAX_SUBTREES ];
239     private final PhylogenyNode[]        _sub_phylogenies_temp_roots                        = new PhylogenyNode[ TreePanel.MAX_SUBTREES ];
240     private int                          _subtree_index                                     = 0;
241     private File                         _treefile                                          = null;
242     private float                        _urt_factor                                        = 1;
243     private float                        _urt_factor_ov                                     = 1;
244     final private HashMap<Long, Double>  _urt_nodeid_angle_map                              = new HashMap<Long, Double>();
245     final private HashMap<Long, Integer> _urt_nodeid_index_map                              = new HashMap<Long, Integer>();
246     private double                       _urt_starting_angle                                = ( float ) ( Math.PI / 2 );
247     private float                        _x_correction_factor                               = 0.0f;
248     private float                        _x_distance                                        = 0.0f;
249     private float                        _y_distance                                        = 0.0f;
250     //  private Image                           offscreenImage;
251     //  private Graphics                        offscreenGraphics;
252     //  private Dimension                       offscreenDimension;
253     static {
254         final DecimalFormatSymbols dfs = new DecimalFormatSymbols();
255         dfs.setDecimalSeparator( '.' );
256         FORMATTER_CONFIDENCE = new DecimalFormat( "#.###", dfs );
257         FORMATTER_BRANCH_LENGTH = new DecimalFormat( "#.###", dfs );
258     }
259
260     TreePanel( final Phylogeny t, final Configuration configuration, final MainPanel tjp ) {
261         requestFocusInWindow();
262         addKeyListener( new KeyAdapter() {
263
264             @Override
265             public void keyPressed( final KeyEvent key_event ) {
266                 keyPressedCalls( key_event );
267                 requestFocusInWindow();
268             }
269         } );
270         addFocusListener( new FocusAdapter() {
271
272             @Override
273             public void focusGained( final FocusEvent e ) {
274                 requestFocusInWindow();
275             }
276         } );
277         if ( ( t == null ) || t.isEmpty() ) {
278             throw new IllegalArgumentException( "attempt to draw phylogeny which is null or empty" );
279         }
280         _graphics_type = tjp.getOptions().getPhylogenyGraphicsType();
281         _main_panel = tjp;
282         _configuration = configuration;
283         _phylogeny = t;
284         _phy_has_branch_lengths = AptxUtil.isHasAtLeastOneBranchLengthLargerThanZero( _phylogeny );
285         init();
286         // if ( !_phylogeny.isEmpty() ) {
287         _phylogeny.recalculateNumberOfExternalDescendants( true );
288         checkForVectorProperties( _phylogeny );
289         // }
290         setBackground( getTreeColorSet().getBackgroundColor() );
291         final MouseListener mouse_listener = new MouseListener( this );
292         addMouseListener( mouse_listener );
293         addMouseMotionListener( mouse_listener );
294         addMouseWheelListener( this );
295         calculateScaleDistance();
296         FORMATTER_CONFIDENCE.setMaximumFractionDigits( configuration.getNumberOfDigitsAfterCommaForConfidenceValues() );
297         FORMATTER_BRANCH_LENGTH.setMaximumFractionDigits( configuration
298                 .getNumberOfDigitsAfterCommaForBranchLengthValues() );
299     }
300
301     @Override
302     final public void actionPerformed( final ActionEvent e ) {
303         boolean done = false;
304         final JMenuItem node_popup_menu_item = ( JMenuItem ) e.getSource();
305         for( int index = 0; ( index < _node_popup_menu_items.length ) && !done; index++ ) {
306             // NOTE: index corresponds to the indices of click-to options
307             // in the control panel.
308             if ( node_popup_menu_item == _node_popup_menu_items[ index ] ) {
309                 // Set this as the new default click-to action
310                 _main_panel.getControlPanel().setClickToAction( index );
311                 final PhylogenyNode node = ( PhylogenyNode ) _node_popup_menu
312                         .getClientProperty( NODE_POPMENU_NODE_CLIENT_PROPERTY );
313                 handleClickToAction( _control_panel.getActionWhenNodeClicked(), node );
314                 done = true;
315             }
316         }
317         repaint();
318         requestFocusInWindow();
319     }
320
321     public synchronized Hashtable<String, BufferedImage> getImageMap() {
322         return getMainPanel().getImageMap();
323     }
324
325     final public MainPanel getMainPanel() {
326         return _main_panel;
327     }
328
329     /**
330      * Get a pointer to the phylogeny 
331      * 
332      * @return a pointer to the phylogeny
333      */
334     public final Phylogeny getPhylogeny() {
335         return _phylogeny;
336     }
337
338     @Override
339     final public void mouseWheelMoved( final MouseWheelEvent e ) {
340         final int notches = e.getWheelRotation();
341         if ( inOvVirtualRectangle( e ) ) {
342             if ( !isInOvRect() ) {
343                 setInOvRect( true );
344                 repaint();
345             }
346         }
347         else {
348             if ( isInOvRect() ) {
349                 setInOvRect( false );
350                 repaint();
351             }
352         }
353         if ( e.isControlDown() ) {
354             if ( notches < 0 ) {
355                 getTreeFontSet().increaseFontSize();
356                 getControlPanel().displayedPhylogenyMightHaveChanged( true );
357             }
358             else {
359                 getTreeFontSet().decreaseFontSize( 1, false );
360                 getControlPanel().displayedPhylogenyMightHaveChanged( true );
361             }
362         }
363         else if ( e.isShiftDown() ) {
364             if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
365                     || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
366                 if ( notches < 0 ) {
367                     for( int i = 0; i < ( -notches ); ++i ) {
368                         setStartingAngle( ( getStartingAngle() % TWO_PI ) + ANGLE_ROTATION_UNIT );
369                         getControlPanel().displayedPhylogenyMightHaveChanged( false );
370                     }
371                 }
372                 else {
373                     for( int i = 0; i < notches; ++i ) {
374                         setStartingAngle( ( getStartingAngle() % TWO_PI ) - ANGLE_ROTATION_UNIT );
375                         if ( getStartingAngle() < 0 ) {
376                             setStartingAngle( TWO_PI + getStartingAngle() );
377                         }
378                         getControlPanel().displayedPhylogenyMightHaveChanged( false );
379                     }
380                 }
381             }
382             else {
383                 if ( notches < 0 ) {
384                     for( int i = 0; i < ( -notches ); ++i ) {
385                         getControlPanel().zoomInY( Constants.WHEEL_ZOOM_IN_FACTOR );
386                         getControlPanel().displayedPhylogenyMightHaveChanged( false );
387                     }
388                 }
389                 else {
390                     for( int i = 0; i < notches; ++i ) {
391                         getControlPanel().zoomOutY( Constants.WHEEL_ZOOM_OUT_FACTOR );
392                         getControlPanel().displayedPhylogenyMightHaveChanged( false );
393                     }
394                 }
395             }
396         }
397         else {
398             if ( notches < 0 ) {
399                 for( int i = 0; i < ( -notches ); ++i ) {
400                     getControlPanel().zoomInX( Constants.WHEEL_ZOOM_IN_FACTOR,
401                                                Constants.WHEEL_ZOOM_IN_X_CORRECTION_FACTOR );
402                     getControlPanel().zoomInY( Constants.WHEEL_ZOOM_IN_FACTOR );
403                     getControlPanel().displayedPhylogenyMightHaveChanged( false );
404                 }
405             }
406             else {
407                 for( int i = 0; i < notches; ++i ) {
408                     getControlPanel().zoomOutY( Constants.WHEEL_ZOOM_OUT_FACTOR );
409                     getControlPanel().zoomOutX( Constants.WHEEL_ZOOM_OUT_FACTOR,
410                                                 Constants.WHEEL_ZOOM_OUT_X_CORRECTION_FACTOR );
411                     getControlPanel().displayedPhylogenyMightHaveChanged( false );
412                 }
413             }
414         }
415         requestFocus();
416         requestFocusInWindow();
417         requestFocus();
418     }
419
420     @Override
421     final public void paintComponent( final Graphics g ) {
422         // Dimension currentSize = getSize();
423         //  if ( offscreenImage == null || !currentSize.equals( offscreenDimension ) ) {
424         // call the 'java.awt.Component.createImage(...)' method to get an
425         // image
426         //   offscreenImage = createImage( currentSize.width, currentSize.height );
427         //  offscreenGraphics = offscreenImage.getGraphics();
428         //  offscreenDimension = currentSize;
429         // }
430         // super.paintComponent( g ); //why?
431         //final Graphics2D g2d = ( Graphics2D ) offscreenGraphics;
432         final Graphics2D g2d = ( Graphics2D ) g;
433         g2d.setRenderingHints( _rendering_hints );
434         paintPhylogeny( g2d, false, false, 0, 0, 0, 0 );
435         //g.drawImage( offscreenImage, 0, 0, this );
436     }
437
438     @Override
439     final public int print( final Graphics g, final PageFormat page_format, final int page_index )
440             throws PrinterException {
441         if ( page_index > 0 ) {
442             return ( NO_SUCH_PAGE );
443         }
444         else {
445             final Graphics2D g2d = ( Graphics2D ) g;
446             g2d.translate( page_format.getImageableX(), page_format.getImageableY() );
447             // Turn off double buffering !?
448             paintPhylogeny( g2d, true, false, 0, 0, 0, 0 );
449             // Turn double buffering back on !?
450             return ( PAGE_EXISTS );
451         }
452     }
453
454     public final void setEdited( final boolean edited ) {
455         _edited = edited;
456     }
457
458     public synchronized void setImageMap( final Hashtable<String, BufferedImage> image_map ) {
459         getMainPanel().setImageMap( image_map );
460     }
461
462     /**
463      * Set a phylogeny tree.
464      * 
465      * @param t
466      *            an instance of a Phylogeny
467      */
468     public final void setTree( final Phylogeny t ) {
469         setNodeInPreorderToNull();
470         _phylogeny = t;
471     }
472
473     public final void setWaitCursor() {
474         setCursor( WAIT_CURSOR );
475         repaint();
476     }
477
478     @Override
479     public void update( final Graphics g ) {
480         paint( g );
481     }
482
483     final void calcMaxDepth() {
484         if ( _phylogeny != null ) {
485             _circ_max_depth = PhylogenyMethods.calculateMaxDepth( _phylogeny );
486         }
487     }
488
489     /**
490      * Set parameters for printing the displayed tree
491      * 
492      */
493     final void calcParametersForPainting( final int x, final int y, final boolean recalc_longest_ext_node_info ) {
494         // updateStyle(); not needed?
495         if ( ( _phylogeny != null ) && !_phylogeny.isEmpty() ) {
496             initNodeData();
497             if ( recalc_longest_ext_node_info ) {
498                 calculateLongestExtNodeInfo();
499                 if ( getOptions().isAllowFontSizeChange() ) {
500                     if ( ( getLongestExtNodeInfo() > ( x * 0.6 ) )
501                             && ( getTreeFontSet().getLargeFont().getSize() > 2 + TreeFontSet.FONT_SIZE_CHANGE_STEP ) ) {
502                         while ( ( getLongestExtNodeInfo() > ( x * 0.7 ) )
503                                 && ( getTreeFontSet().getLargeFont().getSize() > 2 ) ) {
504                             getMainPanel().getTreeFontSet().decreaseFontSize( getConfiguration().getMinBaseFontSize(),
505                                                                               true );
506                             calculateLongestExtNodeInfo();
507                         }
508                     }
509                     else {
510                         while ( ( getLongestExtNodeInfo() < ( x * 0.6 ) )
511                                 && ( getTreeFontSet().getLargeFont().getSize() <= getTreeFontSet().getLargeFontMemory()
512                                         .getSize() - TreeFontSet.FONT_SIZE_CHANGE_STEP ) ) {
513                             getMainPanel().getTreeFontSet().increaseFontSize();
514                             calculateLongestExtNodeInfo();
515                         }
516                     }
517                 }
518             }
519             int ext_nodes = _phylogeny.getRoot().getNumberOfExternalNodes();
520             final int max_depth = PhylogenyMethods.calculateMaxDepth( _phylogeny );
521             if ( ext_nodes == 1 ) {
522                 ext_nodes = max_depth;
523                 if ( ext_nodes < 1 ) {
524                     ext_nodes = 1;
525                 }
526             }
527             updateOvSizes();
528             float xdist = 0;
529             float ov_xdist = 0;
530             if ( !isNonLinedUpCladogram() && !isUniformBranchLengthsForCladogram() ) {
531                 xdist = ( float ) ( ( x - getLongestExtNodeInfo() - TreePanel.MOVE ) / ( ext_nodes + 3.0 ) );
532                 ov_xdist = ( float ) ( getOvMaxWidth() / ( ext_nodes + 3.0 ) );
533             }
534             else {
535                 xdist = ( ( x - getLongestExtNodeInfo() - TreePanel.MOVE ) / ( max_depth + 1 ) );
536                 ov_xdist = ( getOvMaxWidth() / ( max_depth + 1 ) );
537             }
538             float ydist = ( float ) ( ( y - TreePanel.MOVE ) / ( ext_nodes * 2.0 ) );
539             if ( xdist < 0.0 ) {
540                 xdist = 0.0f;
541             }
542             if ( ov_xdist < 0.0 ) {
543                 ov_xdist = 0.0f;
544             }
545             if ( ydist < 0.0 ) {
546                 ydist = 0.0f;
547             }
548             setXdistance( xdist );
549             setYdistance( ydist );
550             setOvXDistance( ov_xdist );
551             final double height = _phylogeny.getHeight();
552             if ( height > 0 ) {
553                 final float corr = ( float ) ( ( x - TreePanel.MOVE - getLongestExtNodeInfo() - getXdistance() ) / height );
554                 setXcorrectionFactor( corr > 0 ? corr : 0 );
555                 final float ov_corr = ( float ) ( ( getOvMaxWidth() - getOvXDistance() ) / height );
556                 setOvXcorrectionFactor( ov_corr > 0 ? ov_corr : 0 );
557             }
558             else {
559                 setXcorrectionFactor( 0 );
560                 setOvXcorrectionFactor( 0 );
561             }
562             _circ_max_depth = max_depth;
563             setUpUrtFactor();
564             //
565             if ( getOptions().isAllowFontSizeChange() ) {
566                 if ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
567                         && ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
568                     //                int dynamic_hiding_factor = calcDynamicHidingFactor();
569                     //                if ( dynamic_hiding_factor > 1 ) {
570                     //                    while ( dynamic_hiding_factor > 1
571                     //                            && getTreeFontSet()._fm_large.getHeight() > TreeFontSet.SMALL_FONTS_BASE ) {
572                     //                        getTreeFontSet().decreaseFontSize( 1, true );
573                     //                        dynamic_hiding_factor = calcDynamicHidingFactor();
574                     //                    }
575                     //                }
576                     //                else if ( getTreeFontSet().isDecreasedSizeBySystem() ) {
577                     //                    while ( dynamic_hiding_factor < 1 && getTreeFontSet()._fm_large.getHeight() < 12 ) {
578                     //                        getTreeFontSet().increaseFontSize();
579                     //                        dynamic_hiding_factor = calcDynamicHidingFactor();
580                     //                    }
581                     //                }
582                 }
583             }
584             //
585         }
586     }
587
588     final void calculateLongestExtNodeInfo() {
589         if ( ( _phylogeny == null ) || _phylogeny.isEmpty() ) {
590             return;
591         }
592         int max_length = ForesterUtil.roundToInt( ( getSize().getWidth() - MOVE )
593                 * Constants.EXT_NODE_INFO_LENGTH_MAX_RATIO );
594         if ( max_length < 40 ) {
595             max_length = 40;
596         }
597         int longest = 30;
598         for( final PhylogenyNode node : _phylogeny.getExternalNodes() ) {
599             int sum = 0;
600             if ( node.isCollapse() ) {
601                 continue;
602             }
603             if ( getControlPanel().isShowNodeNames() ) {
604                 sum += getTreeFontSet()._fm_large.stringWidth( node.getName() + " " );
605             }
606             if ( node.getNodeData().isHasSequence() ) {
607                 if ( getControlPanel().isShowSequenceAcc()
608                         && ( node.getNodeData().getSequence().getAccession() != null ) ) {
609                     sum += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getAccession()
610                             .getValue()
611                             + " " );
612                 }
613                 if ( getControlPanel().isShowSeqNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
614                     sum += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getName() + " " );
615                 }
616                 if ( getControlPanel().isShowSeqSymbols()
617                         && ( node.getNodeData().getSequence().getSymbol().length() > 0 ) ) {
618                     sum += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getSymbol() + " " );
619                 }
620                 if ( getControlPanel().isShowGeneNames()
621                         && ( node.getNodeData().getSequence().getGeneName().length() > 0 ) ) {
622                     sum += getTreeFontSet()._fm_large
623                             .stringWidth( node.getNodeData().getSequence().getGeneName() + " " );
624                 }
625                 if ( getControlPanel().isShowAnnotation()
626                         && ( node.getNodeData().getSequence().getAnnotations() != null )
627                         && !node.getNodeData().getSequence().getAnnotations().isEmpty() ) {
628                     sum += getTreeFontSet()._fm_large.stringWidth( TreePanelUtil.createAnnotationString( node
629                             .getNodeData().getSequence().getAnnotations(), getOptions().isShowAnnotationRefSource() )
630                             + " " );
631                 }
632                 if ( getControlPanel().isShowDomainArchitectures()
633                         && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) {
634                     sum += ( ( RenderableDomainArchitecture ) node.getNodeData().getSequence().getDomainArchitecture() )
635                             .getRenderingSize().getWidth();
636                 }
637             }
638             if ( node.getNodeData().isHasTaxonomy() ) {
639                 final Taxonomy tax = node.getNodeData().getTaxonomy();
640                 if ( getControlPanel().isShowTaxonomyCode() && !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
641                     sum += getTreeFontSet()._fm_large_italic.stringWidth( tax.getTaxonomyCode() + " " );
642                 }
643                 if ( getControlPanel().isShowTaxonomyScientificNames()
644                         && !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
645                     sum += getTreeFontSet()._fm_large_italic.stringWidth( tax.getScientificName() + " " );
646                 }
647                 if ( getControlPanel().isShowTaxonomyCommonNames() && !ForesterUtil.isEmpty( tax.getCommonName() ) ) {
648                     sum += getTreeFontSet()._fm_large_italic.stringWidth( tax.getCommonName() + " ()" );
649                 }
650             }
651             if ( getControlPanel().isShowProperties() && node.getNodeData().isHasProperties() ) {
652                 sum += getTreeFontSet()._fm_large.stringWidth( propertiesToString( node ).toString() );
653             }
654             if ( getControlPanel().isShowBinaryCharacters() && node.getNodeData().isHasBinaryCharacters() ) {
655                 sum += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getBinaryCharacters()
656                         .getGainedCharactersAsStringBuffer().toString() );
657             }
658             if ( sum >= max_length ) {
659                 setLongestExtNodeInfo( max_length );
660                 return;
661             }
662             if ( sum > longest ) {
663                 longest = sum;
664             }
665         }
666         if ( longest >= max_length ) {
667             setLongestExtNodeInfo( max_length );
668         }
669         else {
670             setLongestExtNodeInfo( longest );
671         }
672     }
673
674     final void calculateScaleDistance() {
675         if ( ( _phylogeny == null ) || _phylogeny.isEmpty() ) {
676             return;
677         }
678         final double height = getMaxDistanceToRoot();
679         if ( height > 0 ) {
680             if ( ( height <= 0.5 ) ) {
681                 setScaleDistance( 0.01 );
682             }
683             else if ( height <= 5.0 ) {
684                 setScaleDistance( 0.1 );
685             }
686             else if ( height <= 50.0 ) {
687                 setScaleDistance( 1 );
688             }
689             else if ( height <= 500.0 ) {
690                 setScaleDistance( 10 );
691             }
692             else {
693                 setScaleDistance( 100 );
694             }
695         }
696         else {
697             setScaleDistance( 0.0 );
698         }
699         String scale_label = String.valueOf( getScaleDistance() );
700         if ( !ForesterUtil.isEmpty( _phylogeny.getDistanceUnit() ) ) {
701             scale_label += " [" + _phylogeny.getDistanceUnit() + "]";
702         }
703         setScaleLabel( scale_label );
704     }
705
706     final Color calculateTaxonomyBasedColor( final Taxonomy tax ) {
707         if ( getOptions().isColorByTaxonomicGroup() && !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
708             boolean ex = false;
709             String group = null;
710             try {
711                 group = TaxonomyUtil.getTaxGroupByTaxCode( tax.getTaxonomyCode() );
712             }
713             catch ( final Exception e ) {
714                 ex = true;
715             }
716             if ( !ex && !ForesterUtil.isEmpty( group ) ) {
717                 final Color c = ForesterUtil.obtainColorDependingOnTaxonomyGroup( group );
718                 if ( c != null ) {
719                     return c;
720                 }
721             }
722             return getTreeColorSet().getTaxonomyColor();
723         }
724         else {
725             if ( ForesterUtil.isEmpty( tax.getTaxonomyCode() ) && ForesterUtil.isEmpty( tax.getScientificName() ) ) {
726                 return getTreeColorSet().getTaxonomyColor();
727             }
728             Color c = null;
729             if ( !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
730                 c = getControlPanel().getSpeciesColors().get( tax.getTaxonomyCode() );
731             }
732             if ( ( c == null ) && !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
733                 c = getControlPanel().getSpeciesColors().get( tax.getScientificName() );
734             }
735             if ( c == null ) {
736                 if ( !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
737                     c = TreePanelUtil.calculateColorFromString( tax.getTaxonomyCode(), true );
738                     getControlPanel().getSpeciesColors().put( tax.getTaxonomyCode(), c );
739                 }
740                 else {
741                     c = TreePanelUtil.calculateColorFromString( tax.getScientificName(), true );
742                     getControlPanel().getSpeciesColors().put( tax.getScientificName(), c );
743                 }
744             }
745             return c;
746         }
747     }
748
749     void checkForVectorProperties( final Phylogeny phy ) {
750         final DescriptiveStatistics stats = new BasicDescriptiveStatistics();
751         for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
752             final PhylogenyNode node = iter.next();
753             if ( node.getNodeData().getProperties() != null ) {
754                 final PropertiesMap pm = node.getNodeData().getProperties();
755                 final double[] vector = new double[ pm.getProperties().size() ];
756                 int counter = 0;
757                 for( final String ref : pm.getProperties().keySet() ) {
758                     if ( ref.startsWith( PhyloXmlUtil.VECTOR_PROPERTY_REF ) ) {
759                         final Property p = pm.getProperty( ref );
760                         final String value_str = p.getValue();
761                         final String index_str = ref
762                                 .substring( PhyloXmlUtil.VECTOR_PROPERTY_REF.length(), ref.length() );
763                         double d = -100;
764                         try {
765                             d = Double.parseDouble( value_str );
766                         }
767                         catch ( final NumberFormatException e ) {
768                             JOptionPane.showMessageDialog( this, "Could not parse \"" + value_str
769                                     + "\" into a decimal value", "Problem with Vector Data", JOptionPane.ERROR_MESSAGE );
770                             return;
771                         }
772                         int i = -1;
773                         try {
774                             i = Integer.parseInt( index_str );
775                         }
776                         catch ( final NumberFormatException e ) {
777                             JOptionPane.showMessageDialog( this,
778                                                            "Could not parse \"" + index_str
779                                                                    + "\" into index for vector data",
780                                                            "Problem with Vector Data",
781                                                            JOptionPane.ERROR_MESSAGE );
782                             return;
783                         }
784                         if ( i < 0 ) {
785                             JOptionPane.showMessageDialog( this,
786                                                            "Attempt to use negative index for vector data",
787                                                            "Problem with Vector Data",
788                                                            JOptionPane.ERROR_MESSAGE );
789                             return;
790                         }
791                         vector[ i ] = d;
792                         ++counter;
793                         stats.addValue( d );
794                     }
795                 }
796                 final List<Double> vector_l = new ArrayList<Double>( counter );
797                 for( int i = 0; i < counter; ++i ) {
798                     vector_l.add( vector[ i ] );
799                 }
800                 node.getNodeData().setVector( vector_l );
801             }
802         }
803         if ( stats.getN() > 0 ) {
804             _statistics_for_vector_data = stats;
805         }
806     }
807
808     void clearCurrentExternalNodesDataBuffer() {
809         setCurrentExternalNodesDataBuffer( new StringBuilder() );
810     }
811
812     /**
813      * Collapse the tree from the given node
814      * 
815      * @param node
816      *            a PhylogenyNode
817      */
818     final void collapse( final PhylogenyNode node ) {
819         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
820             JOptionPane.showMessageDialog( this,
821                                            "Cannot collapse in unrooted display type",
822                                            "Attempt to collapse in unrooted display",
823                                            JOptionPane.WARNING_MESSAGE );
824             return;
825         }
826         if ( !node.isExternal() && !node.isRoot() ) {
827             final boolean collapse = !node.isCollapse();
828             TreePanelUtil.collapseSubtree( node, collapse );
829             updateSetOfCollapsedExternalNodes();
830             _phylogeny.recalculateNumberOfExternalDescendants( true );
831             resetNodeIdToDistToLeafMap();
832             calculateLongestExtNodeInfo();
833             setNodeInPreorderToNull();
834             _control_panel.displayedPhylogenyMightHaveChanged( true );
835             resetPreferredSize();
836             updateOvSizes();
837             _main_panel.adjustJScrollPane();
838             repaint();
839         }
840     }
841
842     final void collapseSpeciesSpecificSubtrees() {
843         if ( ( _phylogeny == null ) || ( _phylogeny.getNumberOfExternalNodes() < 2 ) ) {
844             return;
845         }
846         setWaitCursor();
847         TreePanelUtil.collapseSpeciesSpecificSubtrees( _phylogeny );
848         updateSetOfCollapsedExternalNodes();
849         _phylogeny.recalculateNumberOfExternalDescendants( true );
850         resetNodeIdToDistToLeafMap();
851         calculateLongestExtNodeInfo();
852         setNodeInPreorderToNull();
853         resetPreferredSize();
854         _main_panel.adjustJScrollPane();
855         setArrowCursor();
856         repaint();
857     }
858
859     final void colorRank( final String rank ) {
860         if ( ( _phylogeny == null ) || ( _phylogeny.getNumberOfExternalNodes() < 2 ) ) {
861             return;
862         }
863         setWaitCursor();
864         AptxUtil.removeBranchColors( _phylogeny );
865         final int colorizations = TreePanelUtil.colorPhylogenyAccordingToRanks( _phylogeny, rank, this );
866         if ( colorizations > 0 ) {
867             _control_panel.setColorBranches( true );
868             if ( _control_panel.getColorBranchesCb() != null ) {
869                 _control_panel.getColorBranchesCb().setSelected( true );
870             }
871             if ( _control_panel.getColorAccSpeciesCb() != null ) {
872                 _control_panel.getColorAccSpeciesCb().setSelected( false );
873             }
874             _options.setColorLabelsSameAsParentBranch( true );
875             _control_panel.repaint();
876         }
877         setArrowCursor();
878         repaint();
879         if ( colorizations > 0 ) {
880             String msg = "Taxonomy colorization via " + rank + " completed:\n";
881             if ( colorizations > 1 ) {
882                 msg += "colorized " + colorizations + " subtrees";
883             }
884             else {
885                 msg += "colorized one subtree";
886             }
887             setEdited( true );
888             JOptionPane.showMessageDialog( this,
889                                            msg,
890                                            "Taxonomy Colorization Completed (" + rank + ")",
891                                            JOptionPane.INFORMATION_MESSAGE );
892         }
893         else {
894             String msg = "Could not taxonomy colorize any subtree via " + rank + ".\n";
895             msg += "Possible solutions (given that suitable taxonomic information is present):\n";
896             msg += "select a different rank (e.g. phylum, genus, ...)\n";
897             msg += "  and/or\n";
898             msg += "execute:\n";
899             msg += "1. \"" + MainFrameApplication.OBTAIN_DETAILED_TAXONOMIC_INFORMATION + "\" (Tools)\n";
900             msg += "2. \"" + MainFrameApplication.INFER_ANCESTOR_TAXONOMIES + "\" (Analysis)";
901             JOptionPane.showMessageDialog( this, msg, "Taxonomy Colorization Failed", JOptionPane.WARNING_MESSAGE );
902         }
903     }
904
905     final void confColor() {
906         if ( ( _phylogeny == null ) || ( _phylogeny.getNumberOfExternalNodes() < 2 ) ) {
907             return;
908         }
909         setWaitCursor();
910         AptxUtil.removeBranchColors( _phylogeny );
911         TreePanelUtil.colorPhylogenyAccordingToConfidenceValues( _phylogeny, this );
912         _control_panel.setColorBranches( true );
913         if ( _control_panel.getColorBranchesCb() != null ) {
914             _control_panel.getColorBranchesCb().setSelected( true );
915         }
916         setArrowCursor();
917         repaint();
918     }
919
920     final void decreaseDomainStructureEvalueThreshold() {
921         if ( _domain_structure_e_value_thr_exp > -20 ) {
922             _domain_structure_e_value_thr_exp -= 1;
923         }
924     }
925
926     /**
927      * Find the node, if any, at the given location
928      * 
929      * @param x
930      * @param y
931      * @return pointer to the node at x,y, null if not found
932      */
933     final PhylogenyNode findNode( final int x, final int y ) {
934         if ( ( _phylogeny == null ) || _phylogeny.isEmpty() ) {
935             return null;
936         }
937         final int half_box_size_plus_wiggle = ( getOptions().getDefaultNodeShapeSize() / 2 ) + WIGGLE;
938         for( final PhylogenyNodeIterator iter = _phylogeny.iteratorPostorder(); iter.hasNext(); ) {
939             final PhylogenyNode node = iter.next();
940             if ( ( _phylogeny.isRooted() || !node.isRoot() || ( node.getNumberOfDescendants() > 2 ) )
941                     && ( ( node.getXcoord() - half_box_size_plus_wiggle ) <= x )
942                     && ( ( node.getXcoord() + half_box_size_plus_wiggle ) >= x )
943                     && ( ( node.getYcoord() - half_box_size_plus_wiggle ) <= y )
944                     && ( ( node.getYcoord() + half_box_size_plus_wiggle ) >= y ) ) {
945                 return node;
946             }
947         }
948         return null;
949     }
950
951     final Configuration getConfiguration() {
952         return _configuration;
953     }
954
955     final ControlPanel getControlPanel() {
956         return _control_panel;
957     }
958
959     String getCurrentExternalNodesDataBufferAsString() {
960         return _current_external_nodes_data_buffer.toString();
961     }
962
963     int getCurrentExternalNodesDataBufferChangeCounter() {
964         return _current_external_nodes_data_buffer_change_counter;
965     }
966
967     final int getDomainStructureEvalueThreshold() {
968         return _domain_structure_e_value_thr_exp;
969     }
970
971     final Set<Long> getFoundNodes0() {
972         return _found_nodes_0;
973     }
974
975     final Set<Long> getFoundNodes1() {
976         return _found_nodes_1;
977     }
978
979     final Color getGraphicsForNodeBoxWithColorForParentBranch( final PhylogenyNode node ) {
980         if ( getControlPanel().isColorBranches() && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
981             return ( PhylogenyMethods.getBranchColorValue( node ) );
982         }
983         else {
984             return ( getTreeColorSet().getBranchColor() );
985         }
986     }
987
988     final int getLongestExtNodeInfo() {
989         return _longest_ext_node_info;
990     }
991
992     final Options getOptions() {
993         if ( _options == null ) {
994             _options = getControlPanel().getOptions();
995         }
996         return _options;
997     }
998
999     final Rectangle2D getOvRectangle() {
1000         return _ov_rectangle;
1001     }
1002
1003     final Rectangle getOvVirtualRectangle() {
1004         return _ov_virtual_rectangle;
1005     }
1006
1007     final PHYLOGENY_GRAPHICS_TYPE getPhylogenyGraphicsType() {
1008         return _graphics_type;
1009     }
1010
1011     final double getStartingAngle() {
1012         return _urt_starting_angle;
1013     }
1014
1015     DescriptiveStatistics getStatisticsForExpressionValues() {
1016         return _statistics_for_vector_data;
1017     }
1018
1019     /**
1020      * Find a color for this species name.
1021      * 
1022      * @param species
1023      * @return the species color
1024      */
1025     final Color getTaxonomyBasedColor( final PhylogenyNode node ) {
1026         if ( node.getNodeData().isHasTaxonomy() ) {
1027             return calculateTaxonomyBasedColor( node.getNodeData().getTaxonomy() );
1028         }
1029         // return non-colorized color
1030         return getTreeColorSet().getTaxonomyColor();
1031     }
1032
1033     /**
1034      * @return pointer to colorset for tree drawing
1035      */
1036     final TreeColorSet getTreeColorSet() {
1037         return getMainPanel().getTreeColorSet();
1038     }
1039
1040     final File getTreeFile() {
1041         return _treefile;
1042     }
1043
1044     final float getXcorrectionFactor() {
1045         return _x_correction_factor;
1046     }
1047
1048     final float getXdistance() {
1049         return _x_distance;
1050     }
1051
1052     final float getYdistance() {
1053         return _y_distance;
1054     }
1055
1056     final void increaseDomainStructureEvalueThreshold() {
1057         if ( _domain_structure_e_value_thr_exp < 3 ) {
1058             _domain_structure_e_value_thr_exp += 1;
1059         }
1060     }
1061
1062     final void initNodeData() {
1063         if ( ( _phylogeny == null ) || _phylogeny.isEmpty() ) {
1064             return;
1065         }
1066         double max_original_domain_structure_width = 0.0;
1067         for( final PhylogenyNode node : _phylogeny.getExternalNodes() ) {
1068             if ( node.getNodeData().isHasSequence()
1069                     && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) {
1070                 RenderableDomainArchitecture rds = null;
1071                 if ( !( node.getNodeData().getSequence().getDomainArchitecture() instanceof RenderableDomainArchitecture ) ) {
1072                     rds = new RenderableDomainArchitecture( node.getNodeData().getSequence().getDomainArchitecture(),
1073                                                             getConfiguration() );
1074                     node.getNodeData().getSequence().setDomainArchitecture( rds );
1075                 }
1076                 else {
1077                     rds = ( RenderableDomainArchitecture ) node.getNodeData().getSequence().getDomainArchitecture();
1078                 }
1079                 if ( getControlPanel().isShowDomainArchitectures() ) {
1080                     final double dsw = rds.getOriginalSize().getWidth();
1081                     if ( dsw > max_original_domain_structure_width ) {
1082                         max_original_domain_structure_width = dsw;
1083                     }
1084                 }
1085             }
1086         }
1087         if ( getControlPanel().isShowDomainArchitectures() ) {
1088             final double ds_factor_width = _domain_structure_width / max_original_domain_structure_width;
1089             for( final PhylogenyNode node : _phylogeny.getExternalNodes() ) {
1090                 if ( node.getNodeData().isHasSequence()
1091                         && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) {
1092                     final RenderableDomainArchitecture rds = ( RenderableDomainArchitecture ) node.getNodeData()
1093                             .getSequence().getDomainArchitecture();
1094                     rds.setRenderingFactorWidth( ds_factor_width );
1095                     rds.setParameter( _domain_structure_e_value_thr_exp );
1096                 }
1097             }
1098         }
1099     }
1100
1101     final boolean inOv( final MouseEvent e ) {
1102         return ( ( e.getX() > ( getVisibleRect().x + getOvXPosition() + 1 ) )
1103                 && ( e.getX() < ( ( getVisibleRect().x + getOvXPosition() + getOvMaxWidth() ) - 1 ) )
1104                 && ( e.getY() > ( getVisibleRect().y + getOvYPosition() + 1 ) ) && ( e.getY() < ( ( getVisibleRect().y
1105                 + getOvYPosition() + getOvMaxHeight() ) - 1 ) ) );
1106     }
1107
1108     final boolean inOvRectangle( final MouseEvent e ) {
1109         return ( ( e.getX() >= ( getOvRectangle().getX() - 1 ) )
1110                 && ( e.getX() <= ( getOvRectangle().getX() + getOvRectangle().getWidth() + 1 ) )
1111                 && ( e.getY() >= ( getOvRectangle().getY() - 1 ) ) && ( e.getY() <= ( getOvRectangle().getY()
1112                 + getOvRectangle().getHeight() + 1 ) ) );
1113     }
1114
1115     final boolean isApplet() {
1116         return getMainPanel() instanceof MainPanelApplets;
1117     }
1118
1119     final boolean isCanCollapse() {
1120         return ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
1121     }
1122
1123     final boolean isCanColorSubtree() {
1124         return ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
1125     }
1126
1127     final boolean isCanCopy() {
1128         return ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && getOptions().isEditable() );
1129     }
1130
1131     final boolean isCanCut( final PhylogenyNode node ) {
1132         return ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && getOptions().isEditable() && !node
1133                 .isRoot() );
1134     }
1135
1136     final boolean isCanDelete() {
1137         return ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && getOptions().isEditable() );
1138     }
1139
1140     final boolean isCanPaste() {
1141         return ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && getOptions().isEditable()
1142                 && ( getCutOrCopiedTree() != null ) && !getCutOrCopiedTree().isEmpty() );
1143     }
1144
1145     final boolean isCanReroot() {
1146         return ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && ( _subtree_index < 1 ) );
1147     }
1148
1149     final boolean isCanSubtree( final PhylogenyNode node ) {
1150         return ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) && !node.isExternal() && ( !node
1151                 .isRoot() || ( _subtree_index > 0 ) ) );
1152     }
1153
1154     final boolean isCurrentTreeIsSubtree() {
1155         return ( _subtree_index > 0 );
1156     }
1157
1158     final boolean isEdited() {
1159         return _edited;
1160     }
1161
1162     final boolean isInOvRect() {
1163         return _in_ov_rect;
1164     }
1165
1166     final boolean isOvOn() {
1167         return _ov_on;
1168     }
1169
1170     final boolean isPhyHasBranchLengths() {
1171         return _phy_has_branch_lengths;
1172     }
1173
1174     final void midpointRoot() {
1175         if ( ( _phylogeny == null ) || ( _phylogeny.getNumberOfExternalNodes() < 2 ) ) {
1176             return;
1177         }
1178         if ( !_phylogeny.isRerootable() ) {
1179             JOptionPane.showMessageDialog( this,
1180                                            "This is not rerootable",
1181                                            "Not rerootable",
1182                                            JOptionPane.WARNING_MESSAGE );
1183             return;
1184         }
1185         setNodeInPreorderToNull();
1186         setWaitCursor();
1187         PhylogenyMethods.midpointRoot( _phylogeny );
1188         resetNodeIdToDistToLeafMap();
1189         setArrowCursor();
1190         setEdited( true );
1191         repaint();
1192     }
1193
1194     final void mouseClicked( final MouseEvent e ) {
1195         if ( getOptions().isShowOverview() && isOvOn() && isInOv() ) {
1196             final double w_ratio = getVisibleRect().width / getOvRectangle().getWidth();
1197             final double h_ratio = getVisibleRect().height / getOvRectangle().getHeight();
1198             double x = ( e.getX() - getVisibleRect().x - getOvXPosition() - ( getOvRectangle().getWidth() / 2.0 ) )
1199                     * w_ratio;
1200             double y = ( e.getY() - getVisibleRect().y - getOvYPosition() - ( getOvRectangle().getHeight() / 2.0 ) )
1201                     * h_ratio;
1202             if ( x < 0 ) {
1203                 x = 0;
1204             }
1205             if ( y < 0 ) {
1206                 y = 0;
1207             }
1208             final double max_x = getWidth() - getVisibleRect().width;
1209             final double max_y = getHeight() - getVisibleRect().height;
1210             if ( x > max_x ) {
1211                 x = max_x;
1212             }
1213             if ( y > max_y ) {
1214                 y = max_y;
1215             }
1216             getMainPanel().getCurrentScrollPane().getViewport()
1217                     .setViewPosition( new Point( ForesterUtil.roundToInt( x ), ForesterUtil.roundToInt( y ) ) );
1218             setInOvRect( true );
1219             repaint();
1220         }
1221         else {
1222             final PhylogenyNode node = findNode( e.getX(), e.getY() );
1223             if ( node != null ) {
1224                 if ( !node.isRoot() && node.getParent().isCollapse() ) {
1225                     return;
1226                 }
1227                 _highlight_node = node;
1228                 // Check if shift key is down
1229                 if ( ( e.getModifiers() & InputEvent.SHIFT_MASK ) != 0 ) {
1230                     // Yes, so add to _found_nodes
1231                     if ( getFoundNodes0() == null ) {
1232                         setFoundNodes0( new HashSet<Long>() );
1233                     }
1234                     getFoundNodes0().add( node.getId() );
1235                     // Check if control key is down
1236                 }
1237                 else if ( ( e.getModifiers() & InputEvent.CTRL_MASK ) != 0 ) {
1238                     // Yes, so pop-up menu
1239                     displayNodePopupMenu( node, e.getX(), e.getY() );
1240                     // Handle unadorned click
1241                 }
1242                 else {
1243                     // Check for right mouse button
1244                     if ( e.getModifiers() == 4 ) {
1245                         displayNodePopupMenu( node, e.getX(), e.getY() );
1246                     }
1247                     else {
1248                         // if not in _found_nodes, clear _found_nodes
1249                         handleClickToAction( _control_panel.getActionWhenNodeClicked(), node );
1250                     }
1251                 }
1252             }
1253             else {
1254                 // no node was clicked
1255                 _highlight_node = null;
1256             }
1257         }
1258         repaint();
1259     }
1260
1261     final void mouseDragInBrowserPanel( final MouseEvent e ) {
1262         setCursor( MOVE_CURSOR );
1263         final Point scroll_position = getMainPanel().getCurrentScrollPane().getViewport().getViewPosition();
1264         scroll_position.x -= ( e.getX() - getLastDragPointX() );
1265         scroll_position.y -= ( e.getY() - getLastDragPointY() );
1266         if ( scroll_position.x < 0 ) {
1267             scroll_position.x = 0;
1268         }
1269         else {
1270             final int max_x = getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getMaximum()
1271                     - getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getVisibleAmount();
1272             if ( scroll_position.x > max_x ) {
1273                 scroll_position.x = max_x;
1274             }
1275         }
1276         if ( scroll_position.y < 0 ) {
1277             scroll_position.y = 0;
1278         }
1279         else {
1280             final int max_y = getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getMaximum()
1281                     - getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getVisibleAmount();
1282             if ( scroll_position.y > max_y ) {
1283                 scroll_position.y = max_y;
1284             }
1285         }
1286         if ( isOvOn() || getOptions().isShowScale() ) {
1287             repaint();
1288         }
1289         getMainPanel().getCurrentScrollPane().getViewport().setViewPosition( scroll_position );
1290     }
1291
1292     final void mouseDragInOvRectangle( final MouseEvent e ) {
1293         setCursor( HAND_CURSOR );
1294         final double w_ratio = getVisibleRect().width / getOvRectangle().getWidth();
1295         final double h_ratio = getVisibleRect().height / getOvRectangle().getHeight();
1296         final Point scroll_position = getMainPanel().getCurrentScrollPane().getViewport().getViewPosition();
1297         double dx = ( ( w_ratio * e.getX() ) - ( w_ratio * getLastDragPointX() ) );
1298         double dy = ( ( h_ratio * e.getY() ) - ( h_ratio * getLastDragPointY() ) );
1299         scroll_position.x = ForesterUtil.roundToInt( scroll_position.x + dx );
1300         scroll_position.y = ForesterUtil.roundToInt( scroll_position.y + dy );
1301         if ( scroll_position.x <= 0 ) {
1302             scroll_position.x = 0;
1303             dx = 0;
1304         }
1305         else {
1306             final int max_x = getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getMaximum()
1307                     - getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getVisibleAmount();
1308             if ( scroll_position.x >= max_x ) {
1309                 dx = 0;
1310                 scroll_position.x = max_x;
1311             }
1312         }
1313         if ( scroll_position.y <= 0 ) {
1314             dy = 0;
1315             scroll_position.y = 0;
1316         }
1317         else {
1318             final int max_y = getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getMaximum()
1319                     - getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getVisibleAmount();
1320             if ( scroll_position.y >= max_y ) {
1321                 dy = 0;
1322                 scroll_position.y = max_y;
1323             }
1324         }
1325         repaint();
1326         getMainPanel().getCurrentScrollPane().getViewport().setViewPosition( scroll_position );
1327         setLastMouseDragPointX( ( float ) ( e.getX() + dx ) );
1328         setLastMouseDragPointY( ( float ) ( e.getY() + dy ) );
1329     }
1330
1331     final void mouseMoved( final MouseEvent e ) {
1332         requestFocusInWindow();
1333         if ( _current_external_nodes != null ) {
1334             _current_external_nodes = null;
1335             repaint();
1336         }
1337         if ( getControlPanel().isNodeDescPopup() ) {
1338             if ( _node_desc_popup != null ) {
1339                 _node_desc_popup.hide();
1340                 _node_desc_popup = null;
1341             }
1342         }
1343         if ( getOptions().isShowOverview() && isOvOn() ) {
1344             if ( inOvVirtualRectangle( e ) ) {
1345                 if ( !isInOvRect() ) {
1346                     setInOvRect( true );
1347                     repaint();
1348                 }
1349             }
1350             else {
1351                 if ( isInOvRect() ) {
1352                     setInOvRect( false );
1353                     repaint();
1354                 }
1355             }
1356         }
1357         if ( inOv( e ) && getOptions().isShowOverview() && isOvOn() ) {
1358             if ( !isInOv() ) {
1359                 setInOv( true );
1360             }
1361         }
1362         else {
1363             if ( isInOv() ) {
1364                 setInOv( false );
1365             }
1366             final PhylogenyNode node = findNode( e.getX(), e.getY() );
1367             if ( ( node != null ) && ( node.isRoot() || !node.getParent().isCollapse() ) ) {
1368                 if ( ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.GET_EXT_DESC_DATA ) ) {
1369                     for( final PhylogenyNode n : node.getAllExternalDescendants() ) {
1370                         addToCurrentExternalNodes( n.getId() );
1371                     }
1372                     setCursor( HAND_CURSOR );
1373                     repaint();
1374                 }
1375                 else if ( ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.CUT_SUBTREE )
1376                         || ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.COPY_SUBTREE )
1377                         || ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.PASTE_SUBTREE )
1378                         || ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.DELETE_NODE_OR_SUBTREE )
1379                         || ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.REROOT )
1380                         || ( getControlPanel().getActionWhenNodeClicked() == NodeClickAction.ADD_NEW_NODE ) ) {
1381                     setCursor( CUT_CURSOR );
1382                 }
1383                 else {
1384                     setCursor( HAND_CURSOR );
1385                     if ( getControlPanel().isNodeDescPopup() ) {
1386                         showNodeDataPopup( e, node );
1387                     }
1388                 }
1389             }
1390             else {
1391                 setCursor( ARROW_CURSOR );
1392             }
1393         }
1394     }
1395
1396     final void mouseReleasedInBrowserPanel( final MouseEvent e ) {
1397         setCursor( ARROW_CURSOR );
1398     }
1399
1400     final void multiplyUrtFactor( final float f ) {
1401         _urt_factor *= f;
1402     }
1403
1404     final JApplet obtainApplet() {
1405         return ( ( MainPanelApplets ) getMainPanel() ).getApplet();
1406     }
1407
1408     final void paintBranchCircular( final PhylogenyNode p,
1409                                     final PhylogenyNode c,
1410                                     final Graphics2D g,
1411                                     final boolean radial_labels,
1412                                     final boolean to_pdf,
1413                                     final boolean to_graphics_file ) {
1414         final double angle = _urt_nodeid_angle_map.get( c.getId() );
1415         final double root_x = _root.getXcoord();
1416         final double root_y = _root.getYcoord();
1417         final double dx = root_x - p.getXcoord();
1418         final double dy = root_y - p.getYcoord();
1419         final double parent_radius = Math.sqrt( ( dx * dx ) + ( dy * dy ) );
1420         final double arc = ( _urt_nodeid_angle_map.get( p.getId() ) ) - angle;
1421         assignGraphicsForBranchWithColorForParentBranch( c, false, g, to_pdf, to_graphics_file );
1422         if ( ( c.isFirstChildNode() || c.isLastChildNode() )
1423                 && ( ( Math.abs( parent_radius * arc ) > 1.5 ) || to_pdf || to_graphics_file ) ) {
1424             final double r2 = 2.0 * parent_radius;
1425             drawArc( root_x - parent_radius, root_y - parent_radius, r2, r2, ( -angle - arc ), arc, g );
1426         }
1427         drawLine( c.getXcoord(),
1428                   c.getYcoord(),
1429                   root_x + ( Math.cos( angle ) * parent_radius ),
1430                   root_y + ( Math.sin( angle ) * parent_radius ),
1431                   g );
1432         paintNodeBox( c.getXcoord(), c.getYcoord(), c, g, to_pdf, to_graphics_file );
1433         if ( c.isExternal() ) {
1434             final boolean is_in_found_nodes = isInFoundNodes0( c ) || isInFoundNodes1( c )
1435                     || isInCurrentExternalNodes( c );
1436             if ( ( _dynamic_hiding_factor > 1 ) && !is_in_found_nodes
1437                     && ( ( _urt_nodeid_index_map.get( c.getId() ) % _dynamic_hiding_factor ) != 1 ) ) {
1438                 return;
1439             }
1440             paintNodeDataUnrootedCirc( g, c, to_pdf, to_graphics_file, radial_labels, 0, is_in_found_nodes );
1441         }
1442     }
1443
1444     final void paintBranchCircularLite( final PhylogenyNode p, final PhylogenyNode c, final Graphics2D g ) {
1445         final double angle = _urt_nodeid_angle_map.get( c.getId() );
1446         final double root_x = _root.getXSecondary();
1447         final double root_y = _root.getYSecondary();
1448         final double dx = root_x - p.getXSecondary();
1449         final double dy = root_y - p.getYSecondary();
1450         final double arc = ( _urt_nodeid_angle_map.get( p.getId() ) ) - angle;
1451         final double parent_radius = Math.sqrt( ( dx * dx ) + ( dy * dy ) );
1452         g.setColor( getTreeColorSet().getOvColor() );
1453         if ( ( c.isFirstChildNode() || c.isLastChildNode() ) && ( Math.abs( arc ) > 0.02 ) ) {
1454             final double r2 = 2.0 * parent_radius;
1455             drawArc( root_x - parent_radius, root_y - parent_radius, r2, r2, ( -angle - arc ), arc, g );
1456         }
1457         drawLine( c.getXSecondary(),
1458                   c.getYSecondary(),
1459                   root_x + ( Math.cos( angle ) * parent_radius ),
1460                   root_y + ( Math.sin( angle ) * parent_radius ),
1461                   g );
1462         if ( ( isInFoundNodes0( c ) && !isInFoundNodes1( c ) ) || isInCurrentExternalNodes( c ) ) {
1463             g.setColor( getTreeColorSet().getFoundColor0() );
1464             drawRectFilled( c.getXSecondary() - 1, c.getYSecondary() - 1, 3, 3, g );
1465         }
1466         else if ( ( isInFoundNodes1( c ) && !isInFoundNodes0( c ) ) ) {
1467             g.setColor( getTreeColorSet().getFoundColor1() );
1468             drawRectFilled( c.getXSecondary() - 1, c.getYSecondary() - 1, 3, 3, g );
1469         }
1470         else if ( isInFoundNodes0( c ) && isInFoundNodes1( c ) ) {
1471             g.setColor( getTreeColorSet().getFoundColor0and1() );
1472             drawRectFilled( c.getXSecondary() - 1, c.getYSecondary() - 1, 3, 3, g );
1473         }
1474     }
1475
1476     final void paintCircular( final Phylogeny phy,
1477                               final double starting_angle,
1478                               final int center_x,
1479                               final int center_y,
1480                               final int radius,
1481                               final Graphics2D g,
1482                               final boolean to_pdf,
1483                               final boolean to_graphics_file ) {
1484         final int circ_num_ext_nodes = phy.getNumberOfExternalNodes() - _collapsed_external_nodeid_set.size();
1485         System.out.println( "# collapsed external = " + _collapsed_external_nodeid_set.size() );
1486         _root = phy.getRoot();
1487         _root.setXcoord( center_x );
1488         _root.setYcoord( center_y );
1489         final boolean radial_labels = getOptions().getNodeLabelDirection() == NODE_LABEL_DIRECTION.RADIAL;
1490         double current_angle = starting_angle;
1491         int i = 0;
1492         for( final PhylogenyNodeIterator it = phy.iteratorExternalForward(); it.hasNext(); ) {
1493             final PhylogenyNode n = it.next();
1494             if ( !n.isCollapse() ) {
1495                 n.setXcoord( ( float ) ( center_x + ( radius * Math.cos( current_angle ) ) ) );
1496                 n.setYcoord( ( float ) ( center_y + ( radius * Math.sin( current_angle ) ) ) );
1497                 _urt_nodeid_angle_map.put( n.getId(), current_angle );
1498                 _urt_nodeid_index_map.put( n.getId(), i++ );
1499                 current_angle += ( TWO_PI / circ_num_ext_nodes );
1500             }
1501             else {
1502                 //TODO remove me
1503                 System.out.println( "is collapse" + n.getName() );
1504             }
1505         }
1506         paintCirculars( phy.getRoot(), phy, center_x, center_y, radius, radial_labels, g, to_pdf, to_graphics_file );
1507         paintNodeBox( _root.getXcoord(), _root.getYcoord(), _root, g, to_pdf, to_graphics_file );
1508     }
1509
1510     final void paintCircularLite( final Phylogeny phy,
1511                                   final double starting_angle,
1512                                   final int center_x,
1513                                   final int center_y,
1514                                   final int radius,
1515                                   final Graphics2D g ) {
1516         final int circ_num_ext_nodes = phy.getNumberOfExternalNodes();
1517         _root = phy.getRoot();
1518         _root.setXSecondary( center_x );
1519         _root.setYSecondary( center_y );
1520         double current_angle = starting_angle;
1521         for( final PhylogenyNodeIterator it = phy.iteratorExternalForward(); it.hasNext(); ) {
1522             final PhylogenyNode n = it.next();
1523             n.setXSecondary( ( float ) ( center_x + ( radius * Math.cos( current_angle ) ) ) );
1524             n.setYSecondary( ( float ) ( center_y + ( radius * Math.sin( current_angle ) ) ) );
1525             _urt_nodeid_angle_map.put( n.getId(), current_angle );
1526             current_angle += ( TWO_PI / circ_num_ext_nodes );
1527         }
1528         paintCircularsLite( phy.getRoot(), phy, center_x, center_y, radius, g );
1529     }
1530
1531     final void paintPhylogeny( final Graphics2D g,
1532                                final boolean to_pdf,
1533                                final boolean to_graphics_file,
1534                                final int graphics_file_width,
1535                                final int graphics_file_height,
1536                                final int graphics_file_x,
1537                                final int graphics_file_y ) {
1538         if ( ( _phylogeny == null ) || _phylogeny.isEmpty() ) {
1539             return;
1540         }
1541         if ( _control_panel.isShowSequenceRelations() ) {
1542             _query_sequence = _control_panel.getSelectedQuerySequence();
1543         }
1544         // Color the background
1545         if ( !to_pdf ) {
1546             final Rectangle r = getVisibleRect();
1547             if ( !getOptions().isBackgroundColorGradient() || getOptions().isPrintBlackAndWhite() ) {
1548                 g.setColor( getTreeColorSet().getBackgroundColor() );
1549                 if ( !to_graphics_file ) {
1550                     g.fill( r );
1551                 }
1552                 else {
1553                     if ( getOptions().isPrintBlackAndWhite() ) {
1554                         g.setColor( Color.WHITE );
1555                     }
1556                     g.fillRect( graphics_file_x, graphics_file_y, graphics_file_width, graphics_file_height );
1557                 }
1558             }
1559             else {
1560                 if ( !to_graphics_file ) {
1561                     g.setPaint( new GradientPaint( r.x, r.y, getTreeColorSet().getBackgroundColor(), r.x, r.y
1562                             + r.height, getTreeColorSet().getBackgroundColorGradientBottom() ) );
1563                     g.fill( r );
1564                 }
1565                 else {
1566                     g.setPaint( new GradientPaint( graphics_file_x,
1567                                                    graphics_file_y,
1568                                                    getTreeColorSet().getBackgroundColor(),
1569                                                    graphics_file_x,
1570                                                    graphics_file_y + graphics_file_height,
1571                                                    getTreeColorSet().getBackgroundColorGradientBottom() ) );
1572                     g.fillRect( graphics_file_x, graphics_file_y, graphics_file_width, graphics_file_height );
1573                 }
1574             }
1575             setupStroke( g );
1576         }
1577         else {
1578             g.setStroke( new BasicStroke( getOptions().getPrintLineWidth() ) );
1579         }
1580         if ( ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
1581                 && ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
1582             _external_node_index = 0;
1583             // Position starting X of tree
1584             if ( !_phylogeny.isRooted() /*|| ( _subtree_index > 0 )*/) {
1585                 _phylogeny.getRoot().setXcoord( TreePanel.MOVE );
1586             }
1587             else if ( ( _phylogeny.getRoot().getDistanceToParent() > 0.0 ) && getControlPanel().isDrawPhylogram() ) {
1588                 _phylogeny.getRoot().setXcoord( ( float ) ( TreePanel.MOVE + ( _phylogeny.getRoot()
1589                         .getDistanceToParent() * getXcorrectionFactor() ) ) );
1590             }
1591             else {
1592                 _phylogeny.getRoot().setXcoord( TreePanel.MOVE + getXdistance() );
1593             }
1594             // Position starting Y of tree
1595             _phylogeny.getRoot().setYcoord( ( getYdistance() * _phylogeny.getRoot().getNumberOfExternalNodes() )
1596                     + ( TreePanel.MOVE / 2.0f ) );
1597             final int dynamic_hiding_factor = calcDynamicHidingFactor();
1598             if ( getControlPanel().isDynamicallyHideData() ) {
1599                 if ( dynamic_hiding_factor > 1 ) {
1600                     getControlPanel().setDynamicHidingIsOn( true );
1601                 }
1602                 else {
1603                     getControlPanel().setDynamicHidingIsOn( false );
1604                 }
1605             }
1606             if ( _nodes_in_preorder == null ) {
1607                 _nodes_in_preorder = new PhylogenyNode[ _phylogeny.getNodeCount() ];
1608                 int i = 0;
1609                 for( final PhylogenyNodeIterator it = _phylogeny.iteratorPreorder(); it.hasNext(); ) {
1610                     _nodes_in_preorder[ i++ ] = it.next();
1611                 }
1612             }
1613             //final PhylogenyNodeIterator it;
1614             //for( it = _phylogeny.iteratorPreorder(); it.hasNext(); ) {
1615             //    paintNodeRectangular( g, it.next(), to_pdf, getControlPanel().isDynamicallyHideData()
1616             //            && ( dynamic_hiding_factor > 1 ), dynamic_hiding_factor, to_graphics_file );
1617             //}
1618             for( final PhylogenyNode element : _nodes_in_preorder ) {
1619                 paintNodeRectangular( g, element, to_pdf, getControlPanel().isDynamicallyHideData()
1620                         && ( dynamic_hiding_factor > 1 ), dynamic_hiding_factor, to_graphics_file );
1621             }
1622             if ( getOptions().isShowScale() && getControlPanel().isDrawPhylogram() && ( getScaleDistance() > 0.0 ) ) {
1623                 if ( !( to_graphics_file || to_pdf ) ) {
1624                     paintScale( g,
1625                                 getVisibleRect().x,
1626                                 getVisibleRect().y + getVisibleRect().height,
1627                                 to_pdf,
1628                                 to_graphics_file );
1629                 }
1630                 else {
1631                     paintScale( g, graphics_file_x, graphics_file_y + graphics_file_height, to_pdf, to_graphics_file );
1632                 }
1633             }
1634             if ( getOptions().isShowOverview() && isOvOn() && !to_graphics_file && !to_pdf ) {
1635                 paintPhylogenyLite( g );
1636             }
1637         }
1638         else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
1639             if ( getControlPanel().getDynamicallyHideData() != null ) {
1640                 getControlPanel().setDynamicHidingIsOn( false );
1641             }
1642             final double angle = getStartingAngle();
1643             final boolean radial_labels = getOptions().getNodeLabelDirection() == NODE_LABEL_DIRECTION.RADIAL;
1644             _dynamic_hiding_factor = 0;
1645             if ( getControlPanel().isDynamicallyHideData() ) {
1646                 _dynamic_hiding_factor = ( int ) ( ( getTreeFontSet()._fm_large.getHeight() * 1.5 * getPhylogeny()
1647                         .getNumberOfExternalNodes() ) / ( TWO_PI * 10 ) );
1648             }
1649             if ( getControlPanel().getDynamicallyHideData() != null ) {
1650                 if ( _dynamic_hiding_factor > 1 ) {
1651                     getControlPanel().setDynamicHidingIsOn( true );
1652                 }
1653                 else {
1654                     getControlPanel().setDynamicHidingIsOn( false );
1655                 }
1656             }
1657             paintUnrooted( _phylogeny.getRoot(),
1658                            angle,
1659                            ( float ) ( angle + ( 2 * Math.PI ) ),
1660                            radial_labels,
1661                            g,
1662                            to_pdf,
1663                            to_graphics_file );
1664             if ( getOptions().isShowScale() ) {
1665                 if ( !( to_graphics_file || to_pdf ) ) {
1666                     paintScale( g,
1667                                 getVisibleRect().x,
1668                                 getVisibleRect().y + getVisibleRect().height,
1669                                 to_pdf,
1670                                 to_graphics_file );
1671                 }
1672                 else {
1673                     paintScale( g, graphics_file_x, graphics_file_y + graphics_file_height, to_pdf, to_graphics_file );
1674                 }
1675             }
1676             if ( getOptions().isShowOverview() && isOvOn() && !to_graphics_file && !to_pdf ) {
1677                 g.setColor( getTreeColorSet().getOvColor() );
1678                 paintUnrootedLite( _phylogeny.getRoot(),
1679                                    angle,
1680                                    angle + ( 2 * Math.PI ),
1681                                    g,
1682                                    ( getUrtFactorOv() / ( getVisibleRect().width / getOvMaxWidth() ) ) );
1683                 paintOvRectangle( g );
1684             }
1685         }
1686         else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) {
1687             final int radius = ( int ) ( ( Math.min( getPreferredSize().getWidth(), getPreferredSize().getHeight() ) / 2 ) - ( MOVE + getLongestExtNodeInfo() ) );
1688             final int d = radius + MOVE + getLongestExtNodeInfo();
1689             _dynamic_hiding_factor = 0;
1690             if ( getControlPanel().isDynamicallyHideData() && ( radius > 0 ) ) {
1691                 _dynamic_hiding_factor = ( int ) ( ( getTreeFontSet()._fm_large.getHeight() * 1.5 * getPhylogeny()
1692                         .getNumberOfExternalNodes() ) / ( TWO_PI * radius ) );
1693             }
1694             if ( getControlPanel().getDynamicallyHideData() != null ) {
1695                 if ( _dynamic_hiding_factor > 1 ) {
1696                     getControlPanel().setDynamicHidingIsOn( true );
1697                 }
1698                 else {
1699                     getControlPanel().setDynamicHidingIsOn( false );
1700                 }
1701             }
1702             paintCircular( _phylogeny, getStartingAngle(), d, d, radius > 0 ? radius : 0, g, to_pdf, to_graphics_file );
1703             if ( getOptions().isShowOverview() && isOvOn() && !to_graphics_file && !to_pdf ) {
1704                 final int radius_ov = ( int ) ( getOvMaxHeight() < getOvMaxWidth() ? getOvMaxHeight() / 2
1705                         : getOvMaxWidth() / 2 );
1706                 double x_scale = 1.0;
1707                 double y_scale = 1.0;
1708                 int x_pos = getVisibleRect().x + getOvXPosition();
1709                 int y_pos = getVisibleRect().y + getOvYPosition();
1710                 if ( getWidth() > getHeight() ) {
1711                     x_scale = ( double ) getHeight() / getWidth();
1712                     x_pos = ForesterUtil.roundToInt( x_pos / x_scale );
1713                 }
1714                 else {
1715                     y_scale = ( double ) getWidth() / getHeight();
1716                     y_pos = ForesterUtil.roundToInt( y_pos / y_scale );
1717                 }
1718                 _at = g.getTransform();
1719                 g.scale( x_scale, y_scale );
1720                 paintCircularLite( _phylogeny,
1721                                    getStartingAngle(),
1722                                    x_pos + radius_ov,
1723                                    y_pos + radius_ov,
1724                                    ( int ) ( radius_ov - ( getLongestExtNodeInfo() / ( getVisibleRect().width / getOvRectangle()
1725                                            .getWidth() ) ) ),
1726                                    g );
1727                 g.setTransform( _at );
1728                 paintOvRectangle( g );
1729             }
1730         }
1731     }
1732
1733     final void recalculateMaxDistanceToRoot() {
1734         _max_distance_to_root = PhylogenyMethods.calculateMaxDistanceToRoot( getPhylogeny() );
1735     }
1736
1737     /**
1738      * Remove all edit-node frames
1739      */
1740     final void removeAllEditNodeJFrames() {
1741         for( int i = 0; i <= ( TreePanel.MAX_NODE_FRAMES - 1 ); i++ ) {
1742             if ( _node_frames[ i ] != null ) {
1743                 _node_frames[ i ].dispose();
1744                 _node_frames[ i ] = null;
1745             }
1746         }
1747         _node_frame_index = 0;
1748     }
1749
1750     /**
1751      * Remove a node-edit frame.
1752      */
1753     final void removeEditNodeFrame( final int i ) {
1754         _node_frame_index--;
1755         _node_frames[ i ] = null;
1756         if ( i < _node_frame_index ) {
1757             for( int j = 0; j < ( _node_frame_index - 1 ); j++ ) {
1758                 _node_frames[ j ] = _node_frames[ j + 1 ];
1759             }
1760             _node_frames[ _node_frame_index ] = null;
1761         }
1762     }
1763
1764     final void reRoot( final PhylogenyNode node ) {
1765         if ( !getPhylogeny().isRerootable() ) {
1766             JOptionPane.showMessageDialog( this,
1767                                            "This is not rerootable",
1768                                            "Not rerootable",
1769                                            JOptionPane.WARNING_MESSAGE );
1770             return;
1771         }
1772         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
1773             JOptionPane.showMessageDialog( this,
1774                                            "Cannot reroot in unrooted display type",
1775                                            "Attempt to reroot tree in unrooted display",
1776                                            JOptionPane.WARNING_MESSAGE );
1777             return;
1778         }
1779         getPhylogeny().reRoot( node );
1780         getPhylogeny().recalculateNumberOfExternalDescendants( true );
1781         resetNodeIdToDistToLeafMap();
1782         setNodeInPreorderToNull();
1783         resetPreferredSize();
1784         getMainPanel().adjustJScrollPane();
1785         setEdited( true );
1786         repaint();
1787         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) {
1788             getControlPanel().showWhole();
1789         }
1790     }
1791
1792     final void resetNodeIdToDistToLeafMap() {
1793         _nodeid_dist_to_leaf = new HashMap<Long, Short>();
1794     }
1795
1796     final void resetPreferredSize() {
1797         if ( ( getPhylogeny() == null ) || getPhylogeny().isEmpty() ) {
1798             return;
1799         }
1800         int x = 0;
1801         int y = 0;
1802         y = TreePanel.MOVE
1803                 + ForesterUtil.roundToInt( getYdistance() * getPhylogeny().getRoot().getNumberOfExternalNodes() * 2 );
1804         if ( getControlPanel().isDrawPhylogram() ) {
1805             x = TreePanel.MOVE
1806                     + getLongestExtNodeInfo()
1807                     + ForesterUtil
1808                             .roundToInt( ( getXcorrectionFactor() * getPhylogeny().getHeight() ) + getXdistance() );
1809         }
1810         else {
1811             if ( !isNonLinedUpCladogram() && !isUniformBranchLengthsForCladogram() ) {
1812                 x = TreePanel.MOVE
1813                         + getLongestExtNodeInfo()
1814                         + ForesterUtil.roundToInt( getXdistance()
1815                                 * ( getPhylogeny().getRoot().getNumberOfExternalNodes() + 2 ) );
1816             }
1817             else {
1818                 x = TreePanel.MOVE
1819                         + getLongestExtNodeInfo()
1820                         + ForesterUtil.roundToInt( getXdistance()
1821                                 * ( PhylogenyMethods.calculateMaxDepth( getPhylogeny() ) + 1 ) );
1822             }
1823         }
1824         setPreferredSize( new Dimension( x, y ) );
1825     }
1826
1827     final void selectNode( final PhylogenyNode node ) {
1828         if ( ( getFoundNodes0() != null ) && getFoundNodes0().contains( node.getId() ) ) {
1829             getFoundNodes0().remove( node.getId() );
1830             getControlPanel().setSearchFoundCountsOnLabel0( getFoundNodes0().size() );
1831             if ( getFoundNodes0().size() < 1 ) {
1832                 getControlPanel().searchReset0();
1833             }
1834         }
1835         else {
1836             getControlPanel().getSearchFoundCountsLabel0().setVisible( true );
1837             getControlPanel().getSearchResetButton0().setEnabled( true );
1838             getControlPanel().getSearchResetButton0().setVisible( true );
1839             if ( getFoundNodes0() == null ) {
1840                 setFoundNodes0( new HashSet<Long>() );
1841             }
1842             getFoundNodes0().add( node.getId() );
1843             getControlPanel().setSearchFoundCountsOnLabel0( getFoundNodes0().size() );
1844         }
1845     }
1846
1847     final void setArrowCursor() {
1848         setCursor( ARROW_CURSOR );
1849         repaint();
1850     }
1851
1852     final void setControlPanel( final ControlPanel atv_control ) {
1853         _control_panel = atv_control;
1854     }
1855
1856     void setCurrentExternalNodesDataBuffer( final StringBuilder sb ) {
1857         increaseCurrentExternalNodesDataBufferChangeCounter();
1858         _current_external_nodes_data_buffer = sb;
1859     }
1860
1861     final void setFoundNodes0( final Set<Long> found_nodes ) {
1862         _found_nodes_0 = found_nodes;
1863     }
1864
1865     final void setFoundNodes1( final Set<Long> found_nodes ) {
1866         _found_nodes_1 = found_nodes;
1867     }
1868
1869     final void setInOvRect( final boolean in_ov_rect ) {
1870         _in_ov_rect = in_ov_rect;
1871     }
1872
1873     final void setLargeFonts() {
1874         getTreeFontSet().largeFonts();
1875     }
1876
1877     final void setLastMouseDragPointX( final float x ) {
1878         _last_drag_point_x = x;
1879     }
1880
1881     final void setLastMouseDragPointY( final float y ) {
1882         _last_drag_point_y = y;
1883     }
1884
1885     final void setLongestExtNodeInfo( final int i ) {
1886         _longest_ext_node_info = i;
1887     }
1888
1889     final void setMediumFonts() {
1890         getTreeFontSet().mediumFonts();
1891     }
1892
1893     final void setNodeInPreorderToNull() {
1894         _nodes_in_preorder = null;
1895     }
1896
1897     final void setOvOn( final boolean ov_on ) {
1898         _ov_on = ov_on;
1899     }
1900
1901     final void setPhylogenyGraphicsType( final PHYLOGENY_GRAPHICS_TYPE graphics_type ) {
1902         _graphics_type = graphics_type;
1903         setTextAntialias();
1904     }
1905
1906     final void setSmallFonts() {
1907         getTreeFontSet().smallFonts();
1908     }
1909
1910     final void setStartingAngle( final double starting_angle ) {
1911         _urt_starting_angle = starting_angle;
1912     }
1913
1914     void setStatisticsForExpressionValues( final DescriptiveStatistics statistics_for_expression_values ) {
1915         _statistics_for_vector_data = statistics_for_expression_values;
1916     }
1917
1918     final void setSuperTinyFonts() {
1919         getTreeFontSet().superTinyFonts();
1920     }
1921
1922     final void setTextAntialias() {
1923         if ( ( _phylogeny != null ) && !_phylogeny.isEmpty() ) {
1924             if ( _phylogeny.getNumberOfExternalNodes() <= LIMIT_FOR_HQ_RENDERING ) {
1925                 _rendering_hints.put( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY );
1926             }
1927             else {
1928                 _rendering_hints.put( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED );
1929             }
1930         }
1931         if ( getMainPanel().getOptions().isAntialiasScreen() ) {
1932             _rendering_hints.put( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
1933             // try {
1934             _rendering_hints.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB );
1935             // }
1936             // catch ( final Throwable e ) {
1937             //    _rendering_hints.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
1938             //}
1939         }
1940         else {
1941             _rendering_hints.put( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF );
1942             _rendering_hints.put( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF );
1943         }
1944     }
1945
1946     final void setTinyFonts() {
1947         getTreeFontSet().tinyFonts();
1948     }
1949
1950     final void setTreeFile( final File treefile ) {
1951         _treefile = treefile;
1952     }
1953
1954     final void setXcorrectionFactor( final float f ) {
1955         _x_correction_factor = f;
1956     }
1957
1958     final void setXdistance( final float x ) {
1959         _x_distance = x;
1960     }
1961
1962     final void setYdistance( final float y ) {
1963         _y_distance = y;
1964     }
1965
1966     final void sortDescendants( final PhylogenyNode node ) {
1967         if ( !node.isExternal() ) {
1968             DESCENDANT_SORT_PRIORITY pri = DESCENDANT_SORT_PRIORITY.TAXONOMY;
1969             if ( ( !getControlPanel().isShowTaxonomyScientificNames() && !getControlPanel().isShowTaxonomyCode() && !getControlPanel()
1970                     .isShowTaxonomyCommonNames() ) ) {
1971                 if ( ( getControlPanel().isShowSequenceAcc() || getControlPanel().isShowSeqNames() || getControlPanel()
1972                         .isShowSeqSymbols() ) ) {
1973                     pri = DESCENDANT_SORT_PRIORITY.SEQUENCE;
1974                 }
1975                 else if ( getControlPanel().isShowNodeNames() ) {
1976                     pri = DESCENDANT_SORT_PRIORITY.NODE_NAME;
1977                 }
1978             }
1979             PhylogenyMethods.sortNodeDescendents( node, pri );
1980             setNodeInPreorderToNull();
1981             _phylogeny.externalNodesHaveChanged();
1982             _phylogeny.clearHashIdToNodeMap();
1983             _phylogeny.recalculateNumberOfExternalDescendants( true );
1984             resetNodeIdToDistToLeafMap();
1985             setEdited( true );
1986         }
1987         repaint();
1988     }
1989
1990     final void subTree( final PhylogenyNode node ) {
1991         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
1992             JOptionPane.showMessageDialog( this,
1993                                            "Cannot get a sub/super tree in unrooted display",
1994                                            "Attempt to get sub/super tree in unrooted display",
1995                                            JOptionPane.WARNING_MESSAGE );
1996             return;
1997         }
1998         if ( node.isExternal() ) {
1999             JOptionPane.showMessageDialog( this,
2000                                            "Cannot get a subtree of a external node",
2001                                            "Attempt to get subtree of external node",
2002                                            JOptionPane.WARNING_MESSAGE );
2003             return;
2004         }
2005         if ( node.isRoot() && !isCurrentTreeIsSubtree() ) {
2006             JOptionPane.showMessageDialog( this,
2007                                            "Cannot get a subtree of the root node",
2008                                            "Attempt to get subtree of root node",
2009                                            JOptionPane.WARNING_MESSAGE );
2010             return;
2011         }
2012         setNodeInPreorderToNull();
2013         if ( !node.isExternal() && !node.isRoot() && ( _subtree_index <= ( TreePanel.MAX_SUBTREES - 1 ) ) ) {
2014             _sub_phylogenies[ _subtree_index ] = _phylogeny;
2015             _sub_phylogenies_temp_roots[ _subtree_index ] = node;
2016             ++_subtree_index;
2017             _phylogeny = TreePanelUtil.subTree( node, _phylogeny );
2018             updateSubSuperTreeButton();
2019         }
2020         else if ( node.isRoot() && isCurrentTreeIsSubtree() ) {
2021             superTree();
2022         }
2023         _main_panel.getControlPanel().showWhole();
2024         repaint();
2025     }
2026
2027     final void superTree() {
2028         setNodeInPreorderToNull();
2029         final PhylogenyNode temp_root = _sub_phylogenies_temp_roots[ _subtree_index - 1 ];
2030         for( final PhylogenyNode n : temp_root.getDescendants() ) {
2031             n.setParent( temp_root );
2032         }
2033         _sub_phylogenies[ _subtree_index ] = null;
2034         _sub_phylogenies_temp_roots[ _subtree_index ] = null;
2035         _phylogeny = _sub_phylogenies[ --_subtree_index ];
2036         updateSubSuperTreeButton();
2037     }
2038
2039     final void swap( final PhylogenyNode node ) {
2040         if ( node.isExternal() || ( node.getNumberOfDescendants() < 2 ) ) {
2041             return;
2042         }
2043         if ( node.getNumberOfDescendants() > 2 ) {
2044             JOptionPane.showMessageDialog( this,
2045                                            "Cannot swap descendants of nodes with more than 2 descendants",
2046                                            "Cannot swap descendants",
2047                                            JOptionPane.ERROR_MESSAGE );
2048             return;
2049         }
2050         if ( !node.isExternal() ) {
2051             node.swapChildren();
2052             setNodeInPreorderToNull();
2053             _phylogeny.externalNodesHaveChanged();
2054             _phylogeny.clearHashIdToNodeMap();
2055             _phylogeny.recalculateNumberOfExternalDescendants( true );
2056             resetNodeIdToDistToLeafMap();
2057             setEdited( true );
2058         }
2059         repaint();
2060     }
2061
2062     final void taxColor() {
2063         if ( ( _phylogeny == null ) || ( _phylogeny.getNumberOfExternalNodes() < 2 ) ) {
2064             return;
2065         }
2066         setWaitCursor();
2067         TreePanelUtil.colorPhylogenyAccordingToExternalTaxonomy( _phylogeny, this );
2068         _control_panel.setColorBranches( true );
2069         if ( _control_panel.getColorBranchesCb() != null ) {
2070             _control_panel.getColorBranchesCb().setSelected( true );
2071         }
2072         setEdited( true );
2073         setArrowCursor();
2074         repaint();
2075     }
2076
2077     final void updateOvSettings() {
2078         switch ( getOptions().getOvPlacement() ) {
2079             case LOWER_LEFT:
2080                 setOvXPosition( OV_BORDER );
2081                 setOvYPosition( ForesterUtil.roundToInt( getVisibleRect().height - OV_BORDER - getOvMaxHeight() ) );
2082                 setOvYStart( ForesterUtil.roundToInt( getOvYPosition() + ( getOvMaxHeight() / 2 ) ) );
2083                 break;
2084             case LOWER_RIGHT:
2085                 setOvXPosition( ForesterUtil.roundToInt( getVisibleRect().width - OV_BORDER - getOvMaxWidth() ) );
2086                 setOvYPosition( ForesterUtil.roundToInt( getVisibleRect().height - OV_BORDER - getOvMaxHeight() ) );
2087                 setOvYStart( ForesterUtil.roundToInt( getOvYPosition() + ( getOvMaxHeight() / 2 ) ) );
2088                 break;
2089             case UPPER_RIGHT:
2090                 setOvXPosition( ForesterUtil.roundToInt( getVisibleRect().width - OV_BORDER - getOvMaxWidth() ) );
2091                 setOvYPosition( OV_BORDER );
2092                 setOvYStart( ForesterUtil.roundToInt( OV_BORDER + ( getOvMaxHeight() / 2 ) ) );
2093                 break;
2094             default:
2095                 setOvXPosition( OV_BORDER );
2096                 setOvYPosition( OV_BORDER );
2097                 setOvYStart( ForesterUtil.roundToInt( OV_BORDER + ( getOvMaxHeight() / 2 ) ) );
2098                 break;
2099         }
2100     }
2101
2102     final void updateOvSizes() {
2103         if ( ( getWidth() > ( 1.05 * getVisibleRect().width ) ) || ( getHeight() > ( 1.05 * getVisibleRect().height ) ) ) {
2104             setOvOn( true );
2105             float l = getLongestExtNodeInfo();
2106             final float w_ratio = getOvMaxWidth() / getWidth();
2107             l *= w_ratio;
2108             final int ext_nodes = _phylogeny.getRoot().getNumberOfExternalNodes();
2109             setOvYDistance( getOvMaxHeight() / ( 2 * ext_nodes ) );
2110             float ov_xdist = 0;
2111             if ( !isNonLinedUpCladogram() && !isUniformBranchLengthsForCladogram() ) {
2112                 ov_xdist = ( ( getOvMaxWidth() - l ) / ( ext_nodes ) );
2113             }
2114             else {
2115                 ov_xdist = ( ( getOvMaxWidth() - l ) / ( PhylogenyMethods.calculateMaxDepth( _phylogeny ) ) );
2116             }
2117             float ydist = ( float ) ( ( getOvMaxWidth() / ( ext_nodes * 2.0 ) ) );
2118             if ( ov_xdist < 0.0 ) {
2119                 ov_xdist = 0.0f;
2120             }
2121             if ( ydist < 0.0 ) {
2122                 ydist = 0.0f;
2123             }
2124             setOvXDistance( ov_xdist );
2125             final double height = _phylogeny.getHeight();
2126             if ( height > 0 ) {
2127                 final float ov_corr = ( float ) ( ( ( getOvMaxWidth() - l ) - getOvXDistance() ) / height );
2128                 setOvXcorrectionFactor( ov_corr > 0 ? ov_corr : 0 );
2129             }
2130             else {
2131                 setOvXcorrectionFactor( 0 );
2132             }
2133         }
2134         else {
2135             setOvOn( false );
2136         }
2137     }
2138
2139     void updateSetOfCollapsedExternalNodes() {
2140         final Phylogeny phy = getPhylogeny();
2141         _collapsed_external_nodeid_set.clear();
2142         if ( phy != null ) {
2143             E: for( final PhylogenyNodeIterator it = phy.iteratorExternalForward(); it.hasNext(); ) {
2144                 final PhylogenyNode ext_node = it.next();
2145                 PhylogenyNode n = ext_node;
2146                 while ( !n.isRoot() ) {
2147                     if ( n.isCollapse() ) {
2148                         _collapsed_external_nodeid_set.add( ext_node.getId() );
2149                         ext_node.setCollapse( true );
2150                         continue E;
2151                     }
2152                     n = n.getParent();
2153                 }
2154             }
2155         }
2156     }
2157
2158     final void updateSubSuperTreeButton() {
2159         if ( _subtree_index < 1 ) {
2160             getControlPanel().deactivateButtonToReturnToSuperTree();
2161         }
2162         else {
2163             getControlPanel().activateButtonToReturnToSuperTree( _subtree_index );
2164         }
2165     }
2166
2167     final void zoomInDomainStructure() {
2168         if ( _domain_structure_width < 2000 ) {
2169             _domain_structure_width *= 1.2;
2170         }
2171     }
2172
2173     final void zoomOutDomainStructure() {
2174         if ( _domain_structure_width > 20 ) {
2175             _domain_structure_width *= 0.8;
2176         }
2177     }
2178
2179     private void abbreviateScientificName( final String sn ) {
2180         final String[] a = sn.split( "\\s+" );
2181         _sb.append( a[ 0 ].substring( 0, 1 ) );
2182         _sb.append( a[ 1 ].substring( 0, 2 ) );
2183         if ( a.length > 2 ) {
2184             for( int i = 2; i < a.length; i++ ) {
2185                 _sb.append( " " );
2186                 _sb.append( a[ i ] );
2187             }
2188         }
2189     }
2190
2191     final private void addEmptyNode( final PhylogenyNode node ) {
2192         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
2193             errorMessageNoCutCopyPasteInUnrootedDisplay();
2194             return;
2195         }
2196         final String label = createASimpleTextRepresentationOfANode( node );
2197         String msg = "";
2198         if ( ForesterUtil.isEmpty( label ) ) {
2199             msg = "How to add the new, empty node?";
2200         }
2201         else {
2202             msg = "How to add the new, empty node to node" + label + "?";
2203         }
2204         final Object[] options = { "As sibling", "As descendant", "Cancel" };
2205         final int r = JOptionPane.showOptionDialog( this,
2206                                                     msg,
2207                                                     "Addition of Empty New Node",
2208                                                     JOptionPane.CLOSED_OPTION,
2209                                                     JOptionPane.QUESTION_MESSAGE,
2210                                                     null,
2211                                                     options,
2212                                                     options[ 2 ] );
2213         boolean add_as_sibling = true;
2214         if ( r == 1 ) {
2215             add_as_sibling = false;
2216         }
2217         else if ( r != 0 ) {
2218             return;
2219         }
2220         final Phylogeny phy = new Phylogeny();
2221         phy.setRoot( new PhylogenyNode() );
2222         phy.setRooted( true );
2223         if ( add_as_sibling ) {
2224             if ( node.isRoot() ) {
2225                 JOptionPane.showMessageDialog( this,
2226                                                "Cannot add sibling to root",
2227                                                "Attempt to add sibling to root",
2228                                                JOptionPane.ERROR_MESSAGE );
2229                 return;
2230             }
2231             phy.addAsSibling( node );
2232         }
2233         else {
2234             phy.addAsChild( node );
2235         }
2236         setNodeInPreorderToNull();
2237         _phylogeny.externalNodesHaveChanged();
2238         _phylogeny.clearHashIdToNodeMap();
2239         _phylogeny.recalculateNumberOfExternalDescendants( true );
2240         resetNodeIdToDistToLeafMap();
2241         setEdited( true );
2242         repaint();
2243     }
2244
2245     final private void addToCurrentExternalNodes( final long i ) {
2246         if ( _current_external_nodes == null ) {
2247             _current_external_nodes = new HashSet<Long>();
2248         }
2249         _current_external_nodes.add( i );
2250     }
2251
2252     final private void assignGraphicsForBranchWithColorForParentBranch( final PhylogenyNode node,
2253                                                                         final boolean is_vertical,
2254                                                                         final Graphics g,
2255                                                                         final boolean to_pdf,
2256                                                                         final boolean to_graphics_file ) {
2257         final NodeClickAction action = _control_panel.getActionWhenNodeClicked();
2258         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
2259             g.setColor( Color.BLACK );
2260         }
2261         else if ( ( ( action == NodeClickAction.COPY_SUBTREE ) || ( action == NodeClickAction.CUT_SUBTREE )
2262                 || ( action == NodeClickAction.DELETE_NODE_OR_SUBTREE ) || ( action == NodeClickAction.PASTE_SUBTREE ) || ( action == NodeClickAction.ADD_NEW_NODE ) )
2263                 && ( getCutOrCopiedTree() != null )
2264                 && ( getCopiedAndPastedNodes() != null )
2265                 && !to_pdf
2266                 && !to_graphics_file && getCopiedAndPastedNodes().contains( node.getId() ) ) {
2267             g.setColor( getTreeColorSet().getFoundColor0() );
2268         }
2269         else if ( getControlPanel().isColorBranches() && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
2270             g.setColor( PhylogenyMethods.getBranchColorValue( node ) );
2271         }
2272         else if ( to_pdf ) {
2273             g.setColor( getTreeColorSet().getBranchColorForPdf() );
2274         }
2275         else {
2276             g.setColor( getTreeColorSet().getBranchColor() );
2277         }
2278     }
2279
2280     final private void blast( final PhylogenyNode node ) {
2281         if ( !isCanBlast( node ) ) {
2282             JOptionPane.showMessageDialog( this,
2283                                            "Insufficient information present",
2284                                            "Cannot Blast",
2285                                            JOptionPane.INFORMATION_MESSAGE );
2286             return;
2287         }
2288         else {
2289             final String query = Blast.obtainQueryForBlast( node );
2290             System.out.println( "query for BLAST is: " + query );
2291             char type = '?';
2292             if ( !ForesterUtil.isEmpty( query ) ) {
2293                 if ( node.getNodeData().isHasSequence() ) {
2294                     if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getType() ) ) {
2295                         if ( node.getNodeData().getSequence().getType().toLowerCase()
2296                                 .equals( PhyloXmlUtil.SEQ_TYPE_PROTEIN ) ) {
2297                             type = 'p';
2298                         }
2299                         else {
2300                             type = 'n';
2301                         }
2302                     }
2303                     else if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getMolecularSequence() ) ) {
2304                         if ( ForesterUtil.seqIsLikelyToBeAa( node.getNodeData().getSequence().getMolecularSequence() ) ) {
2305                             type = 'p';
2306                         }
2307                         else {
2308                             type = 'n';
2309                         }
2310                     }
2311                 }
2312                 if ( type == '?' ) {
2313                     if ( SequenceAccessionTools.isProteinDbQuery( query ) ) {
2314                         type = 'p';
2315                     }
2316                     else {
2317                         type = 'n';
2318                     }
2319                 }
2320                 JApplet applet = null;
2321                 if ( isApplet() ) {
2322                     applet = obtainApplet();
2323                 }
2324                 try {
2325                     Blast.openNcbiBlastWeb( query, type == 'n', applet, this );
2326                 }
2327                 catch ( final Exception e ) {
2328                     e.printStackTrace();
2329                 }
2330                 if ( Constants.ALLOW_DDBJ_BLAST ) {
2331                     try {
2332                         System.out.println( "trying: " + query );
2333                         final Blast s = new Blast();
2334                         s.ddbjBlast( query );
2335                     }
2336                     catch ( final Exception e ) {
2337                         e.printStackTrace();
2338                     }
2339                 }
2340             }
2341         }
2342     }
2343
2344     private final int calcDynamicHidingFactor() {
2345         return ( int ) ( 0.5 + ( getTreeFontSet()._fm_large.getHeight() / ( 1.5 * getYdistance() ) ) );
2346     }
2347
2348     /**
2349      * Calculate the length of the distance between the given node and its
2350      * parent.
2351      * 
2352      * @param node
2353      * @param ext_node_x
2354      * @factor
2355      * @return the distance value
2356      */
2357     final private float calculateBranchLengthToParent( final PhylogenyNode node, final float factor ) {
2358         if ( getControlPanel().isDrawPhylogram() ) {
2359             if ( node.getDistanceToParent() < 0.0 ) {
2360                 return 0.0f;
2361             }
2362             return ( float ) ( getXcorrectionFactor() * node.getDistanceToParent() );
2363         }
2364         else {
2365             if ( ( factor == 0 ) || isNonLinedUpCladogram() ) {
2366                 return getXdistance();
2367             }
2368             return getXdistance() * factor;
2369         }
2370     }
2371
2372     final private Color calculateColorForAnnotation( final SortedSet<Annotation> ann ) {
2373         Color c = getTreeColorSet().getAnnotationColor();
2374         if ( getControlPanel().isColorAccordingToAnnotation() && ( getControlPanel().getAnnotationColors() != null ) ) {
2375             final StringBuilder sb = new StringBuilder();
2376             for( final Annotation a : ann ) {
2377                 sb.append( !ForesterUtil.isEmpty( a.getRefValue() ) ? a.getRefValue() : a.getDesc() );
2378             }
2379             final String ann_str = sb.toString();
2380             if ( !ForesterUtil.isEmpty( ann_str ) ) {
2381                 c = getControlPanel().getAnnotationColors().get( ann_str );
2382                 if ( c == null ) {
2383                     c = TreePanelUtil.calculateColorFromString( ann_str, false );
2384                     getControlPanel().getAnnotationColors().put( ann_str, c );
2385                 }
2386                 if ( c == null ) {
2387                     c = getTreeColorSet().getAnnotationColor();
2388                 }
2389             }
2390         }
2391         return c;
2392     }
2393
2394     final private float calculateOvBranchLengthToParent( final PhylogenyNode node, final int factor ) {
2395         if ( getControlPanel().isDrawPhylogram() ) {
2396             if ( node.getDistanceToParent() < 0.0 ) {
2397                 return 0.0f;
2398             }
2399             return ( float ) ( getOvXcorrectionFactor() * node.getDistanceToParent() );
2400         }
2401         else {
2402             if ( ( factor == 0 ) || isNonLinedUpCladogram() ) {
2403                 return getOvXDistance();
2404             }
2405             return getOvXDistance() * factor;
2406         }
2407     }
2408
2409     final private void cannotOpenBrowserWarningMessage( final String type_type ) {
2410         JOptionPane.showMessageDialog( this,
2411                                        "Cannot launch web browser for " + type_type + " data of this node",
2412                                        "Cannot launch web browser",
2413                                        JOptionPane.WARNING_MESSAGE );
2414     }
2415
2416     final private void colorizeSubtree( final Color c,
2417                                         final PhylogenyNode node,
2418                                         final List<PhylogenyNode> additional_nodes ) {
2419         _control_panel.setColorBranches( true );
2420         if ( _control_panel.getColorBranchesCb() != null ) {
2421             _control_panel.getColorBranchesCb().setSelected( true );
2422         }
2423         if ( node != null ) {
2424             for( final PreorderTreeIterator it = new PreorderTreeIterator( node ); it.hasNext(); ) {
2425                 it.next().getBranchData().setBranchColor( new BranchColor( c ) );
2426             }
2427         }
2428         if ( additional_nodes != null ) {
2429             for( final PhylogenyNode n : additional_nodes ) {
2430                 n.getBranchData().setBranchColor( new BranchColor( c ) );
2431             }
2432         }
2433         repaint();
2434     }
2435
2436     final private void colorSubtree( final PhylogenyNode node ) {
2437         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
2438             JOptionPane.showMessageDialog( this,
2439                                            "Cannot colorize subtree in unrooted display type",
2440                                            "Attempt to colorize subtree in unrooted display",
2441                                            JOptionPane.WARNING_MESSAGE );
2442             return;
2443         }
2444         _color_chooser.setPreviewPanel( new JPanel() );
2445         SubtreeColorizationActionListener al;
2446         if ( ( getFoundNodes0() != null ) && !getFoundNodes0().isEmpty() ) {
2447             final List<PhylogenyNode> additional_nodes = getFoundNodes0AsListOfPhylogenyNodes();
2448             al = new SubtreeColorizationActionListener( _color_chooser, node, additional_nodes );
2449         }
2450         else {
2451             al = new SubtreeColorizationActionListener( _color_chooser, node );
2452         }
2453         final JDialog dialog = JColorChooser
2454                 .createDialog( this, "Subtree colorization", true, _color_chooser, al, null );
2455         dialog.setVisible( true );
2456     }
2457
2458     final private void copySubtree( final PhylogenyNode node ) {
2459         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
2460             errorMessageNoCutCopyPasteInUnrootedDisplay();
2461             return;
2462         }
2463         setNodeInPreorderToNull();
2464         setCutOrCopiedTree( _phylogeny.copy( node ) );
2465         final List<PhylogenyNode> nodes = PhylogenyMethods.getAllDescendants( node );
2466         final Set<Long> node_ids = new HashSet<Long>( nodes.size() );
2467         for( final PhylogenyNode n : nodes ) {
2468             node_ids.add( n.getId() );
2469         }
2470         node_ids.add( node.getId() );
2471         setCopiedAndPastedNodes( node_ids );
2472         repaint();
2473     }
2474
2475     final private String createASimpleTextRepresentationOfANode( final PhylogenyNode node ) {
2476         final String tax = PhylogenyMethods.getSpecies( node );
2477         String label = node.getName();
2478         if ( !ForesterUtil.isEmpty( label ) && !ForesterUtil.isEmpty( tax ) ) {
2479             label = label + " " + tax;
2480         }
2481         else if ( !ForesterUtil.isEmpty( tax ) ) {
2482             label = tax;
2483         }
2484         else {
2485             label = "";
2486         }
2487         if ( !ForesterUtil.isEmpty( label ) ) {
2488             label = " [" + label + "]";
2489         }
2490         return label;
2491     }
2492
2493     final private void cutSubtree( final PhylogenyNode node ) {
2494         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
2495             errorMessageNoCutCopyPasteInUnrootedDisplay();
2496             return;
2497         }
2498         if ( node.isRoot() ) {
2499             JOptionPane.showMessageDialog( this,
2500                                            "Cannot cut entire tree as subtree",
2501                                            "Attempt to cut entire tree",
2502                                            JOptionPane.ERROR_MESSAGE );
2503             return;
2504         }
2505         final String label = createASimpleTextRepresentationOfANode( node );
2506         final int r = JOptionPane.showConfirmDialog( null,
2507                                                      "Cut subtree" + label + "?",
2508                                                      "Confirm Cutting of Subtree",
2509                                                      JOptionPane.YES_NO_OPTION );
2510         if ( r != JOptionPane.OK_OPTION ) {
2511             return;
2512         }
2513         setNodeInPreorderToNull();
2514         setCopiedAndPastedNodes( null );
2515         setCutOrCopiedTree( _phylogeny.copy( node ) );
2516         _phylogeny.deleteSubtree( node, true );
2517         _phylogeny.clearHashIdToNodeMap();
2518         _phylogeny.recalculateNumberOfExternalDescendants( true );
2519         resetNodeIdToDistToLeafMap();
2520         setEdited( true );
2521         repaint();
2522     }
2523
2524     final private void cycleColors() {
2525         getMainPanel().getTreeColorSet().cycleColorScheme();
2526         for( final TreePanel tree_panel : getMainPanel().getTreePanels() ) {
2527             tree_panel.setBackground( getMainPanel().getTreeColorSet().getBackgroundColor() );
2528         }
2529     }
2530
2531     final private void decreaseOvSize() {
2532         if ( ( getOvMaxWidth() > 20 ) && ( getOvMaxHeight() > 20 ) ) {
2533             setOvMaxWidth( getOvMaxWidth() - 5 );
2534             setOvMaxHeight( getOvMaxHeight() - 5 );
2535             updateOvSettings();
2536             getControlPanel().displayedPhylogenyMightHaveChanged( false );
2537         }
2538     }
2539
2540     final private void deleteNodeOrSubtree( final PhylogenyNode node ) {
2541         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
2542             errorMessageNoCutCopyPasteInUnrootedDisplay();
2543             return;
2544         }
2545         if ( node.isRoot() && ( node.getNumberOfDescendants() != 1 ) ) {
2546             JOptionPane.showMessageDialog( this,
2547                                            "Cannot delete entire tree",
2548                                            "Attempt to delete entire tree",
2549                                            JOptionPane.ERROR_MESSAGE );
2550             return;
2551         }
2552         final String label = createASimpleTextRepresentationOfANode( node );
2553         final Object[] options = { "Node only", "Entire subtree", "Cancel" };
2554         final int r = JOptionPane.showOptionDialog( this,
2555                                                     "Delete" + label + "?",
2556                                                     "Delete Node/Subtree",
2557                                                     JOptionPane.CLOSED_OPTION,
2558                                                     JOptionPane.QUESTION_MESSAGE,
2559                                                     null,
2560                                                     options,
2561                                                     options[ 2 ] );
2562         setNodeInPreorderToNull();
2563         boolean node_only = true;
2564         if ( r == 1 ) {
2565             node_only = false;
2566         }
2567         else if ( r != 0 ) {
2568             return;
2569         }
2570         if ( node_only ) {
2571             PhylogenyMethods.removeNode( node, _phylogeny );
2572         }
2573         else {
2574             _phylogeny.deleteSubtree( node, true );
2575         }
2576         _phylogeny.externalNodesHaveChanged();
2577         _phylogeny.clearHashIdToNodeMap();
2578         _phylogeny.recalculateNumberOfExternalDescendants( true );
2579         resetNodeIdToDistToLeafMap();
2580         setEdited( true );
2581         repaint();
2582     }
2583
2584     final private void displayNodePopupMenu( final PhylogenyNode node, final int x, final int y ) {
2585         makePopupMenus( node );
2586         _node_popup_menu.putClientProperty( NODE_POPMENU_NODE_CLIENT_PROPERTY, node );
2587         _node_popup_menu.show( this, x, y );
2588     }
2589
2590     final private void drawArc( final double x,
2591                                 final double y,
2592                                 final double width,
2593                                 final double heigth,
2594                                 final double start_angle,
2595                                 final double arc_angle,
2596                                 final Graphics2D g ) {
2597         _arc.setArc( x, y, width, heigth, _180_OVER_PI * start_angle, _180_OVER_PI * arc_angle, Arc2D.OPEN );
2598         g.draw( _arc );
2599     }
2600
2601     final private void drawLine( final double x1, final double y1, final double x2, final double y2, final Graphics2D g ) {
2602         if ( ( x1 == x2 ) && ( y1 == y2 ) ) {
2603             return;
2604         }
2605         _line.setLine( x1, y1, x2, y2 );
2606         g.draw( _line );
2607     }
2608
2609     final private void drawOval( final double x,
2610                                  final double y,
2611                                  final double width,
2612                                  final double heigth,
2613                                  final Graphics2D g ) {
2614         _ellipse.setFrame( x, y, width, heigth );
2615         g.draw( _ellipse );
2616     }
2617
2618     final private void drawOvalFilled( final double x,
2619                                        final double y,
2620                                        final double width,
2621                                        final double heigth,
2622                                        final Graphics2D g ) {
2623         _ellipse.setFrame( x, y, width, heigth );
2624         g.fill( _ellipse );
2625     }
2626
2627     final private void drawOvalGradient( final double x,
2628                                          final double y,
2629                                          final double width,
2630                                          final double heigth,
2631                                          final Graphics2D g,
2632                                          final Color color_1,
2633                                          final Color color_2,
2634                                          final Color color_border ) {
2635         _ellipse.setFrame( x, y, width, heigth );
2636         g.setPaint( new GradientPaint( ( float ) x,
2637                                        ( float ) y,
2638                                        color_1,
2639                                        ( float ) ( x + width ),
2640                                        ( float ) ( y + heigth ),
2641                                        color_2,
2642                                        false ) );
2643         g.fill( _ellipse );
2644         if ( color_border != null ) {
2645             g.setPaint( color_border );
2646             g.draw( _ellipse );
2647         }
2648     }
2649
2650     final private void drawRect( final float x, final float y, final float width, final float heigth, final Graphics2D g ) {
2651         _rectangle.setFrame( x, y, width, heigth );
2652         g.draw( _rectangle );
2653     }
2654
2655     final private void drawRectFilled( final double x,
2656                                        final double y,
2657                                        final double width,
2658                                        final double heigth,
2659                                        final Graphics2D g ) {
2660         _rectangle.setFrame( x, y, width, heigth );
2661         g.fill( _rectangle );
2662     }
2663
2664     final private void drawRectGradient( final double x,
2665                                          final double y,
2666                                          final double width,
2667                                          final double heigth,
2668                                          final Graphics2D g,
2669                                          final Color color_1,
2670                                          final Color color_2,
2671                                          final Color color_border ) {
2672         _rectangle.setFrame( x, y, width, heigth );
2673         g.setPaint( new GradientPaint( ( float ) x,
2674                                        ( float ) y,
2675                                        color_1,
2676                                        ( float ) ( x + width ),
2677                                        ( float ) ( y + heigth ),
2678                                        color_2,
2679                                        false ) );
2680         g.fill( _rectangle );
2681         if ( color_border != null ) {
2682             g.setPaint( color_border );
2683             g.draw( _rectangle );
2684         }
2685     }
2686
2687     private double drawTaxonomyImage( final double x, final double y, final PhylogenyNode node, final Graphics2D g ) {
2688         final List<Uri> us = new ArrayList<Uri>();
2689         for( final Taxonomy t : node.getNodeData().getTaxonomies() ) {
2690             for( final Uri uri : t.getUris() ) {
2691                 us.add( uri );
2692             }
2693         }
2694         double offset = 0;
2695         for( final Uri uri : us ) {
2696             if ( uri != null ) {
2697                 final String uri_str = uri.getValue().toString().toLowerCase();
2698                 if ( getImageMap().containsKey( uri_str ) ) {
2699                     final BufferedImage bi = getImageMap().get( uri_str );
2700                     if ( ( bi != null ) && ( bi.getHeight() > 5 ) && ( bi.getWidth() > 5 ) ) {
2701                         double scaling_factor = 1;
2702                         if ( getOptions().isAllowMagnificationOfTaxonomyImages()
2703                                 || ( bi.getHeight() > ( 1.8 * getYdistance() ) ) ) {
2704                             scaling_factor = ( 1.8 * getYdistance() ) / bi.getHeight();
2705                         }
2706                         // y = y - ( 0.9 * getYdistance() );
2707                         final double hs = bi.getHeight() * scaling_factor;
2708                         double ws = ( bi.getWidth() * scaling_factor ) + offset;
2709                         final double my_y = y - ( 0.5 * hs );
2710                         final int x_w = ( int ) ( x + ws + 0.5 );
2711                         final int y_h = ( int ) ( my_y + hs + 0.5 );
2712                         if ( ( ( x_w - x ) > 7 ) && ( ( y_h - my_y ) > 7 ) ) {
2713                             g.drawImage( bi,
2714                                          ( int ) ( x + 0.5 + offset ),
2715                                          ( int ) ( my_y + 0.5 ),
2716                                          x_w,
2717                                          y_h,
2718                                          0,
2719                                          0,
2720                                          bi.getWidth(),
2721                                          bi.getHeight(),
2722                                          null );
2723                             ws += 8;
2724                         }
2725                         else {
2726                             ws = 0.0;
2727                         }
2728                         offset = ws;
2729                     }
2730                 }
2731             }
2732         }
2733         return offset;
2734     }
2735
2736     final private void errorMessageNoCutCopyPasteInUnrootedDisplay() {
2737         JOptionPane.showMessageDialog( this,
2738                                        "Cannot cut, copy, paste, add, or delete subtrees/nodes in unrooted display",
2739                                        "Attempt to cut/copy/paste/add/delete in unrooted display",
2740                                        JOptionPane.ERROR_MESSAGE );
2741     }
2742
2743     private final Color getColorForFoundNode( final PhylogenyNode n ) {
2744         if ( isInCurrentExternalNodes( n ) ) {
2745             return getTreeColorSet().getFoundColor0();
2746         }
2747         else if ( isInFoundNodes0( n ) && !isInFoundNodes1( n ) ) {
2748             return getTreeColorSet().getFoundColor0();
2749         }
2750         else if ( !isInFoundNodes0( n ) && isInFoundNodes1( n ) ) {
2751             return getTreeColorSet().getFoundColor1();
2752         }
2753         else {
2754             return getTreeColorSet().getFoundColor0and1();
2755         }
2756     }
2757
2758     final private Set<Long> getCopiedAndPastedNodes() {
2759         return getMainPanel().getCopiedAndPastedNodes();
2760     }
2761
2762     final private Set<Long> getCurrentExternalNodes() {
2763         return _current_external_nodes;
2764     }
2765
2766     final private Phylogeny getCutOrCopiedTree() {
2767         return getMainPanel().getCutOrCopiedTree();
2768     }
2769
2770     private List<PhylogenyNode> getFoundNodes0AsListOfPhylogenyNodes() {
2771         final List<PhylogenyNode> additional_nodes = new ArrayList<PhylogenyNode>();
2772         for( final Long id : getFoundNodes0() ) {
2773             additional_nodes.add( _phylogeny.getNode( id ) );
2774         }
2775         return additional_nodes;
2776     }
2777
2778     private List<PhylogenyNode> getFoundNodes1AsListOfPhylogenyNodes() {
2779         final List<PhylogenyNode> additional_nodes = new ArrayList<PhylogenyNode>();
2780         for( final Long id : getFoundNodes1() ) {
2781             additional_nodes.add( _phylogeny.getNode( id ) );
2782         }
2783         return additional_nodes;
2784     }
2785
2786     final private float getLastDragPointX() {
2787         return _last_drag_point_x;
2788     }
2789
2790     final private float getLastDragPointY() {
2791         return _last_drag_point_y;
2792     }
2793
2794     final private short getMaxBranchesToLeaf( final PhylogenyNode node ) {
2795         if ( !_nodeid_dist_to_leaf.containsKey( node.getId() ) ) {
2796             final short m = PhylogenyMethods.calculateMaxBranchesToLeaf( node );
2797             _nodeid_dist_to_leaf.put( node.getId(), m );
2798             return m;
2799         }
2800         else {
2801             return _nodeid_dist_to_leaf.get( node.getId() );
2802         }
2803     }
2804
2805     final private double getMaxDistanceToRoot() {
2806         if ( _max_distance_to_root < 0 ) {
2807             recalculateMaxDistanceToRoot();
2808         }
2809         return _max_distance_to_root;
2810     }
2811
2812     final private float getOvMaxHeight() {
2813         return _ov_max_height;
2814     }
2815
2816     final private float getOvMaxWidth() {
2817         return _ov_max_width;
2818     }
2819
2820     final private float getOvXcorrectionFactor() {
2821         return _ov_x_correction_factor;
2822     }
2823
2824     final private float getOvXDistance() {
2825         return _ov_x_distance;
2826     }
2827
2828     final private int getOvXPosition() {
2829         return _ov_x_position;
2830     }
2831
2832     final private float getOvYDistance() {
2833         return _ov_y_distance;
2834     }
2835
2836     final private int getOvYPosition() {
2837         return _ov_y_position;
2838     }
2839
2840     final private int getOvYStart() {
2841         return _ov_y_start;
2842     }
2843
2844     final private List<Accession> getPdbAccs( final PhylogenyNode node ) {
2845         final List<Accession> pdb_ids = new ArrayList<Accession>();
2846         if ( node.getNodeData().isHasSequence() ) {
2847             final Sequence seq = node.getNodeData().getSequence();
2848             if ( !ForesterUtil.isEmpty( seq.getCrossReferences() ) ) {
2849                 final SortedSet<Accession> cross_refs = seq.getCrossReferences();
2850                 for( final Accession acc : cross_refs ) {
2851                     if ( acc.getSource().equalsIgnoreCase( "pdb" ) ) {
2852                         pdb_ids.add( acc );
2853                     }
2854                 }
2855             }
2856         }
2857         return pdb_ids;
2858     }
2859
2860     final private double getScaleDistance() {
2861         return _scale_distance;
2862     }
2863
2864     final private String getScaleLabel() {
2865         return _scale_label;
2866     }
2867
2868     final private TreeFontSet getTreeFontSet() {
2869         return getMainPanel().getTreeFontSet();
2870     }
2871
2872     final private float getUrtFactor() {
2873         return _urt_factor;
2874     }
2875
2876     final private float getUrtFactorOv() {
2877         return _urt_factor_ov;
2878     }
2879
2880     final private void handleClickToAction( final NodeClickAction action, final PhylogenyNode node ) {
2881         switch ( action ) {
2882             case SHOW_DATA:
2883                 showNodeFrame( node );
2884                 break;
2885             case COLLAPSE:
2886                 collapse( node );
2887                 break;
2888             case REROOT:
2889                 reRoot( node );
2890                 break;
2891             case SUBTREE:
2892                 subTree( node );
2893                 break;
2894             case SWAP:
2895                 swap( node );
2896                 break;
2897             case COLOR_SUBTREE:
2898                 colorSubtree( node );
2899                 break;
2900             case OPEN_SEQ_WEB:
2901                 openSeqWeb( node );
2902                 break;
2903             case BLAST:
2904                 blast( node );
2905                 break;
2906             case OPEN_TAX_WEB:
2907                 openTaxWeb( node );
2908                 break;
2909             case OPEN_PDB_WEB:
2910                 openPdbWeb( node );
2911                 break;
2912             case CUT_SUBTREE:
2913                 cutSubtree( node );
2914                 break;
2915             case COPY_SUBTREE:
2916                 copySubtree( node );
2917                 break;
2918             case PASTE_SUBTREE:
2919                 pasteSubtree( node );
2920                 break;
2921             case DELETE_NODE_OR_SUBTREE:
2922                 deleteNodeOrSubtree( node );
2923                 break;
2924             case ADD_NEW_NODE:
2925                 addEmptyNode( node );
2926                 break;
2927             case EDIT_NODE_DATA:
2928                 showNodeEditFrame( node );
2929                 break;
2930             case SELECT_NODES:
2931                 selectNode( node );
2932                 break;
2933             case SORT_DESCENDENTS:
2934                 sortDescendants( node );
2935                 break;
2936             case GET_EXT_DESC_DATA:
2937                 showExtDescNodeData( node );
2938                 break;
2939             default:
2940                 throw new IllegalArgumentException( "unknown action: " + action );
2941         }
2942     }
2943
2944     final private void increaseCurrentExternalNodesDataBufferChangeCounter() {
2945         _current_external_nodes_data_buffer_change_counter++;
2946     }
2947
2948     final private void increaseOvSize() {
2949         if ( ( getOvMaxWidth() < ( getMainPanel().getCurrentScrollPane().getViewport().getVisibleRect().getWidth() / 2 ) )
2950                 && ( getOvMaxHeight() < ( getMainPanel().getCurrentScrollPane().getViewport().getVisibleRect()
2951                         .getHeight() / 2 ) ) ) {
2952             setOvMaxWidth( getOvMaxWidth() + 5 );
2953             setOvMaxHeight( getOvMaxHeight() + 5 );
2954             updateOvSettings();
2955             getControlPanel().displayedPhylogenyMightHaveChanged( false );
2956         }
2957     }
2958
2959     final private void init() {
2960         _color_chooser = new JColorChooser();
2961         _rollover_popup = new JTextArea();
2962         _rollover_popup.setFont( POPUP_FONT );
2963         resetNodeIdToDistToLeafMap();
2964         setTextAntialias();
2965         setTreeFile( null );
2966         setEdited( false );
2967         initializeOvSettings();
2968         setStartingAngle( ( TWO_PI * 3 ) / 4 );
2969         final ImageLoader il = new ImageLoader( this );
2970         new Thread( il ).start();
2971     }
2972
2973     final private void initializeOvSettings() {
2974         setOvMaxHeight( getConfiguration().getOvMaxHeight() );
2975         setOvMaxWidth( getConfiguration().getOvMaxWidth() );
2976     }
2977
2978     final private boolean inOvVirtualRectangle( final int x, final int y ) {
2979         return ( ( x >= ( getOvVirtualRectangle().x - 1 ) )
2980                 && ( x <= ( getOvVirtualRectangle().x + getOvVirtualRectangle().width + 1 ) )
2981                 && ( y >= ( getOvVirtualRectangle().y - 1 ) ) && ( y <= ( getOvVirtualRectangle().y
2982                 + getOvVirtualRectangle().height + 1 ) ) );
2983     }
2984
2985     final private boolean inOvVirtualRectangle( final MouseEvent e ) {
2986         return ( inOvVirtualRectangle( e.getX(), e.getY() ) );
2987     }
2988
2989     final private boolean isCanBlast( final PhylogenyNode node ) {
2990         if ( !node.getNodeData().isHasSequence() && ForesterUtil.isEmpty( node.getName() ) ) {
2991             return false;
2992         }
2993         return Blast.isContainsQueryForBlast( node );
2994     }
2995
2996     final private String isCanOpenSeqWeb( final PhylogenyNode node ) {
2997         final Accession a = SequenceAccessionTools.obtainAccessorFromDataFields( node );
2998         if ( a != null ) {
2999             return a.getValue();
3000         }
3001         return null;
3002     }
3003
3004     final private boolean isCanOpenTaxWeb( final PhylogenyNode node ) {
3005         if ( node.getNodeData().isHasTaxonomy()
3006                 && ( ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getScientificName() ) )
3007                         || ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getTaxonomyCode() ) )
3008                         || ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getCommonName() ) ) || ( ( node
3009                         .getNodeData().getTaxonomy().getIdentifier() != null ) && !ForesterUtil.isEmpty( node
3010                         .getNodeData().getTaxonomy().getIdentifier().getValue() ) ) ) ) {
3011             return true;
3012         }
3013         else {
3014             return false;
3015         }
3016     }
3017
3018     final private boolean isInCurrentExternalNodes( final PhylogenyNode node ) {
3019         return ( ( getCurrentExternalNodes() != null ) && getCurrentExternalNodes().contains( node.getId() ) );
3020     }
3021
3022     private boolean isInFoundNodes( final PhylogenyNode n ) {
3023         return isInFoundNodes0( n ) || isInFoundNodes1( n );
3024     }
3025
3026     final private boolean isInFoundNodes0( final PhylogenyNode node ) {
3027         return ( ( getFoundNodes0() != null ) && getFoundNodes0().contains( node.getId() ) );
3028     }
3029
3030     final private boolean isInFoundNodes1( final PhylogenyNode node ) {
3031         return ( ( getFoundNodes1() != null ) && getFoundNodes1().contains( node.getId() ) );
3032     }
3033
3034     final private boolean isInOv() {
3035         return _in_ov;
3036     }
3037
3038     final private boolean isNodeDataInvisible( final PhylogenyNode node ) {
3039         int y_dist = 40;
3040         if ( getControlPanel().isShowTaxonomyImages() ) {
3041             y_dist = 40 + ( int ) getYdistance();
3042         }
3043         return ( ( node.getYcoord() < ( getVisibleRect().getMinY() - y_dist ) )
3044                 || ( node.getYcoord() > ( getVisibleRect().getMaxY() + y_dist ) ) || ( ( node.getParent() != null ) && ( node
3045                 .getParent().getXcoord() > getVisibleRect().getMaxX() ) ) );
3046     }
3047
3048     final private boolean isNodeDataInvisibleUnrootedCirc( final PhylogenyNode node ) {
3049         return ( ( node.getYcoord() < ( getVisibleRect().getMinY() - 20 ) )
3050                 || ( node.getYcoord() > ( getVisibleRect().getMaxY() + 20 ) )
3051                 || ( node.getXcoord() < ( getVisibleRect().getMinX() - 20 ) ) || ( node.getXcoord() > ( getVisibleRect()
3052                 .getMaxX() + 20 ) ) );
3053     }
3054
3055     final private boolean isNonLinedUpCladogram() {
3056         return getOptions().getCladogramType() == CLADOGRAM_TYPE.NON_LINED_UP;
3057     }
3058
3059     final private boolean isUniformBranchLengthsForCladogram() {
3060         return getOptions().getCladogramType() == CLADOGRAM_TYPE.TOTAL_NODE_SUM_DEP;
3061     }
3062
3063     final private void keyPressedCalls( final KeyEvent e ) {
3064         if ( isOvOn() && ( getMousePosition() != null ) && ( getMousePosition().getLocation() != null ) ) {
3065             if ( inOvVirtualRectangle( getMousePosition().x, getMousePosition().y ) ) {
3066                 if ( !isInOvRect() ) {
3067                     setInOvRect( true );
3068                 }
3069             }
3070             else if ( isInOvRect() ) {
3071                 setInOvRect( false );
3072             }
3073         }
3074         if ( e.getModifiersEx() == InputEvent.CTRL_DOWN_MASK ) {
3075             if ( ( e.getKeyCode() == KeyEvent.VK_DELETE ) || ( e.getKeyCode() == KeyEvent.VK_HOME )
3076                     || ( e.getKeyCode() == KeyEvent.VK_F ) ) {
3077                 getMainPanel().getTreeFontSet().mediumFonts();
3078                 getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( true );
3079             }
3080             else if ( ( e.getKeyCode() == KeyEvent.VK_SUBTRACT ) || ( e.getKeyCode() == KeyEvent.VK_MINUS ) ) {
3081                 getMainPanel().getTreeFontSet().decreaseFontSize( 1, false );
3082                 getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( true );
3083             }
3084             else if ( plusPressed( e.getKeyCode() ) ) {
3085                 getMainPanel().getTreeFontSet().increaseFontSize();
3086                 getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( true );
3087             }
3088         }
3089         else {
3090             if ( ( e.getKeyCode() == KeyEvent.VK_DELETE ) || ( e.getKeyCode() == KeyEvent.VK_HOME )
3091                     || ( e.getKeyCode() == KeyEvent.VK_F ) ) {
3092                 getControlPanel().showWhole();
3093             }
3094             else if ( ( e.getKeyCode() == KeyEvent.VK_UP ) || ( e.getKeyCode() == KeyEvent.VK_DOWN )
3095                     || ( e.getKeyCode() == KeyEvent.VK_LEFT ) || ( e.getKeyCode() == KeyEvent.VK_RIGHT ) ) {
3096                 if ( e.getModifiersEx() == InputEvent.SHIFT_DOWN_MASK ) {
3097                     if ( e.getKeyCode() == KeyEvent.VK_UP ) {
3098                         getMainPanel().getControlPanel().zoomInY( Constants.WHEEL_ZOOM_IN_FACTOR );
3099                         getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
3100                     }
3101                     else if ( e.getKeyCode() == KeyEvent.VK_DOWN ) {
3102                         getMainPanel().getControlPanel().zoomOutY( Constants.WHEEL_ZOOM_OUT_FACTOR );
3103                         getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
3104                     }
3105                     else if ( e.getKeyCode() == KeyEvent.VK_LEFT ) {
3106                         getMainPanel().getControlPanel().zoomOutX( Constants.WHEEL_ZOOM_OUT_FACTOR,
3107                                                                    Constants.WHEEL_ZOOM_OUT_X_CORRECTION_FACTOR );
3108                         getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
3109                     }
3110                     else if ( e.getKeyCode() == KeyEvent.VK_RIGHT ) {
3111                         getMainPanel().getControlPanel().zoomInX( Constants.WHEEL_ZOOM_IN_FACTOR,
3112                                                                   Constants.WHEEL_ZOOM_IN_FACTOR );
3113                         getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
3114                     }
3115                 }
3116                 else {
3117                     final int d = 80;
3118                     int dx = 0;
3119                     int dy = -d;
3120                     if ( e.getKeyCode() == KeyEvent.VK_DOWN ) {
3121                         dy = d;
3122                     }
3123                     else if ( e.getKeyCode() == KeyEvent.VK_LEFT ) {
3124                         dx = -d;
3125                         dy = 0;
3126                     }
3127                     else if ( e.getKeyCode() == KeyEvent.VK_RIGHT ) {
3128                         dx = d;
3129                         dy = 0;
3130                     }
3131                     final Point scroll_position = getMainPanel().getCurrentScrollPane().getViewport().getViewPosition();
3132                     scroll_position.x = scroll_position.x + dx;
3133                     scroll_position.y = scroll_position.y + dy;
3134                     if ( scroll_position.x <= 0 ) {
3135                         scroll_position.x = 0;
3136                     }
3137                     else {
3138                         final int max_x = getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getMaximum()
3139                                 - getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getVisibleAmount();
3140                         if ( scroll_position.x >= max_x ) {
3141                             scroll_position.x = max_x;
3142                         }
3143                     }
3144                     if ( scroll_position.y <= 0 ) {
3145                         scroll_position.y = 0;
3146                     }
3147                     else {
3148                         final int max_y = getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getMaximum()
3149                                 - getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getVisibleAmount();
3150                         if ( scroll_position.y >= max_y ) {
3151                             scroll_position.y = max_y;
3152                         }
3153                     }
3154                     repaint();
3155                     getMainPanel().getCurrentScrollPane().getViewport().setViewPosition( scroll_position );
3156                 }
3157             }
3158             else if ( ( e.getKeyCode() == KeyEvent.VK_SUBTRACT ) || ( e.getKeyCode() == KeyEvent.VK_MINUS ) ) {
3159                 getMainPanel().getControlPanel().zoomOutY( Constants.WHEEL_ZOOM_OUT_FACTOR );
3160                 getMainPanel().getControlPanel().zoomOutX( Constants.WHEEL_ZOOM_OUT_FACTOR,
3161                                                            Constants.WHEEL_ZOOM_OUT_X_CORRECTION_FACTOR );
3162                 getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
3163             }
3164             else if ( plusPressed( e.getKeyCode() ) ) {
3165                 getMainPanel().getControlPanel().zoomInX( Constants.WHEEL_ZOOM_IN_FACTOR,
3166                                                           Constants.WHEEL_ZOOM_IN_FACTOR );
3167                 getMainPanel().getControlPanel().zoomInY( Constants.WHEEL_ZOOM_IN_FACTOR );
3168                 getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
3169             }
3170             else if ( e.getKeyCode() == KeyEvent.VK_S ) {
3171                 if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
3172                         || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
3173                     setStartingAngle( ( getStartingAngle() % TWO_PI ) + ANGLE_ROTATION_UNIT );
3174                     getControlPanel().displayedPhylogenyMightHaveChanged( false );
3175                 }
3176             }
3177             else if ( e.getKeyCode() == KeyEvent.VK_A ) {
3178                 if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
3179                         || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
3180                     setStartingAngle( ( getStartingAngle() % TWO_PI ) - ANGLE_ROTATION_UNIT );
3181                     if ( getStartingAngle() < 0 ) {
3182                         setStartingAngle( TWO_PI + getStartingAngle() );
3183                     }
3184                     getControlPanel().displayedPhylogenyMightHaveChanged( false );
3185                 }
3186             }
3187             else if ( e.getKeyCode() == KeyEvent.VK_D ) {
3188                 boolean selected = false;
3189                 if ( getOptions().getNodeLabelDirection() == NODE_LABEL_DIRECTION.HORIZONTAL ) {
3190                     getOptions().setNodeLabelDirection( NODE_LABEL_DIRECTION.RADIAL );
3191                     selected = true;
3192                 }
3193                 else {
3194                     getOptions().setNodeLabelDirection( NODE_LABEL_DIRECTION.HORIZONTAL );
3195                 }
3196                 if ( getMainPanel().getMainFrame() == null ) {
3197                     // Must be "E" applet version.
3198                     final ArchaeopteryxE ae = ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet();
3199                     if ( ae.getlabelDirectionCbmi() != null ) {
3200                         ae.getlabelDirectionCbmi().setSelected( selected );
3201                     }
3202                 }
3203                 else {
3204                     getMainPanel().getMainFrame().getlabelDirectionCbmi().setSelected( selected );
3205                 }
3206                 repaint();
3207             }
3208             else if ( e.getKeyCode() == KeyEvent.VK_X ) {
3209                 switchDisplaygetPhylogenyGraphicsType();
3210                 repaint();
3211             }
3212             else if ( e.getKeyCode() == KeyEvent.VK_C ) {
3213                 cycleColors();
3214                 repaint();
3215             }
3216             else if ( getOptions().isShowOverview() && isOvOn() && ( e.getKeyCode() == KeyEvent.VK_O ) ) {
3217                 MainFrame.cycleOverview( getOptions(), this );
3218                 repaint();
3219             }
3220             else if ( getOptions().isShowOverview() && isOvOn() && ( e.getKeyCode() == KeyEvent.VK_I ) ) {
3221                 increaseOvSize();
3222             }
3223             else if ( getOptions().isShowOverview() && isOvOn() && ( e.getKeyCode() == KeyEvent.VK_U ) ) {
3224                 decreaseOvSize();
3225             }
3226             e.consume();
3227         }
3228     }
3229
3230     final private void makePopupMenus( final PhylogenyNode node ) {
3231         _node_popup_menu = new JPopupMenu();
3232         final List<String> clickto_names = _main_panel.getControlPanel().getSingleClickToNames();
3233         _node_popup_menu_items = new JMenuItem[ clickto_names.size() ];
3234         for( int i = 0; i < clickto_names.size(); i++ ) {
3235             final String title = clickto_names.get( i );
3236             _node_popup_menu_items[ i ] = new JMenuItem( title );
3237             if ( title.equals( Configuration.clickto_options[ Configuration.open_seq_web ][ 0 ] ) ) {
3238                 final String id = isCanOpenSeqWeb( node );
3239                 if ( !ForesterUtil.isEmpty( id ) ) {
3240                     _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " [" + id + "]" );
3241                     _node_popup_menu_items[ i ].setEnabled( true );
3242                 }
3243                 else {
3244                     _node_popup_menu_items[ i ].setEnabled( false );
3245                 }
3246             }
3247             else if ( title.equals( Configuration.clickto_options[ Configuration.open_pdb_web ][ 0 ] ) ) {
3248                 final List<Accession> accs = getPdbAccs( node );
3249                 _node_popup_menu_items[ i ] = new JMenuItem( title );
3250                 if ( !ForesterUtil.isEmpty( accs ) ) {
3251                     if ( accs.size() == 1 ) {
3252                         _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " ["
3253                                 + TreePanelUtil.pdbAccToString( accs, 0 ) + "]" );
3254                         _node_popup_menu_items[ i ].setEnabled( true );
3255                     }
3256                     else if ( accs.size() == 2 ) {
3257                         _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " ["
3258                                 + TreePanelUtil.pdbAccToString( accs, 0 ) + ", "
3259                                 + TreePanelUtil.pdbAccToString( accs, 1 ) + "]" );
3260                         _node_popup_menu_items[ i ].setEnabled( true );
3261                     }
3262                     else if ( accs.size() == 3 ) {
3263                         _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " ["
3264                                 + TreePanelUtil.pdbAccToString( accs, 0 ) + ", "
3265                                 + TreePanelUtil.pdbAccToString( accs, 1 ) + ", "
3266                                 + TreePanelUtil.pdbAccToString( accs, 2 ) + "]" );
3267                         _node_popup_menu_items[ i ].setEnabled( true );
3268                     }
3269                     else {
3270                         _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " ["
3271                                 + TreePanelUtil.pdbAccToString( accs, 0 ) + ", "
3272                                 + TreePanelUtil.pdbAccToString( accs, 1 ) + ", "
3273                                 + TreePanelUtil.pdbAccToString( accs, 2 ) + ", + " + ( accs.size() - 3 ) + " more]" );
3274                         _node_popup_menu_items[ i ].setEnabled( true );
3275                     }
3276                 }
3277                 else {
3278                     _node_popup_menu_items[ i ].setEnabled( false );
3279                 }
3280                 //
3281             }
3282             else if ( title.equals( Configuration.clickto_options[ Configuration.open_tax_web ][ 0 ] ) ) {
3283                 _node_popup_menu_items[ i ].setEnabled( isCanOpenTaxWeb( node ) );
3284             }
3285             else if ( title.equals( Configuration.clickto_options[ Configuration.blast ][ 0 ] ) ) {
3286                 _node_popup_menu_items[ i ].setEnabled( isCanBlast( node ) );
3287             }
3288             else if ( title.equals( Configuration.clickto_options[ Configuration.delete_subtree_or_node ][ 0 ] ) ) {
3289                 if ( !getOptions().isEditable() ) {
3290                     continue;
3291                 }
3292                 _node_popup_menu_items[ i ].setEnabled( isCanDelete() );
3293             }
3294             else if ( title.equals( Configuration.clickto_options[ Configuration.cut_subtree ][ 0 ] ) ) {
3295                 if ( !getOptions().isEditable() ) {
3296                     continue;
3297                 }
3298                 _node_popup_menu_items[ i ].setEnabled( isCanCut( node ) );
3299             }
3300             else if ( title.equals( Configuration.clickto_options[ Configuration.copy_subtree ][ 0 ] ) ) {
3301                 if ( !getOptions().isEditable() ) {
3302                     continue;
3303                 }
3304                 _node_popup_menu_items[ i ].setEnabled( isCanCopy() );
3305             }
3306             else if ( title.equals( Configuration.clickto_options[ Configuration.paste_subtree ][ 0 ] ) ) {
3307                 if ( !getOptions().isEditable() ) {
3308                     continue;
3309                 }
3310                 _node_popup_menu_items[ i ].setEnabled( isCanPaste() );
3311             }
3312             else if ( title.equals( Configuration.clickto_options[ Configuration.edit_node_data ][ 0 ] ) ) {
3313                 if ( !getOptions().isEditable() ) {
3314                     continue;
3315                 }
3316             }
3317             else if ( title.equals( Configuration.clickto_options[ Configuration.add_new_node ][ 0 ] ) ) {
3318                 if ( !getOptions().isEditable() ) {
3319                     continue;
3320                 }
3321             }
3322             else if ( title.equals( Configuration.clickto_options[ Configuration.reroot ][ 0 ] ) ) {
3323                 _node_popup_menu_items[ i ].setEnabled( isCanReroot() );
3324             }
3325             else if ( title.equals( Configuration.clickto_options[ Configuration.collapse_uncollapse ][ 0 ] ) ) {
3326                 _node_popup_menu_items[ i ].setEnabled( ( isCanCollapse() && !node.isExternal() ) );
3327             }
3328             else if ( title.equals( Configuration.clickto_options[ Configuration.color_subtree ][ 0 ] ) ) {
3329                 _node_popup_menu_items[ i ].setEnabled( isCanColorSubtree() );
3330             }
3331             else if ( title.equals( Configuration.clickto_options[ Configuration.subtree ][ 0 ] ) ) {
3332                 _node_popup_menu_items[ i ].setEnabled( isCanSubtree( node ) );
3333             }
3334             else if ( title.equals( Configuration.clickto_options[ Configuration.swap ][ 0 ] ) ) {
3335                 _node_popup_menu_items[ i ].setEnabled( node.getNumberOfDescendants() == 2 );
3336             }
3337             else if ( title.equals( Configuration.clickto_options[ Configuration.sort_descendents ][ 0 ] ) ) {
3338                 _node_popup_menu_items[ i ].setEnabled( node.getNumberOfDescendants() > 1 );
3339             }
3340             _node_popup_menu_items[ i ].addActionListener( this );
3341             _node_popup_menu.add( _node_popup_menu_items[ i ] );
3342         }
3343     }
3344
3345     private final String obtainTitleForExtDescNodeData() {
3346         switch ( getOptions().getExtDescNodeDataToReturn() ) {
3347             case NODE_NAME:
3348                 return "Node Names";
3349             case GENE_NAME:
3350                 return "Gene Names";
3351             case SEQUENCE_NAME:
3352                 return "Sequence Names";
3353             case SEQUENCE_SYMBOL:
3354                 return "Sequence Symbols";
3355             case SEQUENCE_MOL_SEQ:
3356                 return "Molecular Sequences";
3357             case SEQUENCE_MOL_SEQ_FASTA:
3358                 return "Molecular Sequences (Fasta)";
3359             case SEQUENCE_ACC:
3360                 return "Sequence Accessors";
3361             case TAXONOMY_SCIENTIFIC_NAME:
3362                 return "Scientific Names";
3363             case TAXONOMY_CODE:
3364                 return "Taxonomy Codes";
3365             case TAXONOMY_COMM0N_NAME:
3366                 return "Taxonomy Common Names";
3367             case UNKNOWN:
3368                 return "User Selected Data";
3369             default:
3370                 throw new IllegalArgumentException( "unknown data element: "
3371                         + getOptions().getExtDescNodeDataToReturn() );
3372         }
3373     }
3374
3375     final private void openPdbWeb( final PhylogenyNode node ) {
3376         final List<Accession> pdb_ids = getPdbAccs( node );
3377         if ( ForesterUtil.isEmpty( pdb_ids ) ) {
3378             cannotOpenBrowserWarningMessage( "PDB" );
3379             return;
3380         }
3381         final List<String> uri_strs = TreePanelUtil.createUrisForPdbWeb( node, pdb_ids, getConfiguration(), this );
3382         if ( !ForesterUtil.isEmpty( uri_strs ) ) {
3383             for( final String uri_str : uri_strs ) {
3384                 try {
3385                     AptxUtil.launchWebBrowser( new URI( uri_str ),
3386                                                isApplet(),
3387                                                isApplet() ? obtainApplet() : null,
3388                                                "_aptx_seq" );
3389                 }
3390                 catch ( final IOException e ) {
3391                     AptxUtil.showErrorMessage( this, e.toString() );
3392                     e.printStackTrace();
3393                 }
3394                 catch ( final URISyntaxException e ) {
3395                     AptxUtil.showErrorMessage( this, e.toString() );
3396                     e.printStackTrace();
3397                 }
3398             }
3399         }
3400         else {
3401             cannotOpenBrowserWarningMessage( "PDB" );
3402         }
3403     }
3404
3405     final private void openSeqWeb( final PhylogenyNode node ) {
3406         if ( ForesterUtil.isEmpty( isCanOpenSeqWeb( node ) ) ) {
3407             cannotOpenBrowserWarningMessage( "sequence" );
3408             return;
3409         }
3410         final String uri_str = TreePanelUtil.createUriForSeqWeb( node, getConfiguration(), this );
3411         if ( !ForesterUtil.isEmpty( uri_str ) ) {
3412             try {
3413                 AptxUtil.launchWebBrowser( new URI( uri_str ),
3414                                            isApplet(),
3415                                            isApplet() ? obtainApplet() : null,
3416                                            "_aptx_seq" );
3417             }
3418             catch ( final IOException e ) {
3419                 AptxUtil.showErrorMessage( this, e.toString() );
3420                 e.printStackTrace();
3421             }
3422             catch ( final URISyntaxException e ) {
3423                 AptxUtil.showErrorMessage( this, e.toString() );
3424                 e.printStackTrace();
3425             }
3426         }
3427         else {
3428             cannotOpenBrowserWarningMessage( "sequence" );
3429         }
3430     }
3431
3432     final private void openTaxWeb( final PhylogenyNode node ) {
3433         if ( !isCanOpenTaxWeb( node ) ) {
3434             cannotOpenBrowserWarningMessage( "taxonomic" );
3435             return;
3436         }
3437         String uri_str = null;
3438         final Taxonomy tax = node.getNodeData().getTaxonomy();
3439         if ( ( tax.getIdentifier() != null ) && !ForesterUtil.isEmpty( tax.getIdentifier().getValue() )
3440                 && tax.getIdentifier().getValue().startsWith( "http://" ) ) {
3441             try {
3442                 uri_str = new URI( tax.getIdentifier().getValue() ).toString();
3443             }
3444             catch ( final URISyntaxException e ) {
3445                 AptxUtil.showErrorMessage( this, e.toString() );
3446                 uri_str = null;
3447                 e.printStackTrace();
3448             }
3449         }
3450         else if ( ( tax.getIdentifier() != null )
3451                 && !ForesterUtil.isEmpty( tax.getIdentifier().getValue() )
3452                 && !ForesterUtil.isEmpty( tax.getIdentifier().getProvider() )
3453                 && ( tax.getIdentifier().getProvider().equalsIgnoreCase( "ncbi" ) || tax.getIdentifier().getProvider()
3454                         .equalsIgnoreCase( "uniprot" ) ) ) {
3455             try {
3456                 uri_str = "http://www.uniprot.org/taxonomy/"
3457                         + URLEncoder.encode( tax.getIdentifier().getValue(), ForesterConstants.UTF8 );
3458             }
3459             catch ( final UnsupportedEncodingException e ) {
3460                 AptxUtil.showErrorMessage( this, e.toString() );
3461                 e.printStackTrace();
3462             }
3463         }
3464         else if ( !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
3465             try {
3466                 uri_str = "http://www.uniprot.org/taxonomy/?query="
3467                         + URLEncoder.encode( tax.getScientificName(), ForesterConstants.UTF8 );
3468             }
3469             catch ( final UnsupportedEncodingException e ) {
3470                 AptxUtil.showErrorMessage( this, e.toString() );
3471                 e.printStackTrace();
3472             }
3473         }
3474         else if ( !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
3475             try {
3476                 uri_str = "http://www.uniprot.org/taxonomy/?query="
3477                         + URLEncoder.encode( tax.getTaxonomyCode(), ForesterConstants.UTF8 );
3478             }
3479             catch ( final UnsupportedEncodingException e ) {
3480                 AptxUtil.showErrorMessage( this, e.toString() );
3481                 e.printStackTrace();
3482             }
3483         }
3484         else if ( !ForesterUtil.isEmpty( tax.getCommonName() ) ) {
3485             try {
3486                 uri_str = "http://www.uniprot.org/taxonomy/?query="
3487                         + URLEncoder.encode( tax.getCommonName(), ForesterConstants.UTF8 );
3488             }
3489             catch ( final UnsupportedEncodingException e ) {
3490                 AptxUtil.showErrorMessage( this, e.toString() );
3491                 e.printStackTrace();
3492             }
3493         }
3494         if ( !ForesterUtil.isEmpty( uri_str ) ) {
3495             try {
3496                 AptxUtil.launchWebBrowser( new URI( uri_str ),
3497                                            isApplet(),
3498                                            isApplet() ? obtainApplet() : null,
3499                                            "_aptx_tax" );
3500             }
3501             catch ( final IOException e ) {
3502                 AptxUtil.showErrorMessage( this, e.toString() );
3503                 e.printStackTrace();
3504             }
3505             catch ( final URISyntaxException e ) {
3506                 AptxUtil.showErrorMessage( this, e.toString() );
3507                 e.printStackTrace();
3508             }
3509         }
3510         else {
3511             cannotOpenBrowserWarningMessage( "taxonomic" );
3512         }
3513     }
3514
3515     final private void paintBranchLength( final Graphics2D g,
3516                                           final PhylogenyNode node,
3517                                           final boolean to_pdf,
3518                                           final boolean to_graphics_file ) {
3519         g.setFont( getTreeFontSet().getSmallFont() );
3520         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
3521             g.setColor( Color.BLACK );
3522         }
3523         else {
3524             g.setColor( getTreeColorSet().getBranchLengthColor() );
3525         }
3526         if ( !node.isRoot() ) {
3527             if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
3528                 TreePanel.drawString( FORMATTER_BRANCH_LENGTH.format( node.getDistanceToParent() ), node.getParent()
3529                         .getXcoord() + EURO_D, node.getYcoord() - getTreeFontSet()._small_max_descent, g );
3530             }
3531             else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
3532                 TreePanel.drawString( FORMATTER_BRANCH_LENGTH.format( node.getDistanceToParent() ), node.getParent()
3533                         .getXcoord() + ROUNDED_D, node.getYcoord() - getTreeFontSet()._small_max_descent, g );
3534             }
3535             else {
3536                 TreePanel.drawString( FORMATTER_BRANCH_LENGTH.format( node.getDistanceToParent() ), node.getParent()
3537                         .getXcoord() + 3, node.getYcoord() - getTreeFontSet()._small_max_descent, g );
3538             }
3539         }
3540         else {
3541             TreePanel.drawString( FORMATTER_BRANCH_LENGTH.format( node.getDistanceToParent() ), 3, node.getYcoord()
3542                     - getTreeFontSet()._small_max_descent, g );
3543         }
3544     }
3545
3546     final private void paintBranchLite( final Graphics2D g,
3547                                         final float x1,
3548                                         final float x2,
3549                                         final float y1,
3550                                         final float y2,
3551                                         final PhylogenyNode node ) {
3552         g.setColor( getTreeColorSet().getOvColor() );
3553         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR ) {
3554             drawLine( x1, y1, x2, y2, g );
3555         }
3556         else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CONVEX ) {
3557             _quad_curve.setCurve( x1, y1, x1, y2, x2, y2 );
3558             ( g ).draw( _quad_curve );
3559         }
3560         else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CURVED ) {
3561             final float dx = x2 - x1;
3562             final float dy = y2 - y1;
3563             _cubic_curve.setCurve( x1, y1, x1 + ( dx * 0.4f ), y1 + ( dy * 0.2f ), x1 + ( dx * 0.6f ), y1
3564                     + ( dy * 0.8f ), x2, y2 );
3565             ( g ).draw( _cubic_curve );
3566         }
3567         else {
3568             final float x2a = x2;
3569             final float x1a = x1;
3570             // draw the vertical line
3571             if ( node.isFirstChildNode() || node.isLastChildNode() ) {
3572                 drawLine( x1, y1, x1, y2, g );
3573             }
3574             // draw the horizontal line
3575             drawLine( x1a, y2, x2a, y2, g );
3576         }
3577     }
3578
3579     /**
3580      * Paint a branch which consists of a vertical and a horizontal bar
3581      * @param is_ind_found_nodes 
3582      */
3583     final private void paintBranchRectangular( final Graphics2D g,
3584                                                final float x1,
3585                                                final float x2,
3586                                                final float y1,
3587                                                final float y2,
3588                                                final PhylogenyNode node,
3589                                                final boolean to_pdf,
3590                                                final boolean to_graphics_file ) {
3591         assignGraphicsForBranchWithColorForParentBranch( node, false, g, to_pdf, to_graphics_file );
3592         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR ) {
3593             drawLine( x1, y1, x2, y2, g );
3594         }
3595         else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CONVEX ) {
3596             _quad_curve.setCurve( x1, y1, x1, y2, x2, y2 );
3597             g.draw( _quad_curve );
3598         }
3599         else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CURVED ) {
3600             final float dx = x2 - x1;
3601             final float dy = y2 - y1;
3602             _cubic_curve.setCurve( x1, y1, x1 + ( dx * 0.4f ), y1 + ( dy * 0.2f ), x1 + ( dx * 0.6f ), y1
3603                     + ( dy * 0.8f ), x2, y2 );
3604             g.draw( _cubic_curve );
3605         }
3606         else {
3607             final float x2a = x2;
3608             final float x1a = x1;
3609             float y2_r = 0;
3610             if ( node.isFirstChildNode() || node.isLastChildNode()
3611                     || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE )
3612                     || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) ) {
3613                 if ( !to_graphics_file
3614                         && !to_pdf
3615                         && ( ( ( y2 < ( getVisibleRect().getMinY() - 20 ) ) && ( y1 < ( getVisibleRect().getMinY() - 20 ) ) ) || ( ( y2 > ( getVisibleRect()
3616                                 .getMaxY() + 20 ) ) && ( y1 > ( getVisibleRect().getMaxY() + 20 ) ) ) ) ) {
3617                     // Do nothing.
3618                 }
3619                 else {
3620                     if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
3621                         float x2c = x1 + EURO_D;
3622                         if ( x2c > x2a ) {
3623                             x2c = x2a;
3624                         }
3625                         drawLine( x1, y1, x2c, y2, g );
3626                     }
3627                     else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
3628                         if ( y2 > y1 ) {
3629                             y2_r = y2 - ROUNDED_D;
3630                             if ( y2_r < y1 ) {
3631                                 y2_r = y1;
3632                             }
3633                             drawLine( x1, y1, x1, y2_r, g );
3634                         }
3635                         else {
3636                             y2_r = y2 + ROUNDED_D;
3637                             if ( y2_r > y1 ) {
3638                                 y2_r = y1;
3639                             }
3640                             drawLine( x1, y1, x1, y2_r, g );
3641                         }
3642                     }
3643                     else {
3644                         drawLine( x1, y1, x1, y2, g );
3645                     }
3646                 }
3647             }
3648             // draw the horizontal line
3649             if ( !to_graphics_file && !to_pdf
3650                     && ( ( y2 < ( getVisibleRect().getMinY() - 20 ) ) || ( y2 > ( getVisibleRect().getMaxY() + 20 ) ) ) ) {
3651                 return;
3652             }
3653             float x1_r = 0;
3654             if ( !getControlPanel().isWidthBranches() || ( PhylogenyMethods.getBranchWidthValue( node ) == 1 ) ) {
3655                 if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
3656                     x1_r = x1a + ROUNDED_D;
3657                     if ( x1_r < x2a ) {
3658                         drawLine( x1_r, y2, x2a, y2, g );
3659                     }
3660                 }
3661                 else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
3662                     final float x1c = x1a + EURO_D;
3663                     if ( x1c < x2a ) {
3664                         drawLine( x1c, y2, x2a, y2, g );
3665                     }
3666                 }
3667                 else {
3668                     drawLine( x1a, y2, x2a, y2, g );
3669                 }
3670             }
3671             else {
3672                 final double w = PhylogenyMethods.getBranchWidthValue( node );
3673                 if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
3674                     x1_r = x1a + ROUNDED_D;
3675                     if ( x1_r < x2a ) {
3676                         drawRectFilled( x1_r, y2 - ( w / 2 ), x2a - x1_r, w, g );
3677                     }
3678                 }
3679                 else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
3680                     final float x1c = x1a + EURO_D;
3681                     if ( x1c < x2a ) {
3682                         drawRectFilled( x1c, y2 - ( w / 2 ), x2a - x1c, w, g );
3683                     }
3684                 }
3685                 else {
3686                     drawRectFilled( x1a, y2 - ( w / 2 ), x2a - x1a, w, g );
3687                 }
3688             }
3689             if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) ) {
3690                 if ( x1_r > x2a ) {
3691                     x1_r = x2a;
3692                 }
3693                 if ( y2 > y2_r ) {
3694                     final double diff = y2 - y2_r;
3695                     _arc.setArc( x1, y2_r - diff, 2 * ( x1_r - x1 ), 2 * diff, 180, 90, Arc2D.OPEN );
3696                 }
3697                 else {
3698                     _arc.setArc( x1, y2, 2 * ( x1_r - x1 ), 2 * ( y2_r - y2 ), 90, 90, Arc2D.OPEN );
3699                 }
3700                 g.draw( _arc );
3701             }
3702         }
3703         if ( node.isExternal() ) {
3704             paintNodeBox( x2, y2, node, g, to_pdf, to_graphics_file );
3705         }
3706     }
3707
3708     final private double paintCirculars( final PhylogenyNode n,
3709                                          final Phylogeny phy,
3710                                          final float center_x,
3711                                          final float center_y,
3712                                          final double radius,
3713                                          final boolean radial_labels,
3714                                          final Graphics2D g,
3715                                          final boolean to_pdf,
3716                                          final boolean to_graphics_file ) {
3717         if ( n.isExternal() || n.isCollapse() ) { //~~circ collapse
3718             if ( !_urt_nodeid_angle_map.containsKey( n.getId() ) ) {
3719                 System.out.println( "no " + n + " =====>>>>>>> ERROR!" );//TODO
3720             }
3721             return _urt_nodeid_angle_map.get( n.getId() );
3722         }
3723         else {
3724             final List<PhylogenyNode> descs = n.getDescendants();
3725             double sum = 0;
3726             for( final PhylogenyNode desc : descs ) {
3727                 sum += paintCirculars( desc,
3728                                        phy,
3729                                        center_x,
3730                                        center_y,
3731                                        radius,
3732                                        radial_labels,
3733                                        g,
3734                                        to_pdf,
3735                                        to_graphics_file );
3736             }
3737             double r = 0;
3738             if ( !n.isRoot() ) {
3739                 r = 1 - ( ( ( double ) _circ_max_depth - n.calculateDepth() ) / _circ_max_depth );
3740             }
3741             final double theta = sum / descs.size();
3742             n.setXcoord( ( float ) ( center_x + ( r * radius * Math.cos( theta ) ) ) );
3743             n.setYcoord( ( float ) ( center_y + ( r * radius * Math.sin( theta ) ) ) );
3744             _urt_nodeid_angle_map.put( n.getId(), theta );
3745             for( final PhylogenyNode desc : descs ) {
3746                 paintBranchCircular( n, desc, g, radial_labels, to_pdf, to_graphics_file );
3747             }
3748             return theta;
3749         }
3750     }
3751
3752     final private void paintCircularsLite( final PhylogenyNode n,
3753                                            final Phylogeny phy,
3754                                            final int center_x,
3755                                            final int center_y,
3756                                            final int radius,
3757                                            final Graphics2D g ) {
3758         if ( n.isExternal() ) {
3759             return;
3760         }
3761         else {
3762             final List<PhylogenyNode> descs = n.getDescendants();
3763             for( final PhylogenyNode desc : descs ) {
3764                 paintCircularsLite( desc, phy, center_x, center_y, radius, g );
3765             }
3766             float r = 0;
3767             if ( !n.isRoot() ) {
3768                 r = 1 - ( ( ( float ) _circ_max_depth - n.calculateDepth() ) / _circ_max_depth );
3769             }
3770             final double theta = _urt_nodeid_angle_map.get( n.getId() );
3771             n.setXSecondary( ( float ) ( center_x + ( radius * r * Math.cos( theta ) ) ) );
3772             n.setYSecondary( ( float ) ( center_y + ( radius * r * Math.sin( theta ) ) ) );
3773             for( final PhylogenyNode desc : descs ) {
3774                 paintBranchCircularLite( n, desc, g );
3775             }
3776         }
3777     }
3778
3779     final private void paintCollapsedNode( final Graphics2D g,
3780                                            final PhylogenyNode node,
3781                                            final boolean to_graphics_file,
3782                                            final boolean to_pdf,
3783                                            final boolean is_in_found_nodes ) {
3784         Color c = null;
3785         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
3786             c = Color.BLACK;
3787         }
3788         else if ( is_in_found_nodes ) {
3789             c = getColorForFoundNode( node );
3790         }
3791         else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
3792             c = getTaxonomyBasedColor( node );
3793         }
3794         else if ( getOptions().isColorLabelsSameAsParentBranch() && getControlPanel().isColorBranches()
3795                 && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
3796             c = PhylogenyMethods.getBranchColorValue( node );
3797         }
3798         else {
3799             c = getTreeColorSet().getCollapseFillColor();
3800         }
3801         double d = node.getAllExternalDescendants().size();
3802         if ( d > 1000 ) {
3803             d = ( 3 * _y_distance ) / 3;
3804         }
3805         else {
3806             d = ( Math.log10( d ) * _y_distance ) / 2.5;
3807         }
3808         final int box_size = getOptions().getDefaultNodeShapeSize() + 1;
3809         if ( d < box_size ) {
3810             d = box_size;
3811         }
3812         final float xx = node.getXcoord() - ( 2 * box_size );
3813         final float xxx = xx > node.getParent().getXcoord() + 1 ? xx : node.getParent().getXcoord() + 1;
3814         _polygon.reset();
3815         _polygon.moveTo( xxx, node.getYcoord() );
3816         _polygon.lineTo( node.getXcoord() + 1, node.getYcoord() - d );
3817         _polygon.lineTo( node.getXcoord() + 1, node.getYcoord() + d );
3818         _polygon.closePath();
3819         if ( getOptions().getDefaultNodeFill() == NodeVisualization.NodeFill.SOLID ) {
3820             g.setColor( c );
3821             g.fill( _polygon );
3822         }
3823         else if ( getOptions().getDefaultNodeFill() == NodeVisualization.NodeFill.NONE ) {
3824             g.setColor( getBackground() );
3825             g.fill( _polygon );
3826             g.setColor( c );
3827             g.draw( _polygon );
3828         }
3829         else if ( getOptions().getDefaultNodeFill() == NodeFill.GRADIENT ) {
3830             g.setPaint( new GradientPaint( xxx, node.getYcoord(), getBackground(), node.getXcoord(), ( float ) ( node
3831                     .getYcoord() - d ), c, false ) );
3832             g.fill( _polygon );
3833             g.setPaint( c );
3834             g.draw( _polygon );
3835         }
3836         paintNodeData( g, node, to_graphics_file, to_pdf, is_in_found_nodes );
3837     }
3838
3839     final private void paintConfidenceValues( final Graphics2D g,
3840                                               final PhylogenyNode node,
3841                                               final boolean to_pdf,
3842                                               final boolean to_graphics_file ) {
3843         final List<Confidence> confidences = node.getBranchData().getConfidences();
3844         boolean not_first = false;
3845         Collections.sort( confidences );
3846         final StringBuilder sb = new StringBuilder();
3847         for( final Confidence confidence : confidences ) {
3848             final double value = confidence.getValue();
3849             if ( value != Confidence.CONFIDENCE_DEFAULT_VALUE ) {
3850                 if ( value < getOptions().getMinConfidenceValue() ) {
3851                     return;
3852                 }
3853                 if ( not_first ) {
3854                     sb.append( "/" );
3855                 }
3856                 else {
3857                     not_first = true;
3858                 }
3859                 sb.append( FORMATTER_CONFIDENCE.format( ForesterUtil.round( value, getOptions()
3860                         .getNumberOfDigitsAfterCommaForConfidenceValues() ) ) );
3861                 if ( getOptions().isShowConfidenceStddev() ) {
3862                     if ( confidence.getStandardDeviation() != Confidence.CONFIDENCE_DEFAULT_VALUE ) {
3863                         sb.append( "(" );
3864                         sb.append( FORMATTER_CONFIDENCE.format( ForesterUtil.round( confidence.getStandardDeviation(),
3865                                                                                     getOptions()
3866                                                                                             .getNumberOfDigitsAfterCommaForConfidenceValues() ) ) );
3867                         sb.append( ")" );
3868                     }
3869                 }
3870             }
3871         }
3872         if ( sb.length() > 0 ) {
3873             final double parent_x = node.getParent().getXcoord();
3874             double x = node.getXcoord();
3875             g.setFont( getTreeFontSet().getSmallFont() );
3876             if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
3877                 x += EURO_D;
3878             }
3879             else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
3880                 x += ROUNDED_D;
3881             }
3882             if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
3883                 g.setColor( Color.BLACK );
3884             }
3885             else {
3886                 g.setColor( getTreeColorSet().getConfidenceColor() );
3887             }
3888             final String conf_str = sb.toString();
3889             TreePanel
3890                     .drawString( conf_str,
3891                                  parent_x
3892                                          + ( ( x - parent_x - getTreeFontSet()._fm_small.stringWidth( conf_str ) ) / 2 ),
3893                                  ( node.getYcoord() + getTreeFontSet()._small_max_ascent ) - 1,
3894                                  g );
3895         }
3896     }
3897
3898     final private void paintFoundNode( final PhylogenyNode n, final double x, final double y, final Graphics2D g ) {
3899         final int box_size = getOptions().getDefaultNodeShapeSize();
3900         final double half_box_size = getOptions().getDefaultNodeShapeSize() / 2.0;
3901         g.setColor( getColorForFoundNode( n ) );
3902         //g.fillRect( x - half_box_size, y - half_box_size, box_size, box_size );
3903         //TODO check me
3904         //FIXME
3905         _rectangle.setRect( x - half_box_size, y - half_box_size, box_size, box_size );
3906         g.fill( _rectangle );
3907     }
3908
3909     final private void paintGainedAndLostCharacters( final Graphics2D g,
3910                                                      final PhylogenyNode node,
3911                                                      final String gained,
3912                                                      final String lost ) {
3913         if ( node.getParent() != null ) {
3914             final double parent_x = node.getParent().getXcoord();
3915             final double x = node.getXcoord();
3916             g.setFont( getTreeFontSet().getLargeFont() );
3917             g.setColor( getTreeColorSet().getGainedCharactersColor() );
3918             if ( Constants.SPECIAL_CUSTOM ) {
3919                 g.setColor( Color.BLUE );
3920             }
3921             TreePanel
3922                     .drawString( gained,
3923                                  parent_x + ( ( x - parent_x - getTreeFontSet()._fm_large.stringWidth( gained ) ) / 2 ),
3924                                  ( node.getYcoord() - getTreeFontSet()._fm_large.getMaxDescent() ),
3925                                  g );
3926             g.setColor( getTreeColorSet().getLostCharactersColor() );
3927             TreePanel.drawString( lost,
3928                                   parent_x + ( ( x - parent_x - getTreeFontSet()._fm_large.stringWidth( lost ) ) / 2 ),
3929                                   ( node.getYcoord() + getTreeFontSet()._fm_large.getMaxAscent() ),
3930                                   g );
3931         }
3932     }
3933
3934     /**
3935      * Draw a box at the indicated node.
3936      * 
3937      * @param x
3938      * @param y
3939      * @param node
3940      * @param g
3941      */
3942     final private void paintNodeBox( final double x,
3943                                      final double y,
3944                                      final PhylogenyNode node,
3945                                      final Graphics2D g,
3946                                      final boolean to_pdf,
3947                                      final boolean to_graphics_file ) {
3948         if ( node.isCollapse() ) {
3949             return;
3950         }
3951         // if this node should be highlighted, do so
3952         if ( ( _highlight_node == node ) && !to_pdf && !to_graphics_file ) {
3953             g.setColor( getTreeColorSet().getFoundColor0() );
3954             drawOval( x - 8, y - 8, 16, 16, g );
3955             drawOval( x - 9, y - 8, 17, 17, g );
3956             drawOval( x - 9, y - 9, 18, 18, g );
3957         }
3958         if ( isInFoundNodes( node ) || isInCurrentExternalNodes( node ) ) {
3959             paintFoundNode( node, x, y, g );
3960         }
3961         else {
3962             Color outline_color = null;
3963             if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
3964                 outline_color = Color.BLACK;
3965             }
3966             else if ( getControlPanel().isEvents() && TreePanelUtil.isHasAssignedEvent( node ) ) {
3967                 final Event event = node.getNodeData().getEvent();
3968                 if ( event.isDuplication() ) {
3969                     outline_color = getTreeColorSet().getDuplicationBoxColor();
3970                 }
3971                 else if ( event.isSpeciation() ) {
3972                     outline_color = getTreeColorSet().getSpecBoxColor();
3973                 }
3974                 else if ( event.isSpeciationOrDuplication() ) {
3975                     outline_color = getTreeColorSet().getDuplicationOrSpeciationColor();
3976                 }
3977             }
3978             else if ( getOptions().isTaxonomyColorizeNodeShapes() ) {
3979                 outline_color = getTaxonomyBasedColor( node );
3980             }
3981             else {
3982                 outline_color = getGraphicsForNodeBoxWithColorForParentBranch( node );
3983                 if ( to_pdf && ( outline_color == getTreeColorSet().getBranchColor() ) ) {
3984                     outline_color = getTreeColorSet().getBranchColorForPdf();
3985                 }
3986             }
3987             final int box_size = getOptions().getDefaultNodeShapeSize();
3988             final int half_box_size = box_size / 2;
3989             if ( ( getOptions().isShowDefaultNodeShapesExternal() && node.isExternal() )
3990                     || ( getOptions().isShowDefaultNodeShapesInternal() && node.isInternal() )
3991                     || ( getControlPanel().isEvents() && node.isHasAssignedEvent() ) ) {
3992                 if ( getOptions().getDefaultNodeShape() == NodeShape.CIRCLE ) {
3993                     if ( getOptions().getDefaultNodeFill() == NodeFill.GRADIENT ) {
3994                         drawOvalGradient( x - half_box_size,
3995                                           y - half_box_size,
3996                                           box_size,
3997                                           box_size,
3998                                           g,
3999                                           to_pdf ? Color.WHITE : outline_color,
4000                                           to_pdf ? outline_color : getBackground(),
4001                                           outline_color );
4002                     }
4003                     else if ( getOptions().getDefaultNodeFill() == NodeFill.NONE ) {
4004                         Color background = getBackground();
4005                         if ( to_pdf ) {
4006                             background = Color.WHITE;
4007                         }
4008                         drawOvalGradient( x - half_box_size,
4009                                           y - half_box_size,
4010                                           box_size,
4011                                           box_size,
4012                                           g,
4013                                           background,
4014                                           background,
4015                                           outline_color );
4016                     }
4017                     else if ( getOptions().getDefaultNodeFill() == NodeVisualization.NodeFill.SOLID ) {
4018                         g.setColor( outline_color );
4019                         drawOvalFilled( x - half_box_size, y - half_box_size, box_size, box_size, g );
4020                     }
4021                 }
4022                 else if ( getOptions().getDefaultNodeShape() == NodeVisualization.NodeShape.RECTANGLE ) {
4023                     if ( getOptions().getDefaultNodeFill() == NodeVisualization.NodeFill.GRADIENT ) {
4024                         drawRectGradient( x - half_box_size,
4025                                           y - half_box_size,
4026                                           box_size,
4027                                           box_size,
4028                                           g,
4029                                           to_pdf ? Color.WHITE : outline_color,
4030                                           to_pdf ? outline_color : getBackground(),
4031                                           outline_color );
4032                     }
4033                     else if ( getOptions().getDefaultNodeFill() == NodeVisualization.NodeFill.NONE ) {
4034                         Color background = getBackground();
4035                         if ( to_pdf ) {
4036                             background = Color.WHITE;
4037                         }
4038                         drawRectGradient( x - half_box_size,
4039                                           y - half_box_size,
4040                                           box_size,
4041                                           box_size,
4042                                           g,
4043                                           background,
4044                                           background,
4045                                           outline_color );
4046                     }
4047                     else if ( getOptions().getDefaultNodeFill() == NodeVisualization.NodeFill.SOLID ) {
4048                         g.setColor( outline_color );
4049                         drawRectFilled( x - half_box_size, y - half_box_size, box_size, box_size, g );
4050                     }
4051                 }
4052             }
4053         }
4054     }
4055
4056     final private void paintNodeData( final Graphics2D g,
4057                                       final PhylogenyNode node,
4058                                       final boolean to_graphics_file,
4059                                       final boolean to_pdf,
4060                                       final boolean is_in_found_nodes ) {
4061         if ( isNodeDataInvisible( node ) && !to_graphics_file && !to_pdf ) {
4062             return;
4063         }
4064         if ( getOptions().isShowBranchLengthValues()
4065                 && ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR )
4066                         || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) )
4067                 && ( !node.isRoot() ) && ( node.getDistanceToParent() != PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) ) {
4068             paintBranchLength( g, node, to_pdf, to_graphics_file );
4069         }
4070         if ( !getControlPanel().isShowInternalData() && !node.isExternal() && !node.isCollapse() ) {
4071             return;
4072         }
4073         _sb.setLength( 0 );
4074         int x = 0;
4075         final int half_box_size = getOptions().getDefaultNodeShapeSize() / 2;
4076         if ( getControlPanel().isShowTaxonomyImages()
4077                 && ( getImageMap() != null )
4078                 && !getImageMap().isEmpty()
4079                 && node.getNodeData().isHasTaxonomy()
4080                 && ( ( node.getNodeData().getTaxonomy().getUris() != null ) && !node.getNodeData().getTaxonomy()
4081                         .getUris().isEmpty() ) ) {
4082             x += drawTaxonomyImage( node.getXcoord() + 2 + half_box_size, node.getYcoord(), node, g );
4083         }
4084         if ( ( getControlPanel().isShowTaxonomyCode() || getControlPanel().isShowTaxonomyScientificNames() || getControlPanel()
4085                 .isShowTaxonomyCommonNames() ) && node.getNodeData().isHasTaxonomy() ) {
4086             x += paintTaxonomy( g, node, is_in_found_nodes, to_pdf, to_graphics_file, x );
4087         }
4088         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
4089             g.setColor( Color.BLACK );
4090         }
4091         else if ( is_in_found_nodes ) {
4092             g.setColor( getColorForFoundNode( node ) );
4093         }
4094         else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
4095             g.setColor( getTaxonomyBasedColor( node ) );
4096         }
4097         else if ( getControlPanel().isColorAccordingToAnnotation()
4098                 && ( node.getNodeData().isHasSequence() && ( node.getNodeData().getSequence().getAnnotations() != null ) && ( !node
4099                         .getNodeData().getSequence().getAnnotations().isEmpty() ) ) ) {
4100             g.setColor( calculateColorForAnnotation( node.getNodeData().getSequence().getAnnotations() ) );
4101         }
4102         else if ( getOptions().isColorLabelsSameAsParentBranch() && getControlPanel().isColorBranches()
4103                 && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
4104             g.setColor( PhylogenyMethods.getBranchColorValue( node ) );
4105         }
4106         else if ( to_pdf ) {
4107             g.setColor( Color.BLACK );
4108         }
4109         else {
4110             g.setColor( getTreeColorSet().getSequenceColor() );
4111         }
4112         if ( node.isCollapse() && ( ( !node.isRoot() && !node.getParent().isCollapse() ) || node.isRoot() ) ) {
4113             if ( _sb.length() > 0 ) {
4114                 _sb.setLength( 0 );
4115                 _sb.append( "(" );
4116                 _sb.append( node.getAllExternalDescendants().size() );
4117                 _sb.append( ")" );
4118             }
4119         }
4120         else {
4121             _sb.setLength( 0 );
4122         }
4123         if ( getControlPanel().isShowNodeNames() && ( node.getName().length() > 0 ) ) {
4124             if ( _sb.length() > 0 ) {
4125                 _sb.append( " " );
4126             }
4127             _sb.append( node.getName() );
4128         }
4129         if ( node.getNodeData().isHasSequence() ) {
4130             if ( getControlPanel().isShowSeqSymbols() && ( node.getNodeData().getSequence().getSymbol().length() > 0 ) ) {
4131                 if ( _sb.length() > 0 ) {
4132                     _sb.append( " " );
4133                 }
4134                 _sb.append( node.getNodeData().getSequence().getSymbol() );
4135             }
4136             if ( getControlPanel().isShowGeneNames() && ( node.getNodeData().getSequence().getGeneName().length() > 0 ) ) {
4137                 if ( _sb.length() > 0 ) {
4138                     _sb.append( " " );
4139                 }
4140                 _sb.append( node.getNodeData().getSequence().getGeneName() );
4141             }
4142             if ( getControlPanel().isShowSeqNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
4143                 if ( _sb.length() > 0 ) {
4144                     _sb.append( " " );
4145                 }
4146                 _sb.append( node.getNodeData().getSequence().getName() );
4147             }
4148             if ( getControlPanel().isShowSequenceAcc() && ( node.getNodeData().getSequence().getAccession() != null ) ) {
4149                 if ( _sb.length() > 0 ) {
4150                     _sb.append( " " );
4151                 }
4152                 if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().getSource() ) ) {
4153                     _sb.append( node.getNodeData().getSequence().getAccession().getSource() );
4154                     _sb.append( ":" );
4155                 }
4156                 _sb.append( node.getNodeData().getSequence().getAccession().getValue() );
4157             }
4158         }
4159         if ( getControlPanel().isShowProperties() && node.getNodeData().isHasProperties() ) {
4160             if ( _sb.length() > 0 ) {
4161                 _sb.append( " " );
4162             }
4163             _sb.append( propertiesToString( node ) );
4164         }
4165         g.setFont( getTreeFontSet().getLargeFont() );
4166         if ( is_in_found_nodes ) {
4167             g.setFont( getTreeFontSet().getLargeFont().deriveFont( Font.BOLD ) );
4168         }
4169         double down_shift_factor = 3.0;
4170         if ( !node.isExternal() && ( node.getNumberOfDescendants() == 1 ) ) {
4171             down_shift_factor = 1;
4172         }
4173         final double pos_x = node.getXcoord() + x + 2 + half_box_size;
4174         final double pos_y = ( node.getYcoord() + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ) );
4175         final String sb_str = _sb.toString();
4176         // GUILHEM_BEG ______________
4177         if ( _control_panel.isShowSequenceRelations() && node.getNodeData().isHasSequence()
4178                 && ( _query_sequence != null ) ) {
4179             int nodeTextBoundsWidth = 0;
4180             if ( sb_str.length() > 0 ) {
4181                 final Rectangle2D node_text_bounds = new TextLayout( sb_str, g.getFont(), _frc ).getBounds(); //would like to remove this 'new', but how...
4182                 nodeTextBoundsWidth = ( int ) node_text_bounds.getWidth();
4183             }
4184             if ( node.getNodeData().getSequence().equals( _query_sequence ) ) {
4185                 if ( nodeTextBoundsWidth > 0 ) { // invert font color and background color to show that this is the query sequence
4186                     g.fillRect( ( int ) pos_x - 1, ( int ) pos_y - 8, nodeTextBoundsWidth + 5, 11 );
4187                     g.setColor( getTreeColorSet().getBackgroundColor() );
4188                 }
4189             }
4190             else {
4191                 final List<SequenceRelation> seqRelations = node.getNodeData().getSequence().getSequenceRelations();
4192                 for( final SequenceRelation seqRelation : seqRelations ) {
4193                     final boolean fGotRelationWithQuery = ( seqRelation.getRef0().isEqual( _query_sequence ) || seqRelation
4194                             .getRef1().isEqual( _query_sequence ) )
4195                             && seqRelation.getType().equals( getControlPanel().getSequenceRelationTypeBox()
4196                                     .getSelectedItem() );
4197                     if ( fGotRelationWithQuery ) { // we will underline the text to show that this sequence is ortholog to the query
4198                         final double linePosX = node.getXcoord() + 2 + half_box_size;
4199                         final String sConfidence = ( !getControlPanel().isShowSequenceRelationConfidence() || ( seqRelation
4200                                 .getConfidence() == null ) ) ? null : " (" + seqRelation.getConfidence().getValue()
4201                                 + ")";
4202                         if ( sConfidence != null ) {
4203                             double confidenceX = pos_x;
4204                             if ( sb_str.length() > 0 ) {
4205                                 confidenceX += new TextLayout( sb_str, g.getFont(), _frc ).getBounds().getWidth()
4206                                         + CONFIDENCE_LEFT_MARGIN;
4207                             }
4208                             if ( confidenceX > linePosX ) { // let's only display confidence value if we are already displaying at least one of Prot/Gene Name and Taxonomy Code 
4209                                 final int confidenceWidth = ( int ) new TextLayout( sConfidence, g.getFont(), _frc )
4210                                         .getBounds().getWidth();
4211                                 TreePanel.drawString( sConfidence, confidenceX, pos_y, g );
4212                                 x += CONFIDENCE_LEFT_MARGIN + confidenceWidth;
4213                             }
4214                         }
4215                         if ( ( x + nodeTextBoundsWidth ) > 0 ) /* we only underline if there is something displayed */
4216                         {
4217                             if ( nodeTextBoundsWidth == 0 ) {
4218                                 nodeTextBoundsWidth -= 3; /* the gap between taxonomy code and node name should not be underlined if nothing comes after it */
4219                             }
4220                             else {
4221                                 nodeTextBoundsWidth += 2;
4222                             }
4223                             g.drawLine( ( int ) linePosX + 1, 3 + ( int ) pos_y, ( int ) linePosX + x
4224                                     + nodeTextBoundsWidth, 3 + ( int ) pos_y );
4225                             break;
4226                         }
4227                     }
4228                 }
4229             }
4230         }
4231         if ( sb_str.length() > 0 ) {
4232             TreePanel.drawString( sb_str, pos_x, pos_y, g );
4233         }
4234         // GUILHEM_END _____________
4235         // COMMENTED_OUT_BY_GUILHEM_BEG _______________
4236         // TODO FIXME need to check this one!
4237         //if ( _sb.length() > 0 ) {
4238         //    TreePanel.drawString( _sb.toString(), node.getXcoord() + x + 2 + TreePanel.HALF_BOX_SIZE, node.getYcoord()
4239         //            + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ), g );
4240         //}
4241         // COMMENTED_OUT_BY_GUILHEM_END ________________
4242         if ( getControlPanel().isShowAnnotation() && node.getNodeData().isHasSequence()
4243                 && ( node.getNodeData().getSequence().getAnnotations() != null )
4244                 && ( !node.getNodeData().getSequence().getAnnotations().isEmpty() ) ) {
4245             if ( _sb.length() > 0 ) {
4246                 x += getTreeFontSet()._fm_large.stringWidth( _sb.toString() ) + 5;
4247             }
4248             final SortedSet<Annotation> ann = node.getNodeData().getSequence().getAnnotations();
4249             if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
4250                 g.setColor( Color.BLACK );
4251             }
4252             else if ( getControlPanel().isColorAccordingToAnnotation() ) {
4253                 g.setColor( calculateColorForAnnotation( ann ) );
4254             }
4255             final String ann_str = TreePanelUtil.createAnnotationString( ann, getOptions().isShowAnnotationRefSource() );
4256             TreePanel.drawString( ann_str, node.getXcoord() + x + 3 + half_box_size, node.getYcoord()
4257                     + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ), g );
4258             _sb.setLength( 0 );
4259             _sb.append( ann_str );
4260         }
4261         if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR )
4262                 || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE )
4263                 || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) ) {
4264             if ( ( getControlPanel().isShowBinaryCharacters() || getControlPanel().isShowBinaryCharacterCounts() )
4265                     && node.getNodeData().isHasBinaryCharacters() ) {
4266                 if ( _sb.length() > 0 ) {
4267                     x += getTreeFontSet()._fm_large.stringWidth( _sb.toString() ) + 5;
4268                 }
4269                 if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
4270                     g.setColor( Color.BLACK );
4271                 }
4272                 else {
4273                     g.setColor( getTreeColorSet().getBinaryDomainCombinationsColor() );
4274                 }
4275                 if ( getControlPanel().isShowBinaryCharacters() ) {
4276                     TreePanel.drawString( node.getNodeData().getBinaryCharacters().getPresentCharactersAsStringBuffer()
4277                             .toString(), node.getXcoord() + x + 1 + half_box_size, node.getYcoord()
4278                             + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ), g );
4279                     paintGainedAndLostCharacters( g, node, node.getNodeData().getBinaryCharacters()
4280                             .getGainedCharactersAsStringBuffer().toString(), node.getNodeData().getBinaryCharacters()
4281                             .getLostCharactersAsStringBuffer().toString() );
4282                 }
4283                 else {
4284                     TreePanel.drawString( " " + node.getNodeData().getBinaryCharacters().getPresentCount(),
4285                                           node.getXcoord() + x + 4 + half_box_size,
4286                                           node.getYcoord()
4287                                                   + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ),
4288                                           g );
4289                     paintGainedAndLostCharacters( g, node, "+"
4290                             + node.getNodeData().getBinaryCharacters().getGainedCount(), "-"
4291                             + node.getNodeData().getBinaryCharacters().getLostCount() );
4292                 }
4293             }
4294         }
4295     }
4296
4297     final private void paintNodeDataUnrootedCirc( final Graphics2D g,
4298                                                   final PhylogenyNode node,
4299                                                   final boolean to_pdf,
4300                                                   final boolean to_graphics_file,
4301                                                   final boolean radial_labels,
4302                                                   final double ur_angle,
4303                                                   final boolean is_in_found_nodes ) {
4304         if ( isNodeDataInvisibleUnrootedCirc( node ) && !to_graphics_file && !to_pdf ) {
4305             return;
4306         }
4307         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
4308             g.setColor( Color.BLACK );
4309         }
4310         else if ( is_in_found_nodes ) {
4311             g.setColor( getColorForFoundNode( node ) );
4312         }
4313         else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
4314             g.setColor( getTaxonomyBasedColor( node ) );
4315         }
4316         else if ( getControlPanel().isColorAccordingToAnnotation()
4317                 && ( node.getNodeData().isHasSequence() && ( node.getNodeData().getSequence().getAnnotations() != null ) && ( !node
4318                         .getNodeData().getSequence().getAnnotations().isEmpty() ) ) ) {
4319             g.setColor( calculateColorForAnnotation( node.getNodeData().getSequence().getAnnotations() ) );
4320         }
4321         else {
4322             g.setColor( getTreeColorSet().getSequenceColor() );
4323         }
4324         _sb.setLength( 0 );
4325         _sb.append( " " );
4326         if ( node.getNodeData().isHasTaxonomy()
4327                 && ( getControlPanel().isShowTaxonomyCode() || getControlPanel().isShowTaxonomyScientificNames() || getControlPanel()
4328                         .isShowTaxonomyCommonNames() ) ) {
4329             final Taxonomy taxonomy = node.getNodeData().getTaxonomy();
4330             if ( _control_panel.isShowTaxonomyCode() && !ForesterUtil.isEmpty( taxonomy.getTaxonomyCode() ) ) {
4331                 _sb.append( taxonomy.getTaxonomyCode() );
4332                 _sb.append( " " );
4333             }
4334             if ( _control_panel.isShowTaxonomyScientificNames() && _control_panel.isShowTaxonomyCommonNames() ) {
4335                 if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() )
4336                         && !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
4337                     _sb.append( taxonomy.getScientificName() );
4338                     _sb.append( " (" );
4339                     _sb.append( taxonomy.getCommonName() );
4340                     _sb.append( ") " );
4341                 }
4342                 else if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() ) ) {
4343                     _sb.append( taxonomy.getScientificName() );
4344                     _sb.append( " " );
4345                 }
4346                 else if ( !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
4347                     _sb.append( taxonomy.getCommonName() );
4348                     _sb.append( " " );
4349                 }
4350             }
4351             else if ( _control_panel.isShowTaxonomyScientificNames() ) {
4352                 if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() ) ) {
4353                     _sb.append( taxonomy.getScientificName() );
4354                     _sb.append( " " );
4355                 }
4356             }
4357             else if ( _control_panel.isShowTaxonomyCommonNames() ) {
4358                 if ( !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
4359                     _sb.append( taxonomy.getCommonName() );
4360                     _sb.append( " " );
4361                 }
4362             }
4363         }
4364         if ( node.isCollapse() && ( ( !node.isRoot() && !node.getParent().isCollapse() ) || node.isRoot() ) ) {
4365             _sb.append( " [" );
4366             _sb.append( node.getAllExternalDescendants().size() );
4367             _sb.append( "]" );
4368         }
4369         if ( getControlPanel().isShowNodeNames() && ( node.getName().length() > 0 ) ) {
4370             if ( _sb.length() > 0 ) {
4371                 _sb.append( " " );
4372             }
4373             _sb.append( node.getName() );
4374         }
4375         if ( node.getNodeData().isHasSequence() ) {
4376             if ( getControlPanel().isShowSequenceAcc() && ( node.getNodeData().getSequence().getAccession() != null ) ) {
4377                 if ( _sb.length() > 0 ) {
4378                     _sb.append( " " );
4379                 }
4380                 if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().getSource() ) ) {
4381                     _sb.append( node.getNodeData().getSequence().getAccession().getSource() );
4382                     _sb.append( ":" );
4383                 }
4384                 _sb.append( node.getNodeData().getSequence().getAccession().getValue() );
4385             }
4386             if ( getControlPanel().isShowSeqNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
4387                 if ( _sb.length() > 0 ) {
4388                     _sb.append( " " );
4389                 }
4390                 _sb.append( node.getNodeData().getSequence().getName() );
4391             }
4392         }
4393         g.setFont( getTreeFontSet().getLargeFont() );
4394         if ( is_in_found_nodes ) {
4395             g.setFont( getTreeFontSet().getLargeFont().deriveFont( Font.BOLD ) );
4396         }
4397         if ( _sb.length() > 1 ) {
4398             final String sb_str = _sb.toString();
4399             double m = 0;
4400             if ( _graphics_type == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) {
4401                 m = _urt_nodeid_angle_map.get( node.getId() ) % TWO_PI;
4402             }
4403             else {
4404                 m = ( float ) ( ur_angle % TWO_PI );
4405             }
4406             _at = g.getTransform();
4407             boolean need_to_reset = false;
4408             final float x_coord = node.getXcoord();
4409             final float y_coord = node.getYcoord() + ( getTreeFontSet()._fm_large.getAscent() / 3.0f );
4410             if ( radial_labels ) {
4411                 need_to_reset = true;
4412                 boolean left = false;
4413                 if ( ( m > HALF_PI ) && ( m < ONEHALF_PI ) ) {
4414                     m -= PI;
4415                     left = true;
4416                 }
4417                 g.rotate( m, x_coord, node.getYcoord() );
4418                 if ( left ) {
4419                     g.translate( -( getTreeFontSet()._fm_large.getStringBounds( sb_str, g ).getWidth() ), 0 );
4420                 }
4421             }
4422             else {
4423                 if ( ( m > HALF_PI ) && ( m < ONEHALF_PI ) ) {
4424                     need_to_reset = true;
4425                     g.translate( -getTreeFontSet()._fm_large.getStringBounds( sb_str, g ).getWidth(), 0 );
4426                 }
4427             }
4428             TreePanel.drawString( sb_str, x_coord, y_coord, g );
4429             if ( need_to_reset ) {
4430                 g.setTransform( _at );
4431             }
4432         }
4433     }
4434
4435     final private void paintNodeLite( final Graphics2D g, final PhylogenyNode node ) {
4436         if ( node.isCollapse() ) {
4437             if ( !node.isRoot() && !node.getParent().isCollapse() ) {
4438                 paintCollapsedNode( g, node, false, false, false );
4439             }
4440             return;
4441         }
4442         if ( isInFoundNodes( node ) || isInCurrentExternalNodes( node ) ) {
4443             g.setColor( getColorForFoundNode( node ) );
4444             drawRectFilled( node.getXSecondary() - 1, node.getYSecondary() - 1, 3, 3, g );
4445         }
4446         float new_x = 0;
4447         if ( !node.isExternal() && !node.isCollapse() ) {
4448             boolean first_child = true;
4449             float y2 = 0.0f;
4450             final int parent_max_branch_to_leaf = getMaxBranchesToLeaf( node );
4451             for( int i = 0; i < node.getNumberOfDescendants(); ++i ) {
4452                 final PhylogenyNode child_node = node.getChildNode( i );
4453                 int factor_x;
4454                 if ( !isUniformBranchLengthsForCladogram() ) {
4455                     factor_x = node.getNumberOfExternalNodes() - child_node.getNumberOfExternalNodes();
4456                 }
4457                 else {
4458                     factor_x = parent_max_branch_to_leaf - getMaxBranchesToLeaf( child_node );
4459                 }
4460                 if ( first_child ) {
4461                     first_child = false;
4462                     y2 = node.getYSecondary()
4463                             - ( getOvYDistance() * ( node.getNumberOfExternalNodes() - child_node
4464                                     .getNumberOfExternalNodes() ) );
4465                 }
4466                 else {
4467                     y2 += getOvYDistance() * child_node.getNumberOfExternalNodes();
4468                 }
4469                 final float x2 = calculateOvBranchLengthToParent( child_node, factor_x );
4470                 new_x = x2 + node.getXSecondary();
4471                 final float diff_y = node.getYSecondary() - y2;
4472                 final float diff_x = node.getXSecondary() - new_x;
4473                 if ( ( diff_y > 2 ) || ( diff_y < -2 ) || ( diff_x > 2 ) || ( diff_x < -2 ) ) {
4474                     paintBranchLite( g, node.getXSecondary(), new_x, node.getYSecondary(), y2, child_node );
4475                 }
4476                 child_node.setXSecondary( new_x );
4477                 child_node.setYSecondary( y2 );
4478                 y2 += getOvYDistance() * child_node.getNumberOfExternalNodes();
4479             }
4480         }
4481     }
4482
4483     final private void paintNodeRectangular( final Graphics2D g,
4484                                              final PhylogenyNode node,
4485                                              final boolean to_pdf,
4486                                              final boolean dynamically_hide,
4487                                              final int dynamic_hiding_factor,
4488                                              final boolean to_graphics_file ) {
4489         final boolean is_in_found_nodes = isInFoundNodes( node ) || isInCurrentExternalNodes( node );
4490         if ( node.isCollapse() ) {
4491             if ( ( !node.isRoot() && !node.getParent().isCollapse() ) ) {
4492                 paintCollapsedNode( g, node, to_graphics_file, to_pdf, is_in_found_nodes );
4493             }
4494             return;
4495         }
4496         if ( node.isExternal() ) {
4497             ++_external_node_index;
4498         }
4499         // Confidence values
4500         if ( getControlPanel().isShowConfidenceValues()
4501                 && !node.isExternal()
4502                 && !node.isRoot()
4503                 && ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED )
4504                         || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ) || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) )
4505                 && node.getBranchData().isHasConfidences() ) {
4506             paintConfidenceValues( g, node, to_pdf, to_graphics_file );
4507         }
4508         // Draw a line to root:
4509         if ( node.isRoot() && _phylogeny.isRooted() ) {
4510             paintRootBranch( g, node.getXcoord(), node.getYcoord(), node, to_pdf, to_graphics_file );
4511         }
4512         float new_x = 0;
4513         float new_x_min = Float.MAX_VALUE;
4514         final boolean disallow_shortcutting = dynamic_hiding_factor < 40;
4515         float min_dist = 1.5f;
4516         if ( !disallow_shortcutting ) {
4517             //   System.out.println( dynamic_hiding_factor );
4518             if ( dynamic_hiding_factor > 4000 ) {
4519                 min_dist = 4;
4520             }
4521             else if ( dynamic_hiding_factor > 1000 ) {
4522                 min_dist = 3;
4523             }
4524             else if ( dynamic_hiding_factor > 100 ) {
4525                 min_dist = 2;
4526             }
4527         }
4528         if ( !node.isExternal() && !node.isCollapse() ) {
4529             boolean first_child = true;
4530             float y2 = 0.0f;
4531             final int parent_max_branch_to_leaf = getMaxBranchesToLeaf( node );
4532             for( int i = 0; i < node.getNumberOfDescendants(); ++i ) {
4533                 final PhylogenyNode child_node = node.getChildNode( i );
4534                 int factor_x;
4535                 if ( !isUniformBranchLengthsForCladogram() ) {
4536                     factor_x = node.getNumberOfExternalNodes() - child_node.getNumberOfExternalNodes();
4537                 }
4538                 else {
4539                     factor_x = parent_max_branch_to_leaf - getMaxBranchesToLeaf( child_node );
4540                 }
4541                 if ( first_child ) {
4542                     first_child = false;
4543                     y2 = node.getYcoord()
4544                             - ( _y_distance * ( node.getNumberOfExternalNodes() - child_node.getNumberOfExternalNodes() ) );
4545                 }
4546                 else {
4547                     y2 += _y_distance * child_node.getNumberOfExternalNodes();
4548                 }
4549                 final float x2 = calculateBranchLengthToParent( child_node, factor_x );
4550                 new_x = x2 + node.getXcoord();
4551                 if ( dynamically_hide && ( x2 < new_x_min ) ) {
4552                     new_x_min = x2;
4553                 }
4554                 final float diff_y = node.getYcoord() - y2;
4555                 final float diff_x = node.getXcoord() - new_x;
4556                 if ( disallow_shortcutting || ( diff_y > min_dist ) || ( diff_y < -min_dist ) || ( diff_x > min_dist )
4557                         || ( diff_x < -min_dist ) || to_graphics_file || to_pdf ) {
4558                     paintBranchRectangular( g,
4559                                             node.getXcoord(),
4560                                             new_x,
4561                                             node.getYcoord(),
4562                                             y2,
4563                                             child_node,
4564                                             to_pdf,
4565                                             to_graphics_file );
4566                 }
4567                 child_node.setXcoord( new_x );
4568                 child_node.setYcoord( y2 );
4569                 y2 += _y_distance * child_node.getNumberOfExternalNodes();
4570             }
4571             paintNodeBox( node.getXcoord(), node.getYcoord(), node, g, to_pdf, to_graphics_file );
4572         }
4573         if ( dynamically_hide
4574                 && !is_in_found_nodes
4575                 && ( ( node.isExternal() && ( ( _external_node_index % dynamic_hiding_factor ) != 1 ) ) || ( !node
4576                         .isExternal() && ( ( new_x_min < 20 ) || ( ( _y_distance * node.getNumberOfExternalNodes() ) < getTreeFontSet()._fm_large
4577                         .getHeight() ) ) ) ) ) {
4578             return;
4579         }
4580         paintNodeData( g, node, to_graphics_file, to_pdf, is_in_found_nodes );
4581         paintNodeWithRenderableData( g, node, to_graphics_file, to_pdf );
4582     }
4583
4584     final private void paintNodeWithRenderableData( final Graphics2D g,
4585                                                     final PhylogenyNode node,
4586                                                     final boolean to_graphics_file,
4587                                                     final boolean to_pdf ) {
4588         if ( isNodeDataInvisible( node ) && !to_graphics_file ) {
4589             return;
4590         }
4591         if ( ( !getControlPanel().isShowInternalData() && !node.isExternal() ) ) {
4592             return;
4593         }
4594         if ( getControlPanel().isShowDomainArchitectures() && node.getNodeData().isHasSequence()
4595                 && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) {
4596             RenderableDomainArchitecture rds = null;
4597             if ( node.getNodeData().getSequence().getDomainArchitecture() instanceof RenderableDomainArchitecture ) {
4598                 try {
4599                     rds = ( RenderableDomainArchitecture ) node.getNodeData().getSequence().getDomainArchitecture();
4600                 }
4601                 catch ( final ClassCastException cce ) {
4602                     cce.printStackTrace();
4603                 }
4604                 if ( rds != null ) {
4605                     rds.setRenderingHeight( 6 );
4606                     int x = 0;
4607                     if ( node.getNodeData().isHasTaxonomy() ) {
4608                         if ( getControlPanel().isShowTaxonomyCode()
4609                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) {
4610                             x += getTreeFontSet()._fm_large_italic.stringWidth( node.getNodeData().getTaxonomy()
4611                                     .getTaxonomyCode()
4612                                     + " " );
4613                         }
4614                         if ( getControlPanel().isShowTaxonomyScientificNames()
4615                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getScientificName() ) ) ) {
4616                             x += getTreeFontSet()._fm_large_italic.stringWidth( node.getNodeData().getTaxonomy()
4617                                     .getScientificName()
4618                                     + " " );
4619                         }
4620                         if ( getControlPanel().isShowTaxonomyCommonNames()
4621                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getCommonName() ) ) ) {
4622                             x += getTreeFontSet()._fm_large_italic.stringWidth( node.getNodeData().getTaxonomy()
4623                                     .getCommonName()
4624                                     + " " );
4625                         }
4626                     }
4627                     if ( node.getNodeData().isHasSequence() ) {
4628                         if ( getControlPanel().isShowSeqNames()
4629                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getName() ) ) ) {
4630                             x += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getName()
4631                                     + " " );
4632                         }
4633                         if ( getControlPanel().isShowSeqSymbols()
4634                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getSymbol() ) ) ) {
4635                             x += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getSymbol()
4636                                     + " " );
4637                         }
4638                         if ( getControlPanel().isShowGeneNames()
4639                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getGeneName() ) ) ) {
4640                             x += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getGeneName()
4641                                     + " " );
4642                         }
4643                         if ( getControlPanel().isShowSequenceAcc()
4644                                 && ( node.getNodeData().getSequence().getAccession() != null ) ) {
4645                             x += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence()
4646                                     .getAccession().toString()
4647                                     + " " );
4648                         }
4649                         if ( getControlPanel().isShowAnnotation()
4650                                 && ( node.getNodeData().getSequence().getAnnotations() != null )
4651                                 && ( !node.getNodeData().getSequence().getAnnotations().isEmpty() ) ) {
4652                             x += getTreeFontSet()._fm_large.stringWidth( TreePanelUtil.createAnnotationString( node
4653                                     .getNodeData().getSequence().getAnnotations(), getOptions()
4654                                     .isShowAnnotationRefSource() )
4655                                     + " " );
4656                         }
4657                     }
4658                     if ( getControlPanel().isShowNodeNames() && !ForesterUtil.isEmpty( node.getName() ) ) {
4659                         x += getTreeFontSet()._fm_large.stringWidth( node.getName() + " " );
4660                     }
4661                     rds.render( node.getXcoord() + x, node.getYcoord() - 3, g, this, to_pdf );
4662                 }
4663             }
4664         }
4665         //////////////
4666         if ( getControlPanel().isShowVectorData() && ( node.getNodeData().getVector() != null )
4667                 && ( node.getNodeData().getVector().size() > 0 ) && ( getStatisticsForExpressionValues() != null ) ) {
4668             final RenderableVector rv = RenderableVector.createInstance( node.getNodeData().getVector(),
4669                                                                          getStatisticsForExpressionValues(),
4670                                                                          getConfiguration() );
4671             if ( rv != null ) {
4672                 int x = 0;
4673                 PhylogenyNode my_node = node;
4674                 if ( !getControlPanel().isDrawPhylogram() ) {
4675                     my_node = getPhylogeny().getFirstExternalNode();
4676                 }
4677                 if ( getControlPanel().isShowTaxonomyCode() && ( PhylogenyMethods.getSpecies( my_node ).length() > 0 ) ) {
4678                     x += getTreeFontSet()._fm_large_italic.stringWidth( PhylogenyMethods.getSpecies( my_node ) + " " );
4679                 }
4680                 if ( getControlPanel().isShowNodeNames() && ( my_node.getName().length() > 0 ) ) {
4681                     x += getTreeFontSet()._fm_large.stringWidth( my_node.getName() + " " );
4682                 }
4683                 rv.render( my_node.getXcoord() + x, node.getYcoord() - 5, g, this, to_pdf );
4684             }
4685         }
4686         //////////////
4687     }
4688
4689     final private void paintOvRectangle( final Graphics2D g ) {
4690         final float w_ratio = ( ( float ) getWidth() ) / getVisibleRect().width;
4691         final float h_ratio = ( ( float ) getHeight() ) / getVisibleRect().height;
4692         final float x_ratio = ( ( float ) getWidth() ) / getVisibleRect().x;
4693         final float y_ratio = ( ( float ) getHeight() ) / getVisibleRect().y;
4694         final float width = getOvMaxWidth() / w_ratio;
4695         final float height = getOvMaxHeight() / h_ratio;
4696         final float x = getVisibleRect().x + getOvXPosition() + ( getOvMaxWidth() / x_ratio );
4697         final float y = getVisibleRect().y + getOvYPosition() + ( getOvMaxHeight() / y_ratio );
4698         g.setColor( getTreeColorSet().getFoundColor0() );
4699         getOvRectangle().setRect( x, y, width, height );
4700         final Stroke s = g.getStroke();
4701         g.setStroke( STROKE_1 );
4702         if ( ( width < 6 ) && ( height < 6 ) ) {
4703             drawRectFilled( x, y, 6, 6, g );
4704             getOvVirtualRectangle().setRect( x, y, 6, 6 );
4705         }
4706         else if ( width < 6 ) {
4707             drawRectFilled( x, y, 6, height, g );
4708             getOvVirtualRectangle().setRect( x, y, 6, height );
4709         }
4710         else if ( height < 6 ) {
4711             drawRectFilled( x, y, width, 6, g );
4712             getOvVirtualRectangle().setRect( x, y, width, 6 );
4713         }
4714         else {
4715             drawRect( x, y, width, height, g );
4716             if ( isInOvRect() ) {
4717                 drawRect( x + 1, y + 1, width - 2, height - 2, g );
4718             }
4719             getOvVirtualRectangle().setRect( x, y, width, height );
4720         }
4721         g.setStroke( s );
4722     }
4723
4724     final private void paintPhylogenyLite( final Graphics2D g ) {
4725         _phylogeny
4726                 .getRoot()
4727                 .setXSecondary( ( float ) ( getVisibleRect().x + getOvXPosition() + ( MOVE / ( getVisibleRect().width / getOvRectangle()
4728                         .getWidth() ) ) ) );
4729         _phylogeny.getRoot().setYSecondary( ( getVisibleRect().y + getOvYStart() ) );
4730         final Stroke s = g.getStroke();
4731         g.setStroke( STROKE_05 );
4732         for( final PhylogenyNode element : _nodes_in_preorder ) {
4733             paintNodeLite( g, element );
4734         }
4735         g.setStroke( s );
4736         paintOvRectangle( g );
4737     }
4738
4739     /**
4740      * Paint the root branch. (Differs from others because it will always be a
4741      * single horizontal line).
4742      * @param to_graphics_file 
4743      * 
4744      * @return new x1 value
4745      */
4746     final private void paintRootBranch( final Graphics2D g,
4747                                         final float x1,
4748                                         final float y1,
4749                                         final PhylogenyNode root,
4750                                         final boolean to_pdf,
4751                                         final boolean to_graphics_file ) {
4752         assignGraphicsForBranchWithColorForParentBranch( root, false, g, to_pdf, to_graphics_file );
4753         float d = getXdistance();
4754         if ( getControlPanel().isDrawPhylogram() && ( root.getDistanceToParent() > 0.0 ) ) {
4755             d = ( float ) ( getXcorrectionFactor() * root.getDistanceToParent() );
4756         }
4757         if ( d < MIN_ROOT_LENGTH ) {
4758             d = MIN_ROOT_LENGTH;
4759         }
4760         if ( !getControlPanel().isWidthBranches() || ( PhylogenyMethods.getBranchWidthValue( root ) == 1 ) ) {
4761             drawLine( x1 - d, root.getYcoord(), x1, root.getYcoord(), g );
4762         }
4763         else {
4764             final double w = PhylogenyMethods.getBranchWidthValue( root );
4765             drawRectFilled( x1 - d, root.getYcoord() - ( w / 2 ), d, w, g );
4766         }
4767         paintNodeBox( x1, root.getYcoord(), root, g, to_pdf, to_graphics_file );
4768     }
4769
4770     final private void paintScale( final Graphics2D g,
4771                                    int x1,
4772                                    int y1,
4773                                    final boolean to_pdf,
4774                                    final boolean to_graphics_file ) {
4775         x1 += MOVE;
4776         final double x2 = x1 + ( getScaleDistance() * getXcorrectionFactor() );
4777         y1 -= 12;
4778         final int y2 = y1 - 8;
4779         final int y3 = y1 - 4;
4780         g.setFont( getTreeFontSet().getSmallFont() );
4781         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
4782             g.setColor( Color.BLACK );
4783         }
4784         else {
4785             g.setColor( getTreeColorSet().getBranchLengthColor() );
4786         }
4787         final Stroke s = g.getStroke();
4788         g.setStroke( STROKE_1 );
4789         drawLine( x1, y1, x1, y2, g );
4790         drawLine( x2, y1, x2, y2, g );
4791         drawLine( x1, y3, x2, y3, g );
4792         if ( getScaleLabel() != null ) {
4793             g.drawString( getScaleLabel(), ( x1 + 2 ), y3 - 2 );
4794         }
4795         g.setStroke( s );
4796     }
4797
4798     final private int paintTaxonomy( final Graphics2D g,
4799                                      final PhylogenyNode node,
4800                                      final boolean is_in_found_nodes,
4801                                      final boolean to_pdf,
4802                                      final boolean to_graphics_file,
4803                                      final double x_shift ) {
4804         final Taxonomy taxonomy = node.getNodeData().getTaxonomy();
4805         g.setFont( getTreeFontSet().getLargeItalicFont() );
4806         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
4807             g.setColor( Color.BLACK );
4808         }
4809         else if ( is_in_found_nodes ) {
4810             g.setFont( getTreeFontSet().getLargeItalicFont().deriveFont( TreeFontSet.BOLD_AND_ITALIC ) );
4811             g.setColor( getColorForFoundNode( node ) );
4812         }
4813         else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
4814             g.setColor( getTaxonomyBasedColor( node ) );
4815         }
4816         else if ( getOptions().isColorLabelsSameAsParentBranch() && getControlPanel().isColorBranches()
4817                 && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
4818             g.setColor( PhylogenyMethods.getBranchColorValue( node ) );
4819         }
4820         else if ( to_pdf ) {
4821             g.setColor( Color.BLACK );
4822         }
4823         else {
4824             g.setColor( getTreeColorSet().getTaxonomyColor() );
4825         }
4826         final double start_x = node.getXcoord() + 3 + ( getOptions().getDefaultNodeShapeSize() / 2 ) + x_shift;
4827         final double start_y = node.getYcoord()
4828                 + ( getTreeFontSet()._fm_large.getAscent() / ( node.getNumberOfDescendants() == 1 ? 1 : 3.0 ) );
4829         _sb.setLength( 0 );
4830         if ( _control_panel.isShowTaxonomyCode() && !ForesterUtil.isEmpty( taxonomy.getTaxonomyCode() ) ) {
4831             _sb.append( taxonomy.getTaxonomyCode() );
4832             _sb.append( " " );
4833         }
4834         if ( _control_panel.isShowTaxonomyScientificNames() && _control_panel.isShowTaxonomyCommonNames() ) {
4835             if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() )
4836                     && !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
4837                 if ( getOptions().isAbbreviateScientificTaxonNames()
4838                         && ( taxonomy.getScientificName().indexOf( ' ' ) > 0 ) ) {
4839                     abbreviateScientificName( taxonomy.getScientificName() );
4840                 }
4841                 else {
4842                     _sb.append( taxonomy.getScientificName() );
4843                 }
4844                 _sb.append( " (" );
4845                 _sb.append( taxonomy.getCommonName() );
4846                 _sb.append( ") " );
4847             }
4848             else if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() ) ) {
4849                 if ( getOptions().isAbbreviateScientificTaxonNames()
4850                         && ( taxonomy.getScientificName().indexOf( ' ' ) > 0 ) ) {
4851                     abbreviateScientificName( taxonomy.getScientificName() );
4852                 }
4853                 else {
4854                     _sb.append( taxonomy.getScientificName() );
4855                 }
4856                 _sb.append( " " );
4857             }
4858             else if ( !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
4859                 _sb.append( taxonomy.getCommonName() );
4860                 _sb.append( " " );
4861             }
4862         }
4863         else if ( _control_panel.isShowTaxonomyScientificNames() ) {
4864             if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() ) ) {
4865                 if ( getOptions().isAbbreviateScientificTaxonNames()
4866                         && ( taxonomy.getScientificName().indexOf( ' ' ) > 0 ) ) {
4867                     abbreviateScientificName( taxonomy.getScientificName() );
4868                 }
4869                 else {
4870                     _sb.append( taxonomy.getScientificName() );
4871                 }
4872                 _sb.append( " " );
4873             }
4874         }
4875         else if ( _control_panel.isShowTaxonomyCommonNames() ) {
4876             if ( !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
4877                 _sb.append( taxonomy.getCommonName() );
4878                 _sb.append( " " );
4879             }
4880         }
4881         final String label = _sb.toString();
4882         /* GUILHEM_BEG */
4883         if ( _control_panel.isShowSequenceRelations() && ( label.length() > 0 )
4884                 && ( node.getNodeData().isHasSequence() ) && node.getNodeData().getSequence().equals( _query_sequence ) ) {
4885             // invert font color and background color to show that this is the query sequence
4886             final Rectangle2D nodeTextBounds = new TextLayout( label, g.getFont(), new FontRenderContext( null,
4887                                                                                                           false,
4888                                                                                                           false ) )
4889                     .getBounds();
4890             g.fillRect( ( int ) start_x - 1, ( int ) start_y - 8, ( int ) nodeTextBounds.getWidth() + 4, 11 );
4891             g.setColor( getTreeColorSet().getBackgroundColor() );
4892         }
4893         /* GUILHEM_END */
4894         TreePanel.drawString( label, start_x, start_y, g );
4895         if ( is_in_found_nodes ) {
4896             return getTreeFontSet()._fm_large_italic_bold.stringWidth( label );
4897         }
4898         else {
4899             return getTreeFontSet()._fm_large_italic.stringWidth( label );
4900         }
4901     }
4902
4903     final private void paintUnrooted( final PhylogenyNode n,
4904                                       final double low_angle,
4905                                       final double high_angle,
4906                                       final boolean radial_labels,
4907                                       final Graphics2D g,
4908                                       final boolean to_pdf,
4909                                       final boolean to_graphics_file ) {
4910         if ( n.isRoot() ) {
4911             n.setXcoord( getWidth() / 2 );
4912             n.setYcoord( getHeight() / 2 );
4913         }
4914         if ( n.isExternal() ) {
4915             paintNodeDataUnrootedCirc( g,
4916                                        n,
4917                                        to_pdf,
4918                                        to_graphics_file,
4919                                        radial_labels,
4920                                        ( high_angle + low_angle ) / 2,
4921                                        isInFoundNodes( n ) || isInCurrentExternalNodes( n ) );
4922             return;
4923         }
4924         final float num_enclosed = n.getNumberOfExternalNodes();
4925         final float x = n.getXcoord();
4926         final float y = n.getYcoord();
4927         double current_angle = low_angle;
4928         // final boolean n_below = n.getYcoord() < getVisibleRect().getMinY() - 20;
4929         // final boolean n_above = n.getYcoord() > getVisibleRect().getMaxY() + 20;
4930         // final boolean n_left = n.getXcoord() < getVisibleRect().getMinX() - 20;
4931         // final boolean n_right = n.getXcoord() > getVisibleRect().getMaxX() + 20;
4932         for( int i = 0; i < n.getNumberOfDescendants(); ++i ) {
4933             final PhylogenyNode desc = n.getChildNode( i );
4934             ///  if ( ( ( n_below ) & ( desc.getYcoord() < getVisibleRect().getMinY() - 20 ) )
4935             //          || ( ( n_above ) & ( desc.getYcoord() > getVisibleRect().getMaxY() + 20 ) )
4936             //         || ( ( n_left ) & ( desc.getXcoord() < getVisibleRect().getMinX() - 20 ) )
4937             //          || ( ( n_right ) & ( desc.getXcoord() > getVisibleRect().getMaxX() + 20 ) ) ) {
4938             //     continue;
4939             // }
4940             //if ( ( desc.getYcoord() > n.getYcoord() ) && ( n.getYcoord() > getVisibleRect().getMaxY() - 20 ) ) {
4941             //    continue;
4942             //}
4943             //if ( ( desc.getYcoord() < n.getYcoord() ) && ( n.getYcoord() < getVisibleRect().getMinY() + 20 ) ) {
4944             //    continue;
4945             // }
4946             final int desc_num_enclosed = desc.getNumberOfExternalNodes();
4947             final double arc_size = ( desc_num_enclosed / num_enclosed ) * ( high_angle - low_angle );
4948             float length;
4949             if ( isPhyHasBranchLengths() && getControlPanel().isDrawPhylogram() ) {
4950                 if ( desc.getDistanceToParent() < 0 ) {
4951                     length = 0;
4952                 }
4953                 else {
4954                     length = ( float ) ( desc.getDistanceToParent() * getUrtFactor() );
4955                 }
4956             }
4957             else {
4958                 length = getUrtFactor();
4959             }
4960             final double mid_angle = current_angle + ( arc_size / 2 );
4961             final float new_x = ( float ) ( x + ( Math.cos( mid_angle ) * length ) );
4962             final float new_y = ( float ) ( y + ( Math.sin( mid_angle ) * length ) );
4963             desc.setXcoord( new_x );
4964             desc.setYcoord( new_y );
4965             paintUnrooted( desc, current_angle, current_angle + arc_size, radial_labels, g, to_pdf, to_graphics_file );
4966             current_angle += arc_size;
4967             assignGraphicsForBranchWithColorForParentBranch( desc, false, g, to_pdf, to_graphics_file );
4968             drawLine( x, y, new_x, new_y, g );
4969             paintNodeBox( new_x, new_y, desc, g, to_pdf, to_graphics_file );
4970         }
4971         if ( n.isRoot() ) {
4972             paintNodeBox( n.getXcoord(), n.getYcoord(), n, g, to_pdf, to_graphics_file );
4973         }
4974     }
4975
4976     final private void paintUnrootedLite( final PhylogenyNode n,
4977                                           final double low_angle,
4978                                           final double high_angle,
4979                                           final Graphics2D g,
4980                                           final float urt_ov_factor ) {
4981         if ( n.isRoot() ) {
4982             final int x_pos = ( int ) ( getVisibleRect().x + getOvXPosition() + ( getOvMaxWidth() / 2 ) );
4983             final int y_pos = ( int ) ( getVisibleRect().y + getOvYPosition() + ( getOvMaxHeight() / 2 ) );
4984             n.setXSecondary( x_pos );
4985             n.setYSecondary( y_pos );
4986         }
4987         if ( n.isExternal() ) {
4988             return;
4989         }
4990         final float num_enclosed = n.getNumberOfExternalNodes();
4991         final float x = n.getXSecondary();
4992         final float y = n.getYSecondary();
4993         double current_angle = low_angle;
4994         for( int i = 0; i < n.getNumberOfDescendants(); ++i ) {
4995             final PhylogenyNode desc = n.getChildNode( i );
4996             final int desc_num_enclosed = desc.getNumberOfExternalNodes();
4997             final double arc_size = ( desc_num_enclosed / num_enclosed ) * ( high_angle - low_angle );
4998             float length;
4999             if ( isPhyHasBranchLengths() && getControlPanel().isDrawPhylogram() ) {
5000                 if ( desc.getDistanceToParent() < 0 ) {
5001                     length = 0;
5002                 }
5003                 else {
5004                     length = ( float ) ( desc.getDistanceToParent() * urt_ov_factor );
5005                 }
5006             }
5007             else {
5008                 length = urt_ov_factor;
5009             }
5010             final double mid_angle = current_angle + ( arc_size / 2 );
5011             final float new_x = ( float ) ( x + ( Math.cos( mid_angle ) * length ) );
5012             final float new_y = ( float ) ( y + ( Math.sin( mid_angle ) * length ) );
5013             desc.setXSecondary( new_x );
5014             desc.setYSecondary( new_y );
5015             if ( isInFoundNodes( desc ) || isInCurrentExternalNodes( desc ) ) {
5016                 g.setColor( getColorForFoundNode( desc ) );
5017                 drawRectFilled( desc.getXSecondary() - 1, desc.getYSecondary() - 1, 3, 3, g );
5018                 g.setColor( getTreeColorSet().getOvColor() );
5019             }
5020             paintUnrootedLite( desc, current_angle, current_angle + arc_size, g, urt_ov_factor );
5021             current_angle += arc_size;
5022             drawLine( x, y, new_x, new_y, g );
5023         }
5024     }
5025
5026     final private void pasteSubtree( final PhylogenyNode node ) {
5027         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
5028             errorMessageNoCutCopyPasteInUnrootedDisplay();
5029             return;
5030         }
5031         if ( ( getCutOrCopiedTree() == null ) || getCutOrCopiedTree().isEmpty() ) {
5032             JOptionPane.showMessageDialog( this,
5033                                            "No tree in buffer (need to copy or cut a subtree first)",
5034                                            "Attempt to paste with empty buffer",
5035                                            JOptionPane.ERROR_MESSAGE );
5036             return;
5037         }
5038         final String label = createASimpleTextRepresentationOfANode( getCutOrCopiedTree().getRoot() );
5039         final Object[] options = { "As sibling", "As descendant", "Cancel" };
5040         final int r = JOptionPane.showOptionDialog( this,
5041                                                     "How to paste subtree" + label + "?",
5042                                                     "Paste Subtree",
5043                                                     JOptionPane.CLOSED_OPTION,
5044                                                     JOptionPane.QUESTION_MESSAGE,
5045                                                     null,
5046                                                     options,
5047                                                     options[ 2 ] );
5048         boolean paste_as_sibling = true;
5049         if ( r == 1 ) {
5050             paste_as_sibling = false;
5051         }
5052         else if ( r != 0 ) {
5053             return;
5054         }
5055         final Phylogeny buffer_phy = getCutOrCopiedTree().copy();
5056         buffer_phy.setAllNodesToNotCollapse();
5057         PhylogenyMethods.preOrderReId( buffer_phy );
5058         buffer_phy.setRooted( true );
5059         boolean need_to_show_whole = false;
5060         if ( paste_as_sibling ) {
5061             if ( node.isRoot() ) {
5062                 JOptionPane.showMessageDialog( this,
5063                                                "Cannot paste sibling to root",
5064                                                "Attempt to paste sibling to root",
5065                                                JOptionPane.ERROR_MESSAGE );
5066                 return;
5067             }
5068             buffer_phy.addAsSibling( node );
5069         }
5070         else {
5071             if ( ( node.getNumberOfExternalNodes() == 1 ) && node.isRoot() ) {
5072                 need_to_show_whole = true;
5073                 _phylogeny = buffer_phy;
5074             }
5075             else {
5076                 buffer_phy.addAsChild( node );
5077             }
5078         }
5079         if ( getCopiedAndPastedNodes() == null ) {
5080             setCopiedAndPastedNodes( new HashSet<Long>() );
5081         }
5082         final List<PhylogenyNode> nodes = PhylogenyMethods.obtainAllNodesAsList( buffer_phy );
5083         final Set<Long> node_ids = new HashSet<Long>( nodes.size() );
5084         for( final PhylogenyNode n : nodes ) {
5085             node_ids.add( n.getId() );
5086         }
5087         node_ids.add( node.getId() );
5088         getCopiedAndPastedNodes().addAll( node_ids );
5089         setNodeInPreorderToNull();
5090         _phylogeny.externalNodesHaveChanged();
5091         _phylogeny.clearHashIdToNodeMap();
5092         _phylogeny.recalculateNumberOfExternalDescendants( true );
5093         resetNodeIdToDistToLeafMap();
5094         setEdited( true );
5095         if ( need_to_show_whole ) {
5096             getControlPanel().showWhole();
5097         }
5098         repaint();
5099     }
5100
5101     private final StringBuffer propertiesToString( final PhylogenyNode node ) {
5102         final PropertiesMap properties = node.getNodeData().getProperties();
5103         final StringBuffer sb = new StringBuffer();
5104         boolean first = true;
5105         for( final String ref : properties.getPropertyRefs() ) {
5106             if ( first ) {
5107                 first = false;
5108             }
5109             else {
5110                 sb.append( " " );
5111             }
5112             final Property p = properties.getProperty( ref );
5113             sb.append( TreePanelUtil.getPartAfterColon( p.getRef() ) );
5114             sb.append( "=" );
5115             sb.append( p.getValue() );
5116             if ( !ForesterUtil.isEmpty( p.getUnit() ) ) {
5117                 sb.append( TreePanelUtil.getPartAfterColon( p.getUnit() ) );
5118             }
5119         }
5120         return sb;
5121     }
5122
5123     final private void setCopiedAndPastedNodes( final Set<Long> nodeIds ) {
5124         getMainPanel().setCopiedAndPastedNodes( nodeIds );
5125     }
5126
5127     final private void setCutOrCopiedTree( final Phylogeny cut_or_copied_tree ) {
5128         getMainPanel().setCutOrCopiedTree( cut_or_copied_tree );
5129     }
5130
5131     final private void setInOv( final boolean in_ov ) {
5132         _in_ov = in_ov;
5133     }
5134
5135     final private void setOvMaxHeight( final float ov_max_height ) {
5136         _ov_max_height = ov_max_height;
5137     }
5138
5139     final private void setOvMaxWidth( final float ov_max_width ) {
5140         _ov_max_width = ov_max_width;
5141     }
5142
5143     final private void setOvXcorrectionFactor( final float f ) {
5144         _ov_x_correction_factor = f;
5145     }
5146
5147     final private void setOvXDistance( final float ov_x_distance ) {
5148         _ov_x_distance = ov_x_distance;
5149     }
5150
5151     final private void setOvXPosition( final int ov_x_position ) {
5152         _ov_x_position = ov_x_position;
5153     }
5154
5155     final private void setOvYDistance( final float ov_y_distance ) {
5156         _ov_y_distance = ov_y_distance;
5157     }
5158
5159     final private void setOvYPosition( final int ov_y_position ) {
5160         _ov_y_position = ov_y_position;
5161     }
5162
5163     final private void setOvYStart( final int ov_y_start ) {
5164         _ov_y_start = ov_y_start;
5165     }
5166
5167     final private void setScaleDistance( final double scale_distance ) {
5168         _scale_distance = scale_distance;
5169     }
5170
5171     final private void setScaleLabel( final String scale_label ) {
5172         _scale_label = scale_label;
5173     }
5174
5175     private final void setupStroke( final Graphics2D g ) {
5176         if ( getYdistance() < 0.001 ) {
5177             g.setStroke( STROKE_005 );
5178         }
5179         else if ( getYdistance() < 0.01 ) {
5180             g.setStroke( STROKE_01 );
5181         }
5182         else if ( getYdistance() < 0.5 ) {
5183             g.setStroke( STROKE_025 );
5184         }
5185         else if ( getYdistance() < 1 ) {
5186             g.setStroke( STROKE_05 );
5187         }
5188         else if ( getYdistance() < 2 ) {
5189             g.setStroke( STROKE_075 );
5190         }
5191         else if ( getYdistance() < 20 ) {
5192             g.setStroke( STROKE_1 );
5193         }
5194         else {
5195             g.setStroke( STROKE_2 );
5196         }
5197     }
5198
5199     final private void setUpUrtFactor() {
5200         final int d = getVisibleRect().width < getVisibleRect().height ? getVisibleRect().width
5201                 : getVisibleRect().height;
5202         if ( isPhyHasBranchLengths() && getControlPanel().isDrawPhylogram() ) {
5203             setUrtFactor( ( float ) ( d / ( 2 * getMaxDistanceToRoot() ) ) );
5204         }
5205         else {
5206             final int max_depth = _circ_max_depth;
5207             if ( max_depth > 0 ) {
5208                 setUrtFactor( d / ( 2 * max_depth ) );
5209             }
5210             else {
5211                 setUrtFactor( d / 2 );
5212             }
5213         }
5214         setUrtFactorOv( getUrtFactor() );
5215     }
5216
5217     final private void setUrtFactor( final float urt_factor ) {
5218         _urt_factor = urt_factor;
5219     }
5220
5221     final private void setUrtFactorOv( final float urt_factor_ov ) {
5222         _urt_factor_ov = urt_factor_ov;
5223     }
5224
5225     private void showExtDescNodeData( final PhylogenyNode node ) {
5226         final List<String> data = new ArrayList<String>();
5227         final List<PhylogenyNode> nodes = node.getAllExternalDescendants();
5228         if ( ( getFoundNodes0() != null ) && !getFoundNodes0().isEmpty() ) {
5229             for( final PhylogenyNode n : getFoundNodes0AsListOfPhylogenyNodes() ) {
5230                 if ( !nodes.contains( n ) ) {
5231                     nodes.add( n );
5232                 }
5233             }
5234         }
5235         if ( ( getFoundNodes1() != null ) && !getFoundNodes1().isEmpty() ) {
5236             for( final PhylogenyNode n : getFoundNodes1AsListOfPhylogenyNodes() ) {
5237                 if ( !nodes.contains( n ) ) {
5238                     nodes.add( n );
5239                 }
5240             }
5241         }
5242         for( final PhylogenyNode n : nodes ) {
5243             switch ( getOptions().getExtDescNodeDataToReturn() ) {
5244                 case NODE_NAME:
5245                     if ( !ForesterUtil.isEmpty( n.getName() ) ) {
5246                         data.add( n.getName() );
5247                     }
5248                     break;
5249                 case SEQUENCE_NAME:
5250                     if ( n.getNodeData().isHasSequence()
5251                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getName() ) ) {
5252                         data.add( n.getNodeData().getSequence().getName() );
5253                     }
5254                     break;
5255                 case GENE_NAME:
5256                     if ( n.getNodeData().isHasSequence()
5257                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getGeneName() ) ) {
5258                         data.add( n.getNodeData().getSequence().getGeneName() );
5259                     }
5260                     break;
5261                 case SEQUENCE_SYMBOL:
5262                     if ( n.getNodeData().isHasSequence()
5263                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getSymbol() ) ) {
5264                         data.add( n.getNodeData().getSequence().getSymbol() );
5265                     }
5266                     break;
5267                 case SEQUENCE_MOL_SEQ:
5268                     if ( n.getNodeData().isHasSequence()
5269                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getMolecularSequence() ) ) {
5270                         data.add( n.getNodeData().getSequence().getMolecularSequence() );
5271                     }
5272                     break;
5273                 case SEQUENCE_MOL_SEQ_FASTA:
5274                     final StringBuilder sb = new StringBuilder();
5275                     if ( n.getNodeData().isHasSequence()
5276                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getMolecularSequence() ) ) {
5277                         final StringBuilder ann = new StringBuilder();
5278                         if ( !ForesterUtil.isEmpty( n.getName() ) ) {
5279                             ann.append( n.getName() );
5280                             ann.append( "|" );
5281                         }
5282                         if ( !ForesterUtil.isEmpty( n.getNodeData().getSequence().getSymbol() ) ) {
5283                             ann.append( "SYM=" );
5284                             ann.append( n.getNodeData().getSequence().getSymbol() );
5285                             ann.append( "|" );
5286                         }
5287                         if ( !ForesterUtil.isEmpty( n.getNodeData().getSequence().getName() ) ) {
5288                             ann.append( "NAME=" );
5289                             ann.append( n.getNodeData().getSequence().getName() );
5290                             ann.append( "|" );
5291                         }
5292                         if ( !ForesterUtil.isEmpty( n.getNodeData().getSequence().getGeneName() ) ) {
5293                             ann.append( "GN=" );
5294                             ann.append( n.getNodeData().getSequence().getGeneName() );
5295                             ann.append( "|" );
5296                         }
5297                         if ( n.getNodeData().getSequence().getAccession() != null ) {
5298                             ann.append( "ACC=" );
5299                             ann.append( n.getNodeData().getSequence().getAccession().asText() );
5300                             ann.append( "|" );
5301                         }
5302                         if ( n.getNodeData().isHasTaxonomy() ) {
5303                             if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
5304                                 ann.append( "TAXID=" );
5305                                 ann.append( n.getNodeData().getTaxonomy().getTaxonomyCode() );
5306                                 ann.append( "|" );
5307                             }
5308                             if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getScientificName() ) ) {
5309                                 ann.append( "SN=" );
5310                                 ann.append( n.getNodeData().getTaxonomy().getScientificName() );
5311                                 ann.append( "|" );
5312                             }
5313                         }
5314                         String ann_str;
5315                         if ( ann.charAt( ann.length() - 1 ) == '|' ) {
5316                             ann_str = ann.substring( 0, ann.length() - 1 );
5317                         }
5318                         else {
5319                             ann_str = ann.toString();
5320                         }
5321                         sb.append( SequenceWriter.toFasta( ann_str, n.getNodeData().getSequence()
5322                                 .getMolecularSequence(), 60 ) );
5323                         data.add( sb.toString() );
5324                     }
5325                     break;
5326                 case SEQUENCE_ACC:
5327                     if ( n.getNodeData().isHasSequence() && ( n.getNodeData().getSequence().getAccession() != null )
5328                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getAccession().toString() ) ) {
5329                         data.add( n.getNodeData().getSequence().getAccession().toString() );
5330                     }
5331                     break;
5332                 case TAXONOMY_SCIENTIFIC_NAME:
5333                     if ( n.getNodeData().isHasTaxonomy()
5334                             && !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getScientificName() ) ) {
5335                         data.add( n.getNodeData().getTaxonomy().getScientificName() );
5336                     }
5337                     break;
5338                 case TAXONOMY_COMM0N_NAME:
5339                     if ( n.getNodeData().isHasTaxonomy()
5340                             && !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getCommonName() ) ) {
5341                         data.add( n.getNodeData().getTaxonomy().getCommonName() );
5342                     }
5343                     break;
5344                 case TAXONOMY_CODE:
5345                     if ( n.getNodeData().isHasTaxonomy()
5346                             && !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
5347                         data.add( n.getNodeData().getTaxonomy().getTaxonomyCode() );
5348                     }
5349                     break;
5350                 case UNKNOWN:
5351                     TreePanelUtil.showExtDescNodeDataUserSelectedHelper( getControlPanel(), n, data );
5352                     break;
5353                 default:
5354                     throw new IllegalArgumentException( "unknown data element: "
5355                             + getOptions().getExtDescNodeDataToReturn() );
5356             }
5357         } // for loop
5358         final StringBuilder sb = new StringBuilder();
5359         final int size = TreePanelUtil.makeSB( data, getOptions(), sb );
5360         if ( ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.CONSOLE )
5361                 || ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.BUFFER_ONLY ) ) {
5362             if ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.CONSOLE ) {
5363                 System.out.println( sb );
5364             }
5365             if ( sb.length() < 1 ) {
5366                 clearCurrentExternalNodesDataBuffer();
5367             }
5368             else {
5369                 setCurrentExternalNodesDataBuffer( sb );
5370             }
5371         }
5372         else if ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.WINODW ) {
5373             if ( sb.length() < 1 ) {
5374                 TreePanelUtil.showInformationMessage( this, "No Appropriate Data (" + obtainTitleForExtDescNodeData()
5375                         + ")", "Descendants of selected node do not contain selected data" );
5376                 clearCurrentExternalNodesDataBuffer();
5377             }
5378             else {
5379                 setCurrentExternalNodesDataBuffer( sb );
5380                 String title;
5381                 if ( ( getFoundNodes0() != null ) && !getFoundNodes0().isEmpty() ) {
5382                     title = ( getOptions().getExtDescNodeDataToReturn() == NODE_DATA.UNKNOWN ? "Data"
5383                             : obtainTitleForExtDescNodeData() )
5384                             + " for "
5385                             + data.size()
5386                             + " nodes, unique entries: "
5387                             + size;
5388                 }
5389                 else {
5390                     title = ( getOptions().getExtDescNodeDataToReturn() == NODE_DATA.UNKNOWN ? "Data"
5391                             : obtainTitleForExtDescNodeData() )
5392                             + " for "
5393                             + data.size()
5394                             + "/"
5395                             + node.getNumberOfExternalNodes()
5396                             + " external descendats of node "
5397                             + node
5398                             + ", unique entries: " + size;
5399                 }
5400                 final String s = sb.toString().trim();
5401                 if ( getMainPanel().getMainFrame() == null ) {
5402                     // Must be "E" applet version.
5403                     final ArchaeopteryxE ae = ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet();
5404                     ae.showTextFrame( s, title );
5405                 }
5406                 else {
5407                     getMainPanel().getMainFrame().showTextFrame( s, title );
5408                 }
5409             }
5410         }
5411     }
5412
5413     final private void showNodeDataPopup( final MouseEvent e, final PhylogenyNode node ) {
5414         try {
5415             if ( ( node.getName().length() > 0 )
5416                     || ( node.getNodeData().isHasTaxonomy() && !TreePanelUtil.isTaxonomyEmpty( node.getNodeData()
5417                             .getTaxonomy() ) )
5418                     || ( node.getNodeData().isHasSequence() && !TreePanelUtil.isSequenceEmpty( node.getNodeData()
5419                             .getSequence() ) ) || ( node.getNodeData().isHasDate() )
5420                     || ( node.getNodeData().isHasDistribution() ) || node.getBranchData().isHasConfidences() ) {
5421                 _popup_buffer.setLength( 0 );
5422                 short lines = 0;
5423                 if ( node.getName().length() > 0 ) {
5424                     lines++;
5425                     _popup_buffer.append( node.getName() );
5426                 }
5427                 if ( node.getNodeData().isHasTaxonomy()
5428                         && !TreePanelUtil.isTaxonomyEmpty( node.getNodeData().getTaxonomy() ) ) {
5429                     lines++;
5430                     boolean enc_data = false;
5431                     final Taxonomy tax = node.getNodeData().getTaxonomy();
5432                     if ( _popup_buffer.length() > 0 ) {
5433                         _popup_buffer.append( "\n" );
5434                     }
5435                     if ( !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
5436                         _popup_buffer.append( "[" );
5437                         _popup_buffer.append( tax.getTaxonomyCode() );
5438                         _popup_buffer.append( "]" );
5439                         enc_data = true;
5440                     }
5441                     if ( !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
5442                         if ( enc_data ) {
5443                             _popup_buffer.append( " " );
5444                         }
5445                         _popup_buffer.append( tax.getScientificName() );
5446                         enc_data = true;
5447                     }
5448                     if ( !ForesterUtil.isEmpty( tax.getCommonName() ) ) {
5449                         if ( enc_data ) {
5450                             _popup_buffer.append( " (" );
5451                         }
5452                         else {
5453                             _popup_buffer.append( "(" );
5454                         }
5455                         _popup_buffer.append( tax.getCommonName() );
5456                         _popup_buffer.append( ")" );
5457                         enc_data = true;
5458                     }
5459                     if ( !ForesterUtil.isEmpty( tax.getAuthority() ) ) {
5460                         if ( enc_data ) {
5461                             _popup_buffer.append( " (" );
5462                         }
5463                         else {
5464                             _popup_buffer.append( "(" );
5465                         }
5466                         _popup_buffer.append( tax.getAuthority() );
5467                         _popup_buffer.append( ")" );
5468                         enc_data = true;
5469                     }
5470                     if ( !ForesterUtil.isEmpty( tax.getRank() ) ) {
5471                         if ( enc_data ) {
5472                             _popup_buffer.append( " [" );
5473                         }
5474                         else {
5475                             _popup_buffer.append( "[" );
5476                         }
5477                         _popup_buffer.append( tax.getRank() );
5478                         _popup_buffer.append( "]" );
5479                         enc_data = true;
5480                     }
5481                     if ( tax.getSynonyms().size() > 0 ) {
5482                         if ( enc_data ) {
5483                             _popup_buffer.append( " " );
5484                         }
5485                         _popup_buffer.append( "[" );
5486                         int counter = 1;
5487                         for( final String syn : tax.getSynonyms() ) {
5488                             if ( !ForesterUtil.isEmpty( syn ) ) {
5489                                 enc_data = true;
5490                                 _popup_buffer.append( syn );
5491                                 if ( counter < tax.getSynonyms().size() ) {
5492                                     _popup_buffer.append( ", " );
5493                                 }
5494                             }
5495                             counter++;
5496                         }
5497                         _popup_buffer.append( "]" );
5498                     }
5499                     if ( !enc_data ) {
5500                         if ( ( tax.getIdentifier() != null ) && !ForesterUtil.isEmpty( tax.getIdentifier().getValue() ) ) {
5501                             if ( !ForesterUtil.isEmpty( tax.getIdentifier().getProvider() ) ) {
5502                                 _popup_buffer.append( "[" );
5503                                 _popup_buffer.append( tax.getIdentifier().getProvider() );
5504                                 _popup_buffer.append( "] " );
5505                             }
5506                             _popup_buffer.append( tax.getIdentifier().getValue() );
5507                         }
5508                     }
5509                 }
5510                 if ( node.getNodeData().isHasSequence()
5511                         && !TreePanelUtil.isSequenceEmpty( node.getNodeData().getSequence() ) ) {
5512                     lines++;
5513                     boolean enc_data = false;
5514                     if ( _popup_buffer.length() > 0 ) {
5515                         _popup_buffer.append( "\n" );
5516                     }
5517                     final Sequence seq = node.getNodeData().getSequence();
5518                     if ( seq.getAccession() != null ) {
5519                         _popup_buffer.append( "[" );
5520                         if ( !ForesterUtil.isEmpty( seq.getAccession().getSource() ) ) {
5521                             _popup_buffer.append( seq.getAccession().getSource() );
5522                             _popup_buffer.append( ":" );
5523                         }
5524                         _popup_buffer.append( seq.getAccession().getValue() );
5525                         _popup_buffer.append( "]" );
5526                         enc_data = true;
5527                     }
5528                     if ( !ForesterUtil.isEmpty( seq.getSymbol() ) ) {
5529                         if ( enc_data ) {
5530                             _popup_buffer.append( " [" );
5531                         }
5532                         else {
5533                             _popup_buffer.append( "[" );
5534                         }
5535                         _popup_buffer.append( seq.getSymbol() );
5536                         _popup_buffer.append( "]" );
5537                         enc_data = true;
5538                     }
5539                     if ( !ForesterUtil.isEmpty( seq.getGeneName() ) ) {
5540                         if ( enc_data ) {
5541                             _popup_buffer.append( " [" );
5542                         }
5543                         else {
5544                             _popup_buffer.append( "[" );
5545                         }
5546                         _popup_buffer.append( seq.getGeneName() );
5547                         _popup_buffer.append( "]" );
5548                         enc_data = true;
5549                     }
5550                     if ( !ForesterUtil.isEmpty( seq.getName() ) ) {
5551                         if ( enc_data ) {
5552                             _popup_buffer.append( " " );
5553                         }
5554                         _popup_buffer.append( seq.getName() );
5555                     }
5556                 }
5557                 if ( node.getNodeData().isHasDate() ) {
5558                     lines++;
5559                     if ( _popup_buffer.length() > 0 ) {
5560                         _popup_buffer.append( "\n" );
5561                     }
5562                     _popup_buffer.append( node.getNodeData().getDate().asSimpleText() );
5563                 }
5564                 if ( node.getNodeData().isHasDistribution() ) {
5565                     lines++;
5566                     if ( _popup_buffer.length() > 0 ) {
5567                         _popup_buffer.append( "\n" );
5568                     }
5569                     _popup_buffer.append( node.getNodeData().getDistribution().asSimpleText() );
5570                 }
5571                 if ( node.getBranchData().isHasConfidences() ) {
5572                     final List<Confidence> confs = node.getBranchData().getConfidences();
5573                     for( final Confidence confidence : confs ) {
5574                         lines++;
5575                         if ( _popup_buffer.length() > 0 ) {
5576                             _popup_buffer.append( "\n" );
5577                         }
5578                         if ( !ForesterUtil.isEmpty( confidence.getType() ) ) {
5579                             _popup_buffer.append( "[" );
5580                             _popup_buffer.append( confidence.getType() );
5581                             _popup_buffer.append( "] " );
5582                         }
5583                         _popup_buffer
5584                                 .append( FORMATTER_CONFIDENCE.format( ForesterUtil.round( confidence.getValue(),
5585                                                                                           getOptions()
5586                                                                                                   .getNumberOfDigitsAfterCommaForConfidenceValues() ) ) );
5587                         if ( confidence.getStandardDeviation() != Confidence.CONFIDENCE_DEFAULT_VALUE ) {
5588                             _popup_buffer.append( " (sd=" );
5589                             _popup_buffer.append( FORMATTER_CONFIDENCE.format( ForesterUtil.round( confidence
5590                                     .getStandardDeviation(), getOptions()
5591                                     .getNumberOfDigitsAfterCommaForConfidenceValues() ) ) );
5592                             _popup_buffer.append( ")" );
5593                         }
5594                     }
5595                 }
5596                 if ( node.getNodeData().isHasProperties() ) {
5597                     final PropertiesMap properties = node.getNodeData().getProperties();
5598                     for( final String ref : properties.getPropertyRefs() ) {
5599                         _popup_buffer.append( "\n" );
5600                         final Property p = properties.getProperty( ref );
5601                         _popup_buffer.append( TreePanelUtil.getPartAfterColon( p.getRef() ) );
5602                         _popup_buffer.append( "=" );
5603                         _popup_buffer.append( p.getValue() );
5604                         if ( !ForesterUtil.isEmpty( p.getUnit() ) ) {
5605                             _popup_buffer.append( TreePanelUtil.getPartAfterColon( p.getUnit() ) );
5606                         }
5607                     }
5608                 }
5609                 if ( _popup_buffer.length() > 0 ) {
5610                     if ( !getConfiguration().isUseNativeUI() ) {
5611                         _rollover_popup
5612                                 .setBorder( BorderFactory.createLineBorder( getTreeColorSet().getBranchColor() ) );
5613                         _rollover_popup.setBackground( getTreeColorSet().getBackgroundColor() );
5614                         if ( isInFoundNodes0( node ) && !isInFoundNodes1( node ) ) {
5615                             _rollover_popup.setForeground( getTreeColorSet().getFoundColor0() );
5616                         }
5617                         else if ( !isInFoundNodes0( node ) && isInFoundNodes1( node ) ) {
5618                             _rollover_popup.setForeground( getTreeColorSet().getFoundColor1() );
5619                         }
5620                         else if ( isInFoundNodes0( node ) && isInFoundNodes1( node ) ) {
5621                             _rollover_popup.setForeground( getTreeColorSet().getFoundColor0and1() );
5622                         }
5623                         else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
5624                             _rollover_popup.setForeground( getTaxonomyBasedColor( node ) );
5625                         }
5626                         else {
5627                             _rollover_popup.setForeground( getTreeColorSet().getSequenceColor() );
5628                         }
5629                     }
5630                     else {
5631                         _rollover_popup.setBorder( BorderFactory.createLineBorder( Color.BLACK ) );
5632                     }
5633                     _rollover_popup.setText( _popup_buffer.toString() );
5634                     _node_desc_popup = PopupFactory.getSharedInstance().getPopup( null,
5635                                                                                   _rollover_popup,
5636                                                                                   e.getLocationOnScreen().x + 10,
5637                                                                                   e.getLocationOnScreen().y
5638                                                                                           - ( lines * 20 ) );
5639                     _node_desc_popup.show();
5640                 }
5641             }
5642         }
5643         catch ( final Exception ex ) {
5644             // Do nothing.
5645         }
5646     }
5647
5648     final private void showNodeEditFrame( final PhylogenyNode n ) {
5649         if ( _node_frame_index < TreePanel.MAX_NODE_FRAMES ) {
5650             // pop up edit box for single node
5651             _node_frames[ _node_frame_index ] = new NodeFrame( n, _phylogeny, this, _node_frame_index, "" );
5652             _node_frame_index++;
5653         }
5654         else {
5655             JOptionPane.showMessageDialog( this, "too many node windows are open" );
5656         }
5657     }
5658
5659     final private void showNodeFrame( final PhylogenyNode n ) {
5660         if ( _node_frame_index < TreePanel.MAX_NODE_FRAMES ) {
5661             // pop up edit box for single node
5662             _node_frames[ _node_frame_index ] = new NodeFrame( n, _phylogeny, this, _node_frame_index );
5663             _node_frame_index++;
5664         }
5665         else {
5666             JOptionPane.showMessageDialog( this, "too many node windows are open" );
5667         }
5668     }
5669
5670     final private void switchDisplaygetPhylogenyGraphicsType() {
5671         switch ( getPhylogenyGraphicsType() ) {
5672             case RECTANGULAR:
5673                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE );
5674                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE );
5675                 break;
5676             case EURO_STYLE:
5677                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.ROUNDED );
5678                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.ROUNDED );
5679                 break;
5680             case ROUNDED:
5681                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CURVED );
5682                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CURVED );
5683                 break;
5684             case CURVED:
5685                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR );
5686                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR );
5687                 break;
5688             case TRIANGULAR:
5689                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CONVEX );
5690                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CONVEX );
5691                 break;
5692             case CONVEX:
5693                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
5694                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
5695                 break;
5696             case UNROOTED:
5697                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CIRCULAR );
5698                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CIRCULAR );
5699                 break;
5700             case CIRCULAR:
5701                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
5702                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
5703                 break;
5704             default:
5705                 throw new RuntimeException( "unkwnown display type: " + getPhylogenyGraphicsType() );
5706         }
5707         if ( getControlPanel().getDynamicallyHideData() != null ) {
5708             if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
5709                 getControlPanel().getDynamicallyHideData().setEnabled( false );
5710             }
5711             else {
5712                 getControlPanel().getDynamicallyHideData().setEnabled( true );
5713             }
5714         }
5715         if ( isPhyHasBranchLengths() && ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
5716             getControlPanel().setDrawPhylogramEnabled( true );
5717         }
5718         else {
5719             getControlPanel().setDrawPhylogramEnabled( false );
5720         }
5721         if ( getMainPanel().getMainFrame() == null ) {
5722             // Must be "E" applet version.
5723             ( ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet() )
5724                     .setSelectedTypeInTypeMenu( getPhylogenyGraphicsType() );
5725         }
5726         else {
5727             getMainPanel().getMainFrame().setSelectedTypeInTypeMenu( getPhylogenyGraphicsType() );
5728         }
5729     }
5730
5731     final private static void drawString( final String str, final double x, final double y, final Graphics2D g ) {
5732         g.drawString( str, ( int ) ( x + 0.5 ), ( int ) ( y + 0.5 ) );
5733     }
5734
5735     final private static boolean plusPressed( final int key_code ) {
5736         return ( ( key_code == KeyEvent.VK_ADD ) || ( key_code == KeyEvent.VK_PLUS )
5737                 || ( key_code == KeyEvent.VK_EQUALS ) || ( key_code == KeyEvent.VK_SEMICOLON ) || ( key_code == KeyEvent.VK_1 ) );
5738     }
5739
5740     final private class SubtreeColorizationActionListener implements ActionListener {
5741
5742         List<PhylogenyNode> _additional_nodes = null;
5743         JColorChooser       _chooser          = null;
5744         PhylogenyNode       _node             = null;
5745
5746         SubtreeColorizationActionListener( final JColorChooser chooser, final PhylogenyNode node ) {
5747             _chooser = chooser;
5748             _node = node;
5749         }
5750
5751         SubtreeColorizationActionListener( final JColorChooser chooser,
5752                                            final PhylogenyNode node,
5753                                            final List<PhylogenyNode> additional_nodes ) {
5754             _chooser = chooser;
5755             _node = node;
5756             _additional_nodes = additional_nodes;
5757         }
5758
5759         @Override
5760         public void actionPerformed( final ActionEvent e ) {
5761             final Color c = _chooser.getColor();
5762             if ( c != null ) {
5763                 colorizeSubtree( c, _node, _additional_nodes );
5764             }
5765         }
5766     }
5767 }