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