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