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