inprogress
[jalview.git] / forester / java / src / org / forester / archaeopteryx / TreePanel.java
1 // $Id:
2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
4 //
5 // Copyright (C) 2008-2009 Christian M. Zmasek
6 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
7 // All rights reserved
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 //
23 // Contact: phylosoft @ gmail . com
24 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
25
26 package org.forester.archaeopteryx;
27
28 import java.awt.BasicStroke;
29 import java.awt.Color;
30 import java.awt.Cursor;
31 import java.awt.Dimension;
32 import java.awt.Font;
33 import java.awt.GradientPaint;
34 import java.awt.Graphics;
35 import java.awt.Graphics2D;
36 import java.awt.Point;
37 import java.awt.Rectangle;
38 import java.awt.RenderingHints;
39 import java.awt.Stroke;
40 import java.awt.event.ActionEvent;
41 import java.awt.event.ActionListener;
42 import java.awt.event.FocusAdapter;
43 import java.awt.event.FocusEvent;
44 import java.awt.event.InputEvent;
45 import java.awt.event.KeyAdapter;
46 import java.awt.event.KeyEvent;
47 import java.awt.event.MouseEvent;
48 import java.awt.event.MouseWheelEvent;
49 import java.awt.event.MouseWheelListener;
50 import java.awt.font.FontRenderContext;
51 import java.awt.font.TextLayout;
52 import java.awt.geom.AffineTransform;
53 import java.awt.geom.Arc2D;
54 import java.awt.geom.CubicCurve2D;
55 import java.awt.geom.Ellipse2D;
56 import java.awt.geom.Line2D;
57 import java.awt.geom.Path2D;
58 import java.awt.geom.QuadCurve2D;
59 import java.awt.geom.Rectangle2D;
60 import java.awt.image.BufferedImage;
61 import java.awt.print.PageFormat;
62 import java.awt.print.Printable;
63 import java.awt.print.PrinterException;
64 import java.io.File;
65 import java.io.IOException;
66 import java.io.UnsupportedEncodingException;
67 import java.net.URI;
68 import java.net.URISyntaxException;
69 import java.net.URLEncoder;
70 import java.text.DecimalFormat;
71 import java.text.DecimalFormatSymbols;
72 import java.text.NumberFormat;
73 import java.util.ArrayList;
74 import java.util.Collections;
75 import java.util.HashMap;
76 import java.util.HashSet;
77 import java.util.Hashtable;
78 import java.util.List;
79 import java.util.Set;
80 import java.util.SortedSet;
81
82 import javax.swing.BorderFactory;
83 import javax.swing.JApplet;
84 import javax.swing.JColorChooser;
85 import javax.swing.JDialog;
86 import javax.swing.JMenuItem;
87 import javax.swing.JOptionPane;
88 import javax.swing.JPanel;
89 import javax.swing.JPopupMenu;
90 import javax.swing.JTextArea;
91 import javax.swing.Popup;
92 import javax.swing.PopupFactory;
93
94 import org.forester.archaeopteryx.Configuration.EXT_NODE_DATA_RETURN_ON;
95 import org.forester.archaeopteryx.ControlPanel.NodeClickAction;
96 import org.forester.archaeopteryx.Options.CLADOGRAM_TYPE;
97 import org.forester.archaeopteryx.Options.NODE_LABEL_DIRECTION;
98 import org.forester.archaeopteryx.Options.PHYLOGENY_GRAPHICS_TYPE;
99 import org.forester.archaeopteryx.phylogeny.data.RenderableDomainArchitecture;
100 import org.forester.archaeopteryx.phylogeny.data.RenderableVector;
101 import org.forester.archaeopteryx.tools.Blast;
102 import org.forester.archaeopteryx.tools.ImageLoader;
103 import org.forester.io.parsers.phyloxml.PhyloXmlUtil;
104 import org.forester.io.writers.SequenceWriter;
105 import org.forester.phylogeny.Phylogeny;
106 import org.forester.phylogeny.PhylogenyMethods;
107 import org.forester.phylogeny.PhylogenyMethods.DESCENDANT_SORT_PRIORITY;
108 import org.forester.phylogeny.PhylogenyNode;
109 import org.forester.phylogeny.data.Accession;
110 import org.forester.phylogeny.data.Annotation;
111 import org.forester.phylogeny.data.BranchColor;
112 import org.forester.phylogeny.data.Confidence;
113 import org.forester.phylogeny.data.Event;
114 import org.forester.phylogeny.data.NodeData.NODE_DATA;
115 import org.forester.phylogeny.data.NodeVisualization;
116 import org.forester.phylogeny.data.NodeVisualization.NodeFill;
117 import org.forester.phylogeny.data.NodeVisualization.NodeShape;
118 import org.forester.phylogeny.data.PhylogenyDataUtil;
119 import org.forester.phylogeny.data.PropertiesMap;
120 import org.forester.phylogeny.data.Property;
121 import org.forester.phylogeny.data.Sequence;
122 import org.forester.phylogeny.data.SequenceRelation;
123 import org.forester.phylogeny.data.Taxonomy;
124 import org.forester.phylogeny.data.Uri;
125 import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
126 import org.forester.phylogeny.iterators.PreorderTreeIterator;
127 import org.forester.util.BasicDescriptiveStatistics;
128 import org.forester.util.DescriptiveStatistics;
129 import org.forester.util.ForesterConstants;
130 import org.forester.util.ForesterUtil;
131 import org.forester.util.SequenceAccessionTools;
132 import org.forester.util.TaxonomyUtil;
133
134 public final class TreePanel extends JPanel implements ActionListener, MouseWheelListener, Printable {
135
136     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 colorSubtree( final PhylogenyNode node ) {
2434         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
2435             JOptionPane.showMessageDialog( this,
2436                                            "Cannot colorize subtree in unrooted display type",
2437                                            "Attempt to colorize subtree in unrooted display",
2438                                            JOptionPane.WARNING_MESSAGE );
2439             return;
2440         }
2441         _color_chooser.setPreviewPanel( new JPanel() );
2442         SubtreeColorizationActionListener al;
2443         if ( ( getFoundNodes0() != null ) && !getFoundNodes0().isEmpty() ) {
2444             final List<PhylogenyNode> additional_nodes = getFoundNodes0AsListOfPhylogenyNodes();
2445             al = new SubtreeColorizationActionListener( _color_chooser, node, additional_nodes );
2446         }
2447         else {
2448             al = new SubtreeColorizationActionListener( _color_chooser, node );
2449         }
2450         final JDialog dialog = JColorChooser
2451                 .createDialog( this, "Subtree colorization", true, _color_chooser, al, null );
2452         dialog.setVisible( true );
2453     }
2454
2455     final private void copySubtree( final PhylogenyNode node ) {
2456         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
2457             errorMessageNoCutCopyPasteInUnrootedDisplay();
2458             return;
2459         }
2460         setNodeInPreorderToNull();
2461         setCutOrCopiedTree( _phylogeny.copy( node ) );
2462         final List<PhylogenyNode> nodes = PhylogenyMethods.getAllDescendants( node );
2463         final Set<Long> node_ids = new HashSet<Long>( nodes.size() );
2464         for( final PhylogenyNode n : nodes ) {
2465             node_ids.add( n.getId() );
2466         }
2467         node_ids.add( node.getId() );
2468         setCopiedAndPastedNodes( node_ids );
2469         repaint();
2470     }
2471
2472     final private String createASimpleTextRepresentationOfANode( final PhylogenyNode node ) {
2473         final String tax = PhylogenyMethods.getSpecies( node );
2474         String label = node.getName();
2475         if ( !ForesterUtil.isEmpty( label ) && !ForesterUtil.isEmpty( tax ) ) {
2476             label = label + " " + tax;
2477         }
2478         else if ( !ForesterUtil.isEmpty( tax ) ) {
2479             label = tax;
2480         }
2481         else {
2482             label = "";
2483         }
2484         if ( !ForesterUtil.isEmpty( label ) ) {
2485             label = " [" + label + "]";
2486         }
2487         return label;
2488     }
2489
2490     final private void cutSubtree( final PhylogenyNode node ) {
2491         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
2492             errorMessageNoCutCopyPasteInUnrootedDisplay();
2493             return;
2494         }
2495         if ( node.isRoot() ) {
2496             JOptionPane.showMessageDialog( this,
2497                                            "Cannot cut entire tree as subtree",
2498                                            "Attempt to cut entire tree",
2499                                            JOptionPane.ERROR_MESSAGE );
2500             return;
2501         }
2502         final String label = createASimpleTextRepresentationOfANode( node );
2503         final int r = JOptionPane.showConfirmDialog( null,
2504                                                      "Cut subtree" + label + "?",
2505                                                      "Confirm Cutting of Subtree",
2506                                                      JOptionPane.YES_NO_OPTION );
2507         if ( r != JOptionPane.OK_OPTION ) {
2508             return;
2509         }
2510         setNodeInPreorderToNull();
2511         setCopiedAndPastedNodes( null );
2512         setCutOrCopiedTree( _phylogeny.copy( node ) );
2513         _phylogeny.deleteSubtree( node, true );
2514         _phylogeny.clearHashIdToNodeMap();
2515         _phylogeny.recalculateNumberOfExternalDescendants( true );
2516         resetNodeIdToDistToLeafMap();
2517         setEdited( true );
2518         repaint();
2519     }
2520
2521     final private void cycleColors() {
2522         getMainPanel().getTreeColorSet().cycleColorScheme();
2523         for( final TreePanel tree_panel : getMainPanel().getTreePanels() ) {
2524             tree_panel.setBackground( getMainPanel().getTreeColorSet().getBackgroundColor() );
2525         }
2526     }
2527
2528     final private void decreaseOvSize() {
2529         if ( ( getOvMaxWidth() > 20 ) && ( getOvMaxHeight() > 20 ) ) {
2530             setOvMaxWidth( getOvMaxWidth() - 5 );
2531             setOvMaxHeight( getOvMaxHeight() - 5 );
2532             updateOvSettings();
2533             getControlPanel().displayedPhylogenyMightHaveChanged( false );
2534         }
2535     }
2536
2537     final private void deleteNodeOrSubtree( final PhylogenyNode node ) {
2538         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
2539             errorMessageNoCutCopyPasteInUnrootedDisplay();
2540             return;
2541         }
2542         if ( node.isRoot() && ( node.getNumberOfDescendants() != 1 ) ) {
2543             JOptionPane.showMessageDialog( this,
2544                                            "Cannot delete entire tree",
2545                                            "Attempt to delete entire tree",
2546                                            JOptionPane.ERROR_MESSAGE );
2547             return;
2548         }
2549         final String label = createASimpleTextRepresentationOfANode( node );
2550         final Object[] options = { "Node only", "Entire subtree", "Cancel" };
2551         final int r = JOptionPane.showOptionDialog( this,
2552                                                     "Delete" + label + "?",
2553                                                     "Delete Node/Subtree",
2554                                                     JOptionPane.CLOSED_OPTION,
2555                                                     JOptionPane.QUESTION_MESSAGE,
2556                                                     null,
2557                                                     options,
2558                                                     options[ 2 ] );
2559         setNodeInPreorderToNull();
2560         boolean node_only = true;
2561         if ( r == 1 ) {
2562             node_only = false;
2563         }
2564         else if ( r != 0 ) {
2565             return;
2566         }
2567         if ( node_only ) {
2568             PhylogenyMethods.removeNode( node, _phylogeny );
2569         }
2570         else {
2571             _phylogeny.deleteSubtree( node, true );
2572         }
2573         _phylogeny.externalNodesHaveChanged();
2574         _phylogeny.clearHashIdToNodeMap();
2575         _phylogeny.recalculateNumberOfExternalDescendants( true );
2576         resetNodeIdToDistToLeafMap();
2577         setEdited( true );
2578         repaint();
2579     }
2580
2581     final private void displayNodePopupMenu( final PhylogenyNode node, final int x, final int y ) {
2582         makePopupMenus( node );
2583         _node_popup_menu.putClientProperty( NODE_POPMENU_NODE_CLIENT_PROPERTY, node );
2584         _node_popup_menu.show( this, x, y );
2585     }
2586
2587     final private void drawArc( final double x,
2588                                 final double y,
2589                                 final double width,
2590                                 final double heigth,
2591                                 final double start_angle,
2592                                 final double arc_angle,
2593                                 final Graphics2D g ) {
2594         _arc.setArc( x, y, width, heigth, _180_OVER_PI * start_angle, _180_OVER_PI * arc_angle, Arc2D.OPEN );
2595         g.draw( _arc );
2596     }
2597
2598     final private void drawLine( final double x1, final double y1, final double x2, final double y2, final Graphics2D g ) {
2599         if ( ( x1 == x2 ) && ( y1 == y2 ) ) {
2600             return;
2601         }
2602         _line.setLine( x1, y1, x2, y2 );
2603         g.draw( _line );
2604     }
2605
2606     final private void drawOval( final double x,
2607                                  final double y,
2608                                  final double width,
2609                                  final double heigth,
2610                                  final Graphics2D g ) {
2611         _ellipse.setFrame( x, y, width, heigth );
2612         g.draw( _ellipse );
2613     }
2614
2615     final private void drawOvalFilled( final double x,
2616                                        final double y,
2617                                        final double width,
2618                                        final double heigth,
2619                                        final Graphics2D g ) {
2620         _ellipse.setFrame( x, y, width, heigth );
2621         g.fill( _ellipse );
2622     }
2623
2624     final private void drawOvalGradient( final double x,
2625                                          final double y,
2626                                          final double width,
2627                                          final double heigth,
2628                                          final Graphics2D g,
2629                                          final Color color_1,
2630                                          final Color color_2,
2631                                          final Color color_border ) {
2632         _ellipse.setFrame( x, y, width, heigth );
2633         g.setPaint( new GradientPaint( ( float ) x,
2634                                        ( float ) y,
2635                                        color_1,
2636                                        ( float ) ( x + width ),
2637                                        ( float ) ( y + heigth ),
2638                                        color_2,
2639                                        false ) );
2640         g.fill( _ellipse );
2641         if ( color_border != null ) {
2642             g.setPaint( color_border );
2643             g.draw( _ellipse );
2644         }
2645     }
2646
2647     final private void drawRect( final float x, final float y, final float width, final float heigth, final Graphics2D g ) {
2648         _rectangle.setFrame( x, y, width, heigth );
2649         g.draw( _rectangle );
2650     }
2651
2652     final private void drawRectFilled( final double x,
2653                                        final double y,
2654                                        final double width,
2655                                        final double heigth,
2656                                        final Graphics2D g ) {
2657         _rectangle.setFrame( x, y, width, heigth );
2658         g.fill( _rectangle );
2659     }
2660
2661     final private void drawRectGradient( final double x,
2662                                          final double y,
2663                                          final double width,
2664                                          final double heigth,
2665                                          final Graphics2D g,
2666                                          final Color color_1,
2667                                          final Color color_2,
2668                                          final Color color_border ) {
2669         _rectangle.setFrame( x, y, width, heigth );
2670         g.setPaint( new GradientPaint( ( float ) x,
2671                                        ( float ) y,
2672                                        color_1,
2673                                        ( float ) ( x + width ),
2674                                        ( float ) ( y + heigth ),
2675                                        color_2,
2676                                        false ) );
2677         g.fill( _rectangle );
2678         if ( color_border != null ) {
2679             g.setPaint( color_border );
2680             g.draw( _rectangle );
2681         }
2682     }
2683
2684     private double drawTaxonomyImage( final double x, final double y, final PhylogenyNode node, final Graphics2D g ) {
2685         final List<Uri> us = new ArrayList<Uri>();
2686         for( final Taxonomy t : node.getNodeData().getTaxonomies() ) {
2687             for( final Uri uri : t.getUris() ) {
2688                 us.add( uri );
2689             }
2690         }
2691         double offset = 0;
2692         for( final Uri uri : us ) {
2693             if ( uri != null ) {
2694                 final String uri_str = uri.getValue().toString().toLowerCase();
2695                 if ( getImageMap().containsKey( uri_str ) ) {
2696                     final BufferedImage bi = getImageMap().get( uri_str );
2697                     if ( ( bi != null ) && ( bi.getHeight() > 5 ) && ( bi.getWidth() > 5 ) ) {
2698                         double scaling_factor = 1;
2699                         if ( getOptions().isAllowMagnificationOfTaxonomyImages()
2700                                 || ( bi.getHeight() > ( 1.8 * getYdistance() ) ) ) {
2701                             scaling_factor = ( 1.8 * getYdistance() ) / bi.getHeight();
2702                         }
2703                         // y = y - ( 0.9 * getYdistance() );
2704                         final double hs = bi.getHeight() * scaling_factor;
2705                         double ws = ( bi.getWidth() * scaling_factor ) + offset;
2706                         final double my_y = y - ( 0.5 * hs );
2707                         final int x_w = ( int ) ( x + ws + 0.5 );
2708                         final int y_h = ( int ) ( my_y + hs + 0.5 );
2709                         if ( ( ( x_w - x ) > 7 ) && ( ( y_h - my_y ) > 7 ) ) {
2710                             g.drawImage( bi,
2711                                          ( int ) ( x + 0.5 + offset ),
2712                                          ( int ) ( my_y + 0.5 ),
2713                                          x_w,
2714                                          y_h,
2715                                          0,
2716                                          0,
2717                                          bi.getWidth(),
2718                                          bi.getHeight(),
2719                                          null );
2720                             ws += 8;
2721                         }
2722                         else {
2723                             ws = 0.0;
2724                         }
2725                         offset = ws;
2726                     }
2727                 }
2728             }
2729         }
2730         return offset;
2731     }
2732
2733     final private void errorMessageNoCutCopyPasteInUnrootedDisplay() {
2734         JOptionPane.showMessageDialog( this,
2735                                        "Cannot cut, copy, paste, add, or delete subtrees/nodes in unrooted display",
2736                                        "Attempt to cut/copy/paste/add/delete in unrooted display",
2737                                        JOptionPane.ERROR_MESSAGE );
2738     }
2739
2740     private final Color getColorForFoundNode( final PhylogenyNode n ) {
2741         if ( isInCurrentExternalNodes( n ) ) {
2742             return getTreeColorSet().getFoundColor0();
2743         }
2744         else if ( isInFoundNodes0( n ) && !isInFoundNodes1( n ) ) {
2745             return getTreeColorSet().getFoundColor0();
2746         }
2747         else if ( !isInFoundNodes0( n ) && isInFoundNodes1( n ) ) {
2748             return getTreeColorSet().getFoundColor1();
2749         }
2750         else {
2751             return getTreeColorSet().getFoundColor0and1();
2752         }
2753     }
2754
2755     final private Set<Long> getCopiedAndPastedNodes() {
2756         return getMainPanel().getCopiedAndPastedNodes();
2757     }
2758
2759     final private Set<Long> getCurrentExternalNodes() {
2760         return _current_external_nodes;
2761     }
2762
2763     final private Phylogeny getCutOrCopiedTree() {
2764         return getMainPanel().getCutOrCopiedTree();
2765     }
2766
2767     private List<PhylogenyNode> getFoundNodes0AsListOfPhylogenyNodes() {
2768         final List<PhylogenyNode> additional_nodes = new ArrayList<PhylogenyNode>();
2769         for( final Long id : getFoundNodes0() ) {
2770             additional_nodes.add( _phylogeny.getNode( id ) );
2771         }
2772         return additional_nodes;
2773     }
2774
2775     private List<PhylogenyNode> getFoundNodes1AsListOfPhylogenyNodes() {
2776         final List<PhylogenyNode> additional_nodes = new ArrayList<PhylogenyNode>();
2777         for( final Long id : getFoundNodes1() ) {
2778             additional_nodes.add( _phylogeny.getNode( id ) );
2779         }
2780         return additional_nodes;
2781     }
2782
2783     final private float getLastDragPointX() {
2784         return _last_drag_point_x;
2785     }
2786
2787     final private float getLastDragPointY() {
2788         return _last_drag_point_y;
2789     }
2790
2791     final private short getMaxBranchesToLeaf( final PhylogenyNode node ) {
2792         if ( !_nodeid_dist_to_leaf.containsKey( node.getId() ) ) {
2793             final short m = PhylogenyMethods.calculateMaxBranchesToLeaf( node );
2794             _nodeid_dist_to_leaf.put( node.getId(), m );
2795             return m;
2796         }
2797         else {
2798             return _nodeid_dist_to_leaf.get( node.getId() );
2799         }
2800     }
2801
2802     final private double getMaxDistanceToRoot() {
2803         if ( _max_distance_to_root < 0 ) {
2804             recalculateMaxDistanceToRoot();
2805         }
2806         return _max_distance_to_root;
2807     }
2808
2809     final private float getOvMaxHeight() {
2810         return _ov_max_height;
2811     }
2812
2813     final private float getOvMaxWidth() {
2814         return _ov_max_width;
2815     }
2816
2817     final private float getOvXcorrectionFactor() {
2818         return _ov_x_correction_factor;
2819     }
2820
2821     final private float getOvXDistance() {
2822         return _ov_x_distance;
2823     }
2824
2825     final private int getOvXPosition() {
2826         return _ov_x_position;
2827     }
2828
2829     final private float getOvYDistance() {
2830         return _ov_y_distance;
2831     }
2832
2833     final private int getOvYPosition() {
2834         return _ov_y_position;
2835     }
2836
2837     final private int getOvYStart() {
2838         return _ov_y_start;
2839     }
2840
2841     final private List<Accession> getPdbAccs( final PhylogenyNode node ) {
2842         final List<Accession> pdb_ids = new ArrayList<Accession>();
2843         if ( node.getNodeData().isHasSequence() ) {
2844             final Sequence seq = node.getNodeData().getSequence();
2845             if ( !ForesterUtil.isEmpty( seq.getCrossReferences() ) ) {
2846                 final SortedSet<Accession> cross_refs = seq.getCrossReferences();
2847                 for( final Accession acc : cross_refs ) {
2848                     if ( acc.getSource().equalsIgnoreCase( "pdb" ) ) {
2849                         pdb_ids.add( acc );
2850                     }
2851                 }
2852             }
2853         }
2854         return pdb_ids;
2855     }
2856
2857     final private double getScaleDistance() {
2858         return _scale_distance;
2859     }
2860
2861     final private String getScaleLabel() {
2862         return _scale_label;
2863     }
2864
2865     final private TreeFontSet getTreeFontSet() {
2866         return getMainPanel().getTreeFontSet();
2867     }
2868
2869     final private float getUrtFactor() {
2870         return _urt_factor;
2871     }
2872
2873     final private float getUrtFactorOv() {
2874         return _urt_factor_ov;
2875     }
2876
2877     final private void handleClickToAction( final NodeClickAction action, final PhylogenyNode node ) {
2878         switch ( action ) {
2879             case SHOW_DATA:
2880                 showNodeFrame( node );
2881                 break;
2882             case COLLAPSE:
2883                 collapse( node );
2884                 break;
2885             case REROOT:
2886                 reRoot( node );
2887                 break;
2888             case SUBTREE:
2889                 subTree( node );
2890                 break;
2891             case SWAP:
2892                 swap( node );
2893                 break;
2894             case COLOR_SUBTREE:
2895                 colorSubtree( node );
2896                 break;
2897             case OPEN_SEQ_WEB:
2898                 openSeqWeb( node );
2899                 break;
2900             case BLAST:
2901                 blast( node );
2902                 break;
2903             case OPEN_TAX_WEB:
2904                 openTaxWeb( node );
2905                 break;
2906             case OPEN_PDB_WEB:
2907                 openPdbWeb( node );
2908                 break;
2909             case CUT_SUBTREE:
2910                 cutSubtree( node );
2911                 break;
2912             case COPY_SUBTREE:
2913                 copySubtree( node );
2914                 break;
2915             case PASTE_SUBTREE:
2916                 pasteSubtree( node );
2917                 break;
2918             case DELETE_NODE_OR_SUBTREE:
2919                 deleteNodeOrSubtree( node );
2920                 break;
2921             case ADD_NEW_NODE:
2922                 addEmptyNode( node );
2923                 break;
2924             case EDIT_NODE_DATA:
2925                 showNodeEditFrame( node );
2926                 break;
2927             case SELECT_NODES:
2928                 selectNode( node );
2929                 break;
2930             case SORT_DESCENDENTS:
2931                 sortDescendants( node );
2932                 break;
2933             case GET_EXT_DESC_DATA:
2934                 showExtDescNodeData( node );
2935                 break;
2936             default:
2937                 throw new IllegalArgumentException( "unknown action: " + action );
2938         }
2939     }
2940
2941     final private void increaseCurrentExternalNodesDataBufferChangeCounter() {
2942         _current_external_nodes_data_buffer_change_counter++;
2943     }
2944
2945     final private void increaseOvSize() {
2946         if ( ( getOvMaxWidth() < ( getMainPanel().getCurrentScrollPane().getViewport().getVisibleRect().getWidth() / 2 ) )
2947                 && ( getOvMaxHeight() < ( getMainPanel().getCurrentScrollPane().getViewport().getVisibleRect()
2948                         .getHeight() / 2 ) ) ) {
2949             setOvMaxWidth( getOvMaxWidth() + 5 );
2950             setOvMaxHeight( getOvMaxHeight() + 5 );
2951             updateOvSettings();
2952             getControlPanel().displayedPhylogenyMightHaveChanged( false );
2953         }
2954     }
2955
2956     final private void init() {
2957         _color_chooser = new JColorChooser();
2958         _rollover_popup = new JTextArea();
2959         _rollover_popup.setFont( POPUP_FONT );
2960         resetNodeIdToDistToLeafMap();
2961         setTextAntialias();
2962         setTreeFile( null );
2963         setEdited( false );
2964         initializeOvSettings();
2965         setStartingAngle( ( TWO_PI * 3 ) / 4 );
2966         final ImageLoader il = new ImageLoader( this );
2967         new Thread( il ).start();
2968     }
2969
2970     final private void initializeOvSettings() {
2971         setOvMaxHeight( getConfiguration().getOvMaxHeight() );
2972         setOvMaxWidth( getConfiguration().getOvMaxWidth() );
2973     }
2974
2975     final private boolean inOvVirtualRectangle( final int x, final int y ) {
2976         return ( ( x >= ( getOvVirtualRectangle().x - 1 ) )
2977                 && ( x <= ( getOvVirtualRectangle().x + getOvVirtualRectangle().width + 1 ) )
2978                 && ( y >= ( getOvVirtualRectangle().y - 1 ) ) && ( y <= ( getOvVirtualRectangle().y
2979                 + getOvVirtualRectangle().height + 1 ) ) );
2980     }
2981
2982     final private boolean inOvVirtualRectangle( final MouseEvent e ) {
2983         return ( inOvVirtualRectangle( e.getX(), e.getY() ) );
2984     }
2985
2986     final private boolean isCanBlast( final PhylogenyNode node ) {
2987         if ( !node.getNodeData().isHasSequence() && ForesterUtil.isEmpty( node.getName() ) ) {
2988             return false;
2989         }
2990         return Blast.isContainsQueryForBlast( node );
2991     }
2992
2993     final private String isCanOpenSeqWeb( final PhylogenyNode node ) {
2994         final Accession a = SequenceAccessionTools.obtainAccessorFromDataFields( node );
2995         if ( a != null ) {
2996             return a.getValue();
2997         }
2998         return null;
2999     }
3000
3001     final private boolean isCanOpenTaxWeb( final PhylogenyNode node ) {
3002         if ( node.getNodeData().isHasTaxonomy()
3003                 && ( ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getScientificName() ) )
3004                         || ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getTaxonomyCode() ) )
3005                         || ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getCommonName() ) ) || ( ( node
3006                         .getNodeData().getTaxonomy().getIdentifier() != null ) && !ForesterUtil.isEmpty( node
3007                         .getNodeData().getTaxonomy().getIdentifier().getValue() ) ) ) ) {
3008             return true;
3009         }
3010         else {
3011             return false;
3012         }
3013     }
3014
3015     final private boolean isInCurrentExternalNodes( final PhylogenyNode node ) {
3016         return ( ( getCurrentExternalNodes() != null ) && getCurrentExternalNodes().contains( node.getId() ) );
3017     }
3018
3019     private boolean isInFoundNodes( final PhylogenyNode n ) {
3020         return isInFoundNodes0( n ) || isInFoundNodes1( n );
3021     }
3022
3023     final private boolean isInFoundNodes0( final PhylogenyNode node ) {
3024         return ( ( getFoundNodes0() != null ) && getFoundNodes0().contains( node.getId() ) );
3025     }
3026
3027     final private boolean isInFoundNodes1( final PhylogenyNode node ) {
3028         return ( ( getFoundNodes1() != null ) && getFoundNodes1().contains( node.getId() ) );
3029     }
3030
3031     final private boolean isInOv() {
3032         return _in_ov;
3033     }
3034
3035     final private boolean isNodeDataInvisible( final PhylogenyNode node ) {
3036         int y_dist = 40;
3037         if ( getControlPanel().isShowTaxonomyImages() ) {
3038             y_dist = 40 + ( int ) getYdistance();
3039         }
3040         return ( ( node.getYcoord() < ( getVisibleRect().getMinY() - y_dist ) )
3041                 || ( node.getYcoord() > ( getVisibleRect().getMaxY() + y_dist ) ) || ( ( node.getParent() != null ) && ( node
3042                 .getParent().getXcoord() > getVisibleRect().getMaxX() ) ) );
3043     }
3044
3045     final private boolean isNodeDataInvisibleUnrootedCirc( final PhylogenyNode node ) {
3046         return ( ( node.getYcoord() < ( getVisibleRect().getMinY() - 20 ) )
3047                 || ( node.getYcoord() > ( getVisibleRect().getMaxY() + 20 ) )
3048                 || ( node.getXcoord() < ( getVisibleRect().getMinX() - 20 ) ) || ( node.getXcoord() > ( getVisibleRect()
3049                 .getMaxX() + 20 ) ) );
3050     }
3051
3052     final private boolean isNonLinedUpCladogram() {
3053         return getOptions().getCladogramType() == CLADOGRAM_TYPE.NON_LINED_UP;
3054     }
3055
3056     final private boolean isUniformBranchLengthsForCladogram() {
3057         return getOptions().getCladogramType() == CLADOGRAM_TYPE.TOTAL_NODE_SUM_DEP;
3058     }
3059
3060     final private void keyPressedCalls( final KeyEvent e ) {
3061         if ( isOvOn() && ( getMousePosition() != null ) && ( getMousePosition().getLocation() != null ) ) {
3062             if ( inOvVirtualRectangle( getMousePosition().x, getMousePosition().y ) ) {
3063                 if ( !isInOvRect() ) {
3064                     setInOvRect( true );
3065                 }
3066             }
3067             else if ( isInOvRect() ) {
3068                 setInOvRect( false );
3069             }
3070         }
3071         if ( e.getModifiersEx() == InputEvent.CTRL_DOWN_MASK ) {
3072             if ( ( e.getKeyCode() == KeyEvent.VK_DELETE ) || ( e.getKeyCode() == KeyEvent.VK_HOME )
3073                     || ( e.getKeyCode() == KeyEvent.VK_F ) ) {
3074                 getMainPanel().getTreeFontSet().mediumFonts();
3075                 getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( true );
3076             }
3077             else if ( ( e.getKeyCode() == KeyEvent.VK_SUBTRACT ) || ( e.getKeyCode() == KeyEvent.VK_MINUS ) ) {
3078                 getMainPanel().getTreeFontSet().decreaseFontSize( 1, false );
3079                 getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( true );
3080             }
3081             else if ( plusPressed( e.getKeyCode() ) ) {
3082                 getMainPanel().getTreeFontSet().increaseFontSize();
3083                 getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( true );
3084             }
3085         }
3086         else {
3087             if ( ( e.getKeyCode() == KeyEvent.VK_DELETE ) || ( e.getKeyCode() == KeyEvent.VK_HOME )
3088                     || ( e.getKeyCode() == KeyEvent.VK_F ) ) {
3089                 getControlPanel().showWhole();
3090             }
3091             else if ( ( e.getKeyCode() == KeyEvent.VK_UP ) || ( e.getKeyCode() == KeyEvent.VK_DOWN )
3092                     || ( e.getKeyCode() == KeyEvent.VK_LEFT ) || ( e.getKeyCode() == KeyEvent.VK_RIGHT ) ) {
3093                 if ( e.getModifiersEx() == InputEvent.SHIFT_DOWN_MASK ) {
3094                     if ( e.getKeyCode() == KeyEvent.VK_UP ) {
3095                         getMainPanel().getControlPanel().zoomInY( Constants.WHEEL_ZOOM_IN_FACTOR );
3096                         getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
3097                     }
3098                     else if ( e.getKeyCode() == KeyEvent.VK_DOWN ) {
3099                         getMainPanel().getControlPanel().zoomOutY( Constants.WHEEL_ZOOM_OUT_FACTOR );
3100                         getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
3101                     }
3102                     else if ( e.getKeyCode() == KeyEvent.VK_LEFT ) {
3103                         getMainPanel().getControlPanel().zoomOutX( Constants.WHEEL_ZOOM_OUT_FACTOR,
3104                                                                    Constants.WHEEL_ZOOM_OUT_X_CORRECTION_FACTOR );
3105                         getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
3106                     }
3107                     else if ( e.getKeyCode() == KeyEvent.VK_RIGHT ) {
3108                         getMainPanel().getControlPanel().zoomInX( Constants.WHEEL_ZOOM_IN_FACTOR,
3109                                                                   Constants.WHEEL_ZOOM_IN_FACTOR );
3110                         getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
3111                     }
3112                 }
3113                 else {
3114                     final int d = 80;
3115                     int dx = 0;
3116                     int dy = -d;
3117                     if ( e.getKeyCode() == KeyEvent.VK_DOWN ) {
3118                         dy = d;
3119                     }
3120                     else if ( e.getKeyCode() == KeyEvent.VK_LEFT ) {
3121                         dx = -d;
3122                         dy = 0;
3123                     }
3124                     else if ( e.getKeyCode() == KeyEvent.VK_RIGHT ) {
3125                         dx = d;
3126                         dy = 0;
3127                     }
3128                     final Point scroll_position = getMainPanel().getCurrentScrollPane().getViewport().getViewPosition();
3129                     scroll_position.x = scroll_position.x + dx;
3130                     scroll_position.y = scroll_position.y + dy;
3131                     if ( scroll_position.x <= 0 ) {
3132                         scroll_position.x = 0;
3133                     }
3134                     else {
3135                         final int max_x = getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getMaximum()
3136                                 - getMainPanel().getCurrentScrollPane().getHorizontalScrollBar().getVisibleAmount();
3137                         if ( scroll_position.x >= max_x ) {
3138                             scroll_position.x = max_x;
3139                         }
3140                     }
3141                     if ( scroll_position.y <= 0 ) {
3142                         scroll_position.y = 0;
3143                     }
3144                     else {
3145                         final int max_y = getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getMaximum()
3146                                 - getMainPanel().getCurrentScrollPane().getVerticalScrollBar().getVisibleAmount();
3147                         if ( scroll_position.y >= max_y ) {
3148                             scroll_position.y = max_y;
3149                         }
3150                     }
3151                     repaint();
3152                     getMainPanel().getCurrentScrollPane().getViewport().setViewPosition( scroll_position );
3153                 }
3154             }
3155             else if ( ( e.getKeyCode() == KeyEvent.VK_SUBTRACT ) || ( e.getKeyCode() == KeyEvent.VK_MINUS ) ) {
3156                 getMainPanel().getControlPanel().zoomOutY( Constants.WHEEL_ZOOM_OUT_FACTOR );
3157                 getMainPanel().getControlPanel().zoomOutX( Constants.WHEEL_ZOOM_OUT_FACTOR,
3158                                                            Constants.WHEEL_ZOOM_OUT_X_CORRECTION_FACTOR );
3159                 getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
3160             }
3161             else if ( plusPressed( e.getKeyCode() ) ) {
3162                 getMainPanel().getControlPanel().zoomInX( Constants.WHEEL_ZOOM_IN_FACTOR,
3163                                                           Constants.WHEEL_ZOOM_IN_FACTOR );
3164                 getMainPanel().getControlPanel().zoomInY( Constants.WHEEL_ZOOM_IN_FACTOR );
3165                 getMainPanel().getControlPanel().displayedPhylogenyMightHaveChanged( false );
3166             }
3167             else if ( e.getKeyCode() == KeyEvent.VK_S ) {
3168                 if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
3169                         || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
3170                     setStartingAngle( ( getStartingAngle() % TWO_PI ) + ANGLE_ROTATION_UNIT );
3171                     getControlPanel().displayedPhylogenyMightHaveChanged( false );
3172                 }
3173             }
3174             else if ( e.getKeyCode() == KeyEvent.VK_A ) {
3175                 if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED )
3176                         || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
3177                     setStartingAngle( ( getStartingAngle() % TWO_PI ) - ANGLE_ROTATION_UNIT );
3178                     if ( getStartingAngle() < 0 ) {
3179                         setStartingAngle( TWO_PI + getStartingAngle() );
3180                     }
3181                     getControlPanel().displayedPhylogenyMightHaveChanged( false );
3182                 }
3183             }
3184             else if ( e.getKeyCode() == KeyEvent.VK_D ) {
3185                 boolean selected = false;
3186                 if ( getOptions().getNodeLabelDirection() == NODE_LABEL_DIRECTION.HORIZONTAL ) {
3187                     getOptions().setNodeLabelDirection( NODE_LABEL_DIRECTION.RADIAL );
3188                     selected = true;
3189                 }
3190                 else {
3191                     getOptions().setNodeLabelDirection( NODE_LABEL_DIRECTION.HORIZONTAL );
3192                 }
3193                 if ( getMainPanel().getMainFrame() == null ) {
3194                     // Must be "E" applet version.
3195                     final ArchaeopteryxE ae = ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet();
3196                     if ( ae.getlabelDirectionCbmi() != null ) {
3197                         ae.getlabelDirectionCbmi().setSelected( selected );
3198                     }
3199                 }
3200                 else {
3201                     getMainPanel().getMainFrame().getlabelDirectionCbmi().setSelected( selected );
3202                 }
3203                 repaint();
3204             }
3205             else if ( e.getKeyCode() == KeyEvent.VK_X ) {
3206                 switchDisplaygetPhylogenyGraphicsType();
3207                 repaint();
3208             }
3209             else if ( e.getKeyCode() == KeyEvent.VK_C ) {
3210                 cycleColors();
3211                 repaint();
3212             }
3213             else if ( getOptions().isShowOverview() && isOvOn() && ( e.getKeyCode() == KeyEvent.VK_O ) ) {
3214                 MainFrame.cycleOverview( getOptions(), this );
3215                 repaint();
3216             }
3217             else if ( getOptions().isShowOverview() && isOvOn() && ( e.getKeyCode() == KeyEvent.VK_I ) ) {
3218                 increaseOvSize();
3219             }
3220             else if ( getOptions().isShowOverview() && isOvOn() && ( e.getKeyCode() == KeyEvent.VK_U ) ) {
3221                 decreaseOvSize();
3222             }
3223             e.consume();
3224         }
3225     }
3226
3227     final private void makePopupMenus( final PhylogenyNode node ) {
3228         _node_popup_menu = new JPopupMenu();
3229         final List<String> clickto_names = _main_panel.getControlPanel().getSingleClickToNames();
3230         _node_popup_menu_items = new JMenuItem[ clickto_names.size() ];
3231         for( int i = 0; i < clickto_names.size(); i++ ) {
3232             final String title = clickto_names.get( i );
3233             _node_popup_menu_items[ i ] = new JMenuItem( title );
3234             if ( title.equals( Configuration.clickto_options[ Configuration.open_seq_web ][ 0 ] ) ) {
3235                 final String id = isCanOpenSeqWeb( node );
3236                 if ( !ForesterUtil.isEmpty( id ) ) {
3237                     _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " [" + id + "]" );
3238                     _node_popup_menu_items[ i ].setEnabled( true );
3239                 }
3240                 else {
3241                     _node_popup_menu_items[ i ].setEnabled( false );
3242                 }
3243             }
3244             else if ( title.equals( Configuration.clickto_options[ Configuration.open_pdb_web ][ 0 ] ) ) {
3245                 final List<Accession> accs = getPdbAccs( node );
3246                 _node_popup_menu_items[ i ] = new JMenuItem( title );
3247                 if ( !ForesterUtil.isEmpty( accs ) ) {
3248                     if ( accs.size() == 1 ) {
3249                         _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " ["
3250                                 + TreePanelUtil.pdbAccToString( accs, 0 ) + "]" );
3251                         _node_popup_menu_items[ i ].setEnabled( true );
3252                     }
3253                     else if ( accs.size() == 2 ) {
3254                         _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " ["
3255                                 + TreePanelUtil.pdbAccToString( accs, 0 ) + ", "
3256                                 + TreePanelUtil.pdbAccToString( accs, 1 ) + "]" );
3257                         _node_popup_menu_items[ i ].setEnabled( true );
3258                     }
3259                     else if ( accs.size() == 3 ) {
3260                         _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " ["
3261                                 + TreePanelUtil.pdbAccToString( accs, 0 ) + ", "
3262                                 + TreePanelUtil.pdbAccToString( accs, 1 ) + ", "
3263                                 + TreePanelUtil.pdbAccToString( accs, 2 ) + "]" );
3264                         _node_popup_menu_items[ i ].setEnabled( true );
3265                     }
3266                     else {
3267                         _node_popup_menu_items[ i ].setText( _node_popup_menu_items[ i ].getText() + " ["
3268                                 + TreePanelUtil.pdbAccToString( accs, 0 ) + ", "
3269                                 + TreePanelUtil.pdbAccToString( accs, 1 ) + ", "
3270                                 + TreePanelUtil.pdbAccToString( accs, 2 ) + ", + " + ( accs.size() - 3 ) + " more]" );
3271                         _node_popup_menu_items[ i ].setEnabled( true );
3272                     }
3273                 }
3274                 else {
3275                     _node_popup_menu_items[ i ].setEnabled( false );
3276                 }
3277                 //
3278             }
3279             else if ( title.equals( Configuration.clickto_options[ Configuration.open_tax_web ][ 0 ] ) ) {
3280                 _node_popup_menu_items[ i ].setEnabled( isCanOpenTaxWeb( node ) );
3281             }
3282             else if ( title.equals( Configuration.clickto_options[ Configuration.blast ][ 0 ] ) ) {
3283                 _node_popup_menu_items[ i ].setEnabled( isCanBlast( node ) );
3284             }
3285             else if ( title.equals( Configuration.clickto_options[ Configuration.delete_subtree_or_node ][ 0 ] ) ) {
3286                 if ( !getOptions().isEditable() ) {
3287                     continue;
3288                 }
3289                 _node_popup_menu_items[ i ].setEnabled( isCanDelete() );
3290             }
3291             else if ( title.equals( Configuration.clickto_options[ Configuration.cut_subtree ][ 0 ] ) ) {
3292                 if ( !getOptions().isEditable() ) {
3293                     continue;
3294                 }
3295                 _node_popup_menu_items[ i ].setEnabled( isCanCut( node ) );
3296             }
3297             else if ( title.equals( Configuration.clickto_options[ Configuration.copy_subtree ][ 0 ] ) ) {
3298                 if ( !getOptions().isEditable() ) {
3299                     continue;
3300                 }
3301                 _node_popup_menu_items[ i ].setEnabled( isCanCopy() );
3302             }
3303             else if ( title.equals( Configuration.clickto_options[ Configuration.paste_subtree ][ 0 ] ) ) {
3304                 if ( !getOptions().isEditable() ) {
3305                     continue;
3306                 }
3307                 _node_popup_menu_items[ i ].setEnabled( isCanPaste() );
3308             }
3309             else if ( title.equals( Configuration.clickto_options[ Configuration.edit_node_data ][ 0 ] ) ) {
3310                 if ( !getOptions().isEditable() ) {
3311                     continue;
3312                 }
3313             }
3314             else if ( title.equals( Configuration.clickto_options[ Configuration.add_new_node ][ 0 ] ) ) {
3315                 if ( !getOptions().isEditable() ) {
3316                     continue;
3317                 }
3318             }
3319             else if ( title.equals( Configuration.clickto_options[ Configuration.reroot ][ 0 ] ) ) {
3320                 _node_popup_menu_items[ i ].setEnabled( isCanReroot() );
3321             }
3322             else if ( title.equals( Configuration.clickto_options[ Configuration.collapse_uncollapse ][ 0 ] ) ) {
3323                 _node_popup_menu_items[ i ].setEnabled( ( isCanCollapse() && !node.isExternal() ) );
3324             }
3325             else if ( title.equals( Configuration.clickto_options[ Configuration.color_subtree ][ 0 ] ) ) {
3326                 _node_popup_menu_items[ i ].setEnabled( isCanColorSubtree() );
3327             }
3328             else if ( title.equals( Configuration.clickto_options[ Configuration.subtree ][ 0 ] ) ) {
3329                 _node_popup_menu_items[ i ].setEnabled( isCanSubtree( node ) );
3330             }
3331             else if ( title.equals( Configuration.clickto_options[ Configuration.swap ][ 0 ] ) ) {
3332                 _node_popup_menu_items[ i ].setEnabled( node.getNumberOfDescendants() == 2 );
3333             }
3334             else if ( title.equals( Configuration.clickto_options[ Configuration.sort_descendents ][ 0 ] ) ) {
3335                 _node_popup_menu_items[ i ].setEnabled( node.getNumberOfDescendants() > 1 );
3336             }
3337             _node_popup_menu_items[ i ].addActionListener( this );
3338             _node_popup_menu.add( _node_popup_menu_items[ i ] );
3339         }
3340     }
3341
3342     private final String obtainTitleForExtDescNodeData() {
3343         switch ( getOptions().getExtDescNodeDataToReturn() ) {
3344             case NODE_NAME:
3345                 return "Node Names";
3346             case GENE_NAME:
3347                 return "Gene Names";
3348             case SEQUENCE_NAME:
3349                 return "Sequence Names";
3350             case SEQUENCE_SYMBOL:
3351                 return "Sequence Symbols";
3352             case SEQUENCE_MOL_SEQ:
3353                 return "Molecular Sequences";
3354             case SEQUENCE_MOL_SEQ_FASTA:
3355                 return "Molecular Sequences (Fasta)";
3356             case SEQUENCE_ACC:
3357                 return "Sequence Accessors";
3358             case TAXONOMY_SCIENTIFIC_NAME:
3359                 return "Scientific Names";
3360             case TAXONOMY_CODE:
3361                 return "Taxonomy Codes";
3362             case TAXONOMY_COMM0N_NAME:
3363                 return "Taxonomy Common Names";
3364             case UNKNOWN:
3365                 return "User Selected Data";
3366             default:
3367                 throw new IllegalArgumentException( "unknown data element: "
3368                         + getOptions().getExtDescNodeDataToReturn() );
3369         }
3370     }
3371
3372     final private void openPdbWeb( final PhylogenyNode node ) {
3373         final List<Accession> pdb_ids = getPdbAccs( node );
3374         if ( ForesterUtil.isEmpty( pdb_ids ) ) {
3375             cannotOpenBrowserWarningMessage( "PDB" );
3376             return;
3377         }
3378         final List<String> uri_strs = TreePanelUtil.createUrisForPdbWeb( node, pdb_ids, getConfiguration(), this );
3379         if ( !ForesterUtil.isEmpty( uri_strs ) ) {
3380             for( final String uri_str : uri_strs ) {
3381                 try {
3382                     AptxUtil.launchWebBrowser( new URI( uri_str ),
3383                                                isApplet(),
3384                                                isApplet() ? obtainApplet() : null,
3385                                                "_aptx_seq" );
3386                 }
3387                 catch ( final IOException e ) {
3388                     AptxUtil.showErrorMessage( this, e.toString() );
3389                     e.printStackTrace();
3390                 }
3391                 catch ( final URISyntaxException e ) {
3392                     AptxUtil.showErrorMessage( this, e.toString() );
3393                     e.printStackTrace();
3394                 }
3395             }
3396         }
3397         else {
3398             cannotOpenBrowserWarningMessage( "PDB" );
3399         }
3400     }
3401
3402     final private void openSeqWeb( final PhylogenyNode node ) {
3403         if ( ForesterUtil.isEmpty( isCanOpenSeqWeb( node ) ) ) {
3404             cannotOpenBrowserWarningMessage( "sequence" );
3405             return;
3406         }
3407         final String uri_str = TreePanelUtil.createUriForSeqWeb( node, getConfiguration(), this );
3408         if ( !ForesterUtil.isEmpty( uri_str ) ) {
3409             try {
3410                 AptxUtil.launchWebBrowser( new URI( uri_str ),
3411                                            isApplet(),
3412                                            isApplet() ? obtainApplet() : null,
3413                                            "_aptx_seq" );
3414             }
3415             catch ( final IOException e ) {
3416                 AptxUtil.showErrorMessage( this, e.toString() );
3417                 e.printStackTrace();
3418             }
3419             catch ( final URISyntaxException e ) {
3420                 AptxUtil.showErrorMessage( this, e.toString() );
3421                 e.printStackTrace();
3422             }
3423         }
3424         else {
3425             cannotOpenBrowserWarningMessage( "sequence" );
3426         }
3427     }
3428
3429     final private void openTaxWeb( final PhylogenyNode node ) {
3430         if ( !isCanOpenTaxWeb( node ) ) {
3431             cannotOpenBrowserWarningMessage( "taxonomic" );
3432             return;
3433         }
3434         String uri_str = null;
3435         final Taxonomy tax = node.getNodeData().getTaxonomy();
3436         if ( ( tax.getIdentifier() != null ) && !ForesterUtil.isEmpty( tax.getIdentifier().getValue() )
3437                 && tax.getIdentifier().getValue().startsWith( "http://" ) ) {
3438             try {
3439                 uri_str = new URI( tax.getIdentifier().getValue() ).toString();
3440             }
3441             catch ( final URISyntaxException e ) {
3442                 AptxUtil.showErrorMessage( this, e.toString() );
3443                 uri_str = null;
3444                 e.printStackTrace();
3445             }
3446         }
3447         else if ( ( tax.getIdentifier() != null )
3448                 && !ForesterUtil.isEmpty( tax.getIdentifier().getValue() )
3449                 && !ForesterUtil.isEmpty( tax.getIdentifier().getProvider() )
3450                 && ( tax.getIdentifier().getProvider().equalsIgnoreCase( "ncbi" ) || tax.getIdentifier().getProvider()
3451                         .equalsIgnoreCase( "uniprot" ) ) ) {
3452             try {
3453                 uri_str = "http://www.uniprot.org/taxonomy/"
3454                         + URLEncoder.encode( tax.getIdentifier().getValue(), ForesterConstants.UTF8 );
3455             }
3456             catch ( final UnsupportedEncodingException e ) {
3457                 AptxUtil.showErrorMessage( this, e.toString() );
3458                 e.printStackTrace();
3459             }
3460         }
3461         else if ( !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
3462             try {
3463                 uri_str = "http://www.uniprot.org/taxonomy/?query="
3464                         + URLEncoder.encode( tax.getScientificName(), ForesterConstants.UTF8 );
3465             }
3466             catch ( final UnsupportedEncodingException e ) {
3467                 AptxUtil.showErrorMessage( this, e.toString() );
3468                 e.printStackTrace();
3469             }
3470         }
3471         else if ( !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
3472             try {
3473                 uri_str = "http://www.uniprot.org/taxonomy/?query="
3474                         + URLEncoder.encode( tax.getTaxonomyCode(), ForesterConstants.UTF8 );
3475             }
3476             catch ( final UnsupportedEncodingException e ) {
3477                 AptxUtil.showErrorMessage( this, e.toString() );
3478                 e.printStackTrace();
3479             }
3480         }
3481         else if ( !ForesterUtil.isEmpty( tax.getCommonName() ) ) {
3482             try {
3483                 uri_str = "http://www.uniprot.org/taxonomy/?query="
3484                         + URLEncoder.encode( tax.getCommonName(), ForesterConstants.UTF8 );
3485             }
3486             catch ( final UnsupportedEncodingException e ) {
3487                 AptxUtil.showErrorMessage( this, e.toString() );
3488                 e.printStackTrace();
3489             }
3490         }
3491         if ( !ForesterUtil.isEmpty( uri_str ) ) {
3492             try {
3493                 AptxUtil.launchWebBrowser( new URI( uri_str ),
3494                                            isApplet(),
3495                                            isApplet() ? obtainApplet() : null,
3496                                            "_aptx_tax" );
3497             }
3498             catch ( final IOException e ) {
3499                 AptxUtil.showErrorMessage( this, e.toString() );
3500                 e.printStackTrace();
3501             }
3502             catch ( final URISyntaxException e ) {
3503                 AptxUtil.showErrorMessage( this, e.toString() );
3504                 e.printStackTrace();
3505             }
3506         }
3507         else {
3508             cannotOpenBrowserWarningMessage( "taxonomic" );
3509         }
3510     }
3511
3512     final private void paintBranchLength( final Graphics2D g,
3513                                           final PhylogenyNode node,
3514                                           final boolean to_pdf,
3515                                           final boolean to_graphics_file ) {
3516         g.setFont( getTreeFontSet().getSmallFont() );
3517         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
3518             g.setColor( Color.BLACK );
3519         }
3520         else {
3521             g.setColor( getTreeColorSet().getBranchLengthColor() );
3522         }
3523         if ( !node.isRoot() ) {
3524             if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
3525                 TreePanel.drawString( FORMATTER_BRANCH_LENGTH.format( node.getDistanceToParent() ), node.getParent()
3526                         .getXcoord() + EURO_D, node.getYcoord() - getTreeFontSet()._small_max_descent, g );
3527             }
3528             else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
3529                 TreePanel.drawString( FORMATTER_BRANCH_LENGTH.format( node.getDistanceToParent() ), node.getParent()
3530                         .getXcoord() + ROUNDED_D, node.getYcoord() - getTreeFontSet()._small_max_descent, g );
3531             }
3532             else {
3533                 TreePanel.drawString( FORMATTER_BRANCH_LENGTH.format( node.getDistanceToParent() ), node.getParent()
3534                         .getXcoord() + 3, node.getYcoord() - getTreeFontSet()._small_max_descent, g );
3535             }
3536         }
3537         else {
3538             TreePanel.drawString( FORMATTER_BRANCH_LENGTH.format( node.getDistanceToParent() ), 3, node.getYcoord()
3539                     - getTreeFontSet()._small_max_descent, g );
3540         }
3541     }
3542
3543     final private void paintBranchLite( final Graphics2D g,
3544                                         final float x1,
3545                                         final float x2,
3546                                         final float y1,
3547                                         final float y2,
3548                                         final PhylogenyNode node ) {
3549         g.setColor( getTreeColorSet().getOvColor() );
3550         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR ) {
3551             drawLine( x1, y1, x2, y2, g );
3552         }
3553         else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CONVEX ) {
3554             _quad_curve.setCurve( x1, y1, x1, y2, x2, y2 );
3555             ( g ).draw( _quad_curve );
3556         }
3557         else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CURVED ) {
3558             final float dx = x2 - x1;
3559             final float dy = y2 - y1;
3560             _cubic_curve.setCurve( x1, y1, x1 + ( dx * 0.4f ), y1 + ( dy * 0.2f ), x1 + ( dx * 0.6f ), y1
3561                     + ( dy * 0.8f ), x2, y2 );
3562             ( g ).draw( _cubic_curve );
3563         }
3564         else {
3565             final float x2a = x2;
3566             final float x1a = x1;
3567             // draw the vertical line
3568             if ( node.isFirstChildNode() || node.isLastChildNode() ) {
3569                 drawLine( x1, y1, x1, y2, g );
3570             }
3571             // draw the horizontal line
3572             drawLine( x1a, y2, x2a, y2, g );
3573         }
3574     }
3575
3576     /**
3577      * Paint a branch which consists of a vertical and a horizontal bar
3578      * @param is_ind_found_nodes 
3579      */
3580     final private void paintBranchRectangular( final Graphics2D g,
3581                                                final float x1,
3582                                                final float x2,
3583                                                final float y1,
3584                                                final float y2,
3585                                                final PhylogenyNode node,
3586                                                final boolean to_pdf,
3587                                                final boolean to_graphics_file ) {
3588         assignGraphicsForBranchWithColorForParentBranch( node, false, g, to_pdf, to_graphics_file );
3589         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR ) {
3590             drawLine( x1, y1, x2, y2, g );
3591         }
3592         else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CONVEX ) {
3593             _quad_curve.setCurve( x1, y1, x1, y2, x2, y2 );
3594             g.draw( _quad_curve );
3595         }
3596         else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.CURVED ) {
3597             final float dx = x2 - x1;
3598             final float dy = y2 - y1;
3599             _cubic_curve.setCurve( x1, y1, x1 + ( dx * 0.4f ), y1 + ( dy * 0.2f ), x1 + ( dx * 0.6f ), y1
3600                     + ( dy * 0.8f ), x2, y2 );
3601             g.draw( _cubic_curve );
3602         }
3603         else {
3604             final float x2a = x2;
3605             final float x1a = x1;
3606             float y2_r = 0;
3607             if ( node.isFirstChildNode() || node.isLastChildNode()
3608                     || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE )
3609                     || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) ) {
3610                 if ( !to_graphics_file
3611                         && !to_pdf
3612                         && ( ( ( y2 < ( getVisibleRect().getMinY() - 20 ) ) && ( y1 < ( getVisibleRect().getMinY() - 20 ) ) ) || ( ( y2 > ( getVisibleRect()
3613                                 .getMaxY() + 20 ) ) && ( y1 > ( getVisibleRect().getMaxY() + 20 ) ) ) ) ) {
3614                     // Do nothing.
3615                 }
3616                 else {
3617                     if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
3618                         float x2c = x1 + EURO_D;
3619                         if ( x2c > x2a ) {
3620                             x2c = x2a;
3621                         }
3622                         drawLine( x1, y1, x2c, y2, g );
3623                     }
3624                     else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
3625                         if ( y2 > y1 ) {
3626                             y2_r = y2 - ROUNDED_D;
3627                             if ( y2_r < y1 ) {
3628                                 y2_r = y1;
3629                             }
3630                             drawLine( x1, y1, x1, y2_r, g );
3631                         }
3632                         else {
3633                             y2_r = y2 + ROUNDED_D;
3634                             if ( y2_r > y1 ) {
3635                                 y2_r = y1;
3636                             }
3637                             drawLine( x1, y1, x1, y2_r, g );
3638                         }
3639                     }
3640                     else {
3641                         drawLine( x1, y1, x1, y2, g );
3642                     }
3643                 }
3644             }
3645             // draw the horizontal line
3646             if ( !to_graphics_file && !to_pdf
3647                     && ( ( y2 < ( getVisibleRect().getMinY() - 20 ) ) || ( y2 > ( getVisibleRect().getMaxY() + 20 ) ) ) ) {
3648                 return;
3649             }
3650             float x1_r = 0;
3651             if ( !getControlPanel().isWidthBranches() || ( PhylogenyMethods.getBranchWidthValue( node ) == 1 ) ) {
3652                 if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
3653                     x1_r = x1a + ROUNDED_D;
3654                     if ( x1_r < x2a ) {
3655                         drawLine( x1_r, y2, x2a, y2, g );
3656                     }
3657                 }
3658                 else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
3659                     final float x1c = x1a + EURO_D;
3660                     if ( x1c < x2a ) {
3661                         drawLine( x1c, y2, x2a, y2, g );
3662                     }
3663                 }
3664                 else {
3665                     drawLine( x1a, y2, x2a, y2, g );
3666                 }
3667             }
3668             else {
3669                 final double w = PhylogenyMethods.getBranchWidthValue( node );
3670                 if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
3671                     x1_r = x1a + ROUNDED_D;
3672                     if ( x1_r < x2a ) {
3673                         drawRectFilled( x1_r, y2 - ( w / 2 ), x2a - x1_r, w, g );
3674                     }
3675                 }
3676                 else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
3677                     final float x1c = x1a + EURO_D;
3678                     if ( x1c < x2a ) {
3679                         drawRectFilled( x1c, y2 - ( w / 2 ), x2a - x1c, w, g );
3680                     }
3681                 }
3682                 else {
3683                     drawRectFilled( x1a, y2 - ( w / 2 ), x2a - x1a, w, g );
3684                 }
3685             }
3686             if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) ) {
3687                 if ( x1_r > x2a ) {
3688                     x1_r = x2a;
3689                 }
3690                 if ( y2 > y2_r ) {
3691                     final double diff = y2 - y2_r;
3692                     _arc.setArc( x1, y2_r - diff, 2 * ( x1_r - x1 ), 2 * diff, 180, 90, Arc2D.OPEN );
3693                 }
3694                 else {
3695                     _arc.setArc( x1, y2, 2 * ( x1_r - x1 ), 2 * ( y2_r - y2 ), 90, 90, Arc2D.OPEN );
3696                 }
3697                 g.draw( _arc );
3698             }
3699         }
3700         if ( node.isExternal() ) {
3701             paintNodeBox( x2, y2, node, g, to_pdf, to_graphics_file );
3702         }
3703     }
3704
3705     final private double paintCirculars( final PhylogenyNode n,
3706                                          final Phylogeny phy,
3707                                          final float center_x,
3708                                          final float center_y,
3709                                          final double radius,
3710                                          final boolean radial_labels,
3711                                          final Graphics2D g,
3712                                          final boolean to_pdf,
3713                                          final boolean to_graphics_file ) {
3714         if ( n.isExternal() || n.isCollapse() ) { //~~circ collapse
3715             if ( !_urt_nodeid_angle_map.containsKey( n.getId() ) ) {
3716                 System.out.println( "no " + n + " =====>>>>>>> ERROR!" );//TODO
3717             }
3718             return _urt_nodeid_angle_map.get( n.getId() );
3719         }
3720         else {
3721             final List<PhylogenyNode> descs = n.getDescendants();
3722             double sum = 0;
3723             for( final PhylogenyNode desc : descs ) {
3724                 sum += paintCirculars( desc,
3725                                        phy,
3726                                        center_x,
3727                                        center_y,
3728                                        radius,
3729                                        radial_labels,
3730                                        g,
3731                                        to_pdf,
3732                                        to_graphics_file );
3733             }
3734             double r = 0;
3735             if ( !n.isRoot() ) {
3736                 r = 1 - ( ( ( double ) _circ_max_depth - n.calculateDepth() ) / _circ_max_depth );
3737             }
3738             final double theta = sum / descs.size();
3739             n.setXcoord( ( float ) ( center_x + ( r * radius * Math.cos( theta ) ) ) );
3740             n.setYcoord( ( float ) ( center_y + ( r * radius * Math.sin( theta ) ) ) );
3741             _urt_nodeid_angle_map.put( n.getId(), theta );
3742             for( final PhylogenyNode desc : descs ) {
3743                 paintBranchCircular( n, desc, g, radial_labels, to_pdf, to_graphics_file );
3744             }
3745             return theta;
3746         }
3747     }
3748
3749     final private void paintCircularsLite( final PhylogenyNode n,
3750                                            final Phylogeny phy,
3751                                            final int center_x,
3752                                            final int center_y,
3753                                            final int radius,
3754                                            final Graphics2D g ) {
3755         if ( n.isExternal() ) {
3756             return;
3757         }
3758         else {
3759             final List<PhylogenyNode> descs = n.getDescendants();
3760             for( final PhylogenyNode desc : descs ) {
3761                 paintCircularsLite( desc, phy, center_x, center_y, radius, g );
3762             }
3763             float r = 0;
3764             if ( !n.isRoot() ) {
3765                 r = 1 - ( ( ( float ) _circ_max_depth - n.calculateDepth() ) / _circ_max_depth );
3766             }
3767             final double theta = _urt_nodeid_angle_map.get( n.getId() );
3768             n.setXSecondary( ( float ) ( center_x + ( radius * r * Math.cos( theta ) ) ) );
3769             n.setYSecondary( ( float ) ( center_y + ( radius * r * Math.sin( theta ) ) ) );
3770             for( final PhylogenyNode desc : descs ) {
3771                 paintBranchCircularLite( n, desc, g );
3772             }
3773         }
3774     }
3775
3776     final private void paintCollapsedNode( final Graphics2D g,
3777                                            final PhylogenyNode node,
3778                                            final boolean to_graphics_file,
3779                                            final boolean to_pdf,
3780                                            final boolean is_in_found_nodes ) {
3781         Color c = null;
3782         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
3783             c = Color.BLACK;
3784         }
3785         else if ( is_in_found_nodes ) {
3786             c = getColorForFoundNode( node );
3787         }
3788         else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
3789             c = getTaxonomyBasedColor( node );
3790         }
3791         else if ( getOptions().isColorLabelsSameAsParentBranch() && getControlPanel().isColorBranches()
3792                 && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
3793             c = PhylogenyMethods.getBranchColorValue( node );
3794         }
3795         else {
3796             c = getTreeColorSet().getCollapseFillColor();
3797         }
3798         double d = node.getAllExternalDescendants().size();
3799         if ( d > 1000 ) {
3800             d = ( 3 * _y_distance ) / 3;
3801         }
3802         else {
3803             d = ( Math.log10( d ) * _y_distance ) / 2.5;
3804         }
3805         final int box_size = getOptions().getDefaultNodeShapeSize() + 1;
3806         if ( d < box_size ) {
3807             d = box_size;
3808         }
3809         final float xx = node.getXcoord() - ( 2 * box_size );
3810         final float xxx = xx > node.getParent().getXcoord() + 1 ? xx : node.getParent().getXcoord() + 1;
3811         _polygon.reset();
3812         _polygon.moveTo( xxx, node.getYcoord() );
3813         _polygon.lineTo( node.getXcoord() + 1, node.getYcoord() - d );
3814         _polygon.lineTo( node.getXcoord() + 1, node.getYcoord() + d );
3815         _polygon.closePath();
3816         if ( getOptions().getDefaultNodeFill() == NodeVisualization.NodeFill.SOLID ) {
3817             g.setColor( c );
3818             g.fill( _polygon );
3819         }
3820         else if ( getOptions().getDefaultNodeFill() == NodeVisualization.NodeFill.NONE ) {
3821             g.setColor( getBackground() );
3822             g.fill( _polygon );
3823             g.setColor( c );
3824             g.draw( _polygon );
3825         }
3826         else if ( getOptions().getDefaultNodeFill() == NodeFill.GRADIENT ) {
3827             g.setPaint( new GradientPaint( xxx, node.getYcoord(), getBackground(), node.getXcoord(), ( float ) ( node
3828                     .getYcoord() - d ), c, false ) );
3829             g.fill( _polygon );
3830             g.setPaint( c );
3831             g.draw( _polygon );
3832         }
3833         paintNodeData( g, node, to_graphics_file, to_pdf, is_in_found_nodes );
3834     }
3835
3836     final private void paintConfidenceValues( final Graphics2D g,
3837                                               final PhylogenyNode node,
3838                                               final boolean to_pdf,
3839                                               final boolean to_graphics_file ) {
3840         final List<Confidence> confidences = node.getBranchData().getConfidences();
3841         boolean not_first = false;
3842         Collections.sort( confidences );
3843         final StringBuilder sb = new StringBuilder();
3844         for( final Confidence confidence : confidences ) {
3845             final double value = confidence.getValue();
3846             if ( value != Confidence.CONFIDENCE_DEFAULT_VALUE ) {
3847                 if ( value < getOptions().getMinConfidenceValue() ) {
3848                     return;
3849                 }
3850                 if ( not_first ) {
3851                     sb.append( "/" );
3852                 }
3853                 else {
3854                     not_first = true;
3855                 }
3856                 sb.append( FORMATTER_CONFIDENCE.format( ForesterUtil.round( value, getOptions()
3857                         .getNumberOfDigitsAfterCommaForConfidenceValues() ) ) );
3858                 if ( getOptions().isShowConfidenceStddev() ) {
3859                     if ( confidence.getStandardDeviation() != Confidence.CONFIDENCE_DEFAULT_VALUE ) {
3860                         sb.append( "(" );
3861                         sb.append( FORMATTER_CONFIDENCE.format( ForesterUtil.round( confidence.getStandardDeviation(),
3862                                                                                     getOptions()
3863                                                                                             .getNumberOfDigitsAfterCommaForConfidenceValues() ) ) );
3864                         sb.append( ")" );
3865                     }
3866                 }
3867             }
3868         }
3869         if ( sb.length() > 0 ) {
3870             final double parent_x = node.getParent().getXcoord();
3871             double x = node.getXcoord();
3872             g.setFont( getTreeFontSet().getSmallFont() );
3873             if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) {
3874                 x += EURO_D;
3875             }
3876             else if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) {
3877                 x += ROUNDED_D;
3878             }
3879             if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
3880                 g.setColor( Color.BLACK );
3881             }
3882             else {
3883                 g.setColor( getTreeColorSet().getConfidenceColor() );
3884             }
3885             final String conf_str = sb.toString();
3886             TreePanel
3887                     .drawString( conf_str,
3888                                  parent_x
3889                                          + ( ( x - parent_x - getTreeFontSet()._fm_small.stringWidth( conf_str ) ) / 2 ),
3890                                  ( node.getYcoord() + getTreeFontSet()._small_max_ascent ) - 1,
3891                                  g );
3892         }
3893     }
3894
3895     final private void paintGainedAndLostCharacters( final Graphics2D g,
3896                                                      final PhylogenyNode node,
3897                                                      final String gained,
3898                                                      final String lost ) {
3899         if ( node.getParent() != null ) {
3900             final double parent_x = node.getParent().getXcoord();
3901             final double x = node.getXcoord();
3902             g.setFont( getTreeFontSet().getLargeFont() );
3903             g.setColor( getTreeColorSet().getGainedCharactersColor() );
3904             if ( Constants.SPECIAL_CUSTOM ) {
3905                 g.setColor( Color.BLUE );
3906             }
3907             TreePanel
3908                     .drawString( gained,
3909                                  parent_x + ( ( x - parent_x - getTreeFontSet()._fm_large.stringWidth( gained ) ) / 2 ),
3910                                  ( node.getYcoord() - getTreeFontSet()._fm_large.getMaxDescent() ),
3911                                  g );
3912             g.setColor( getTreeColorSet().getLostCharactersColor() );
3913             TreePanel.drawString( lost,
3914                                   parent_x + ( ( x - parent_x - getTreeFontSet()._fm_large.stringWidth( lost ) ) / 2 ),
3915                                   ( node.getYcoord() + getTreeFontSet()._fm_large.getMaxAscent() ),
3916                                   g );
3917         }
3918     }
3919
3920     /**
3921      * Draw a box at the indicated node.
3922      * 
3923      * @param x
3924      * @param y
3925      * @param node
3926      * @param g
3927      */
3928     final private void paintNodeBox( final double x,
3929                                      final double y,
3930                                      final PhylogenyNode node,
3931                                      final Graphics2D g,
3932                                      final boolean to_pdf,
3933                                      final boolean to_graphics_file ) {
3934         if ( node.isCollapse() ) {
3935             return;
3936         }
3937         // if this node should be highlighted, do so
3938         if ( ( _highlight_node == node ) && !to_pdf && !to_graphics_file ) {
3939             g.setColor( getTreeColorSet().getFoundColor0() );
3940             drawOval( x - 8, y - 8, 16, 16, g );
3941             drawOval( x - 9, y - 8, 17, 17, g );
3942             drawOval( x - 9, y - 9, 18, 18, g );
3943         }
3944         if ( ( isInFoundNodes( node ) || isInCurrentExternalNodes( node ) )
3945                 || ( getOptions().isShowDefaultNodeShapesExternal() && node.isExternal() )
3946                 || ( getOptions().isShowDefaultNodeShapesInternal() && node.isInternal() )
3947                 || ( getControlPanel().isEvents() && node.isHasAssignedEvent() && ( node.getNodeData().getEvent()
3948                         .isDuplication()
3949                         || node.getNodeData().getEvent().isSpeciation() || node.getNodeData().getEvent()
3950                         .isSpeciationOrDuplication() ) ) ) {
3951             final double box_size = getOptions().getDefaultNodeShapeSize();
3952             final double half_box_size = box_size / 2.0;
3953             Color outline_color = null;
3954             if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
3955                 outline_color = Color.BLACK;
3956             }
3957             else if ( isInFoundNodes( node ) || isInCurrentExternalNodes( node ) ) {
3958                 outline_color = getColorForFoundNode( node );
3959             }
3960             else if ( getControlPanel().isEvents() && TreePanelUtil.isHasAssignedEvent( node ) ) {
3961                 final Event event = node.getNodeData().getEvent();
3962                 if ( event.isDuplication() ) {
3963                     outline_color = getTreeColorSet().getDuplicationBoxColor();
3964                 }
3965                 else if ( event.isSpeciation() ) {
3966                     outline_color = getTreeColorSet().getSpecBoxColor();
3967                 }
3968                 else if ( event.isSpeciationOrDuplication() ) {
3969                     outline_color = getTreeColorSet().getDuplicationOrSpeciationColor();
3970                 }
3971             }
3972             else {
3973                 outline_color = getGraphicsForNodeBoxWithColorForParentBranch( node );
3974                 if ( to_pdf && ( outline_color == getTreeColorSet().getBranchColor() ) ) {
3975                     outline_color = getTreeColorSet().getBranchColorForPdf();
3976                 }
3977             }
3978             if ( getOptions().getDefaultNodeShape() == NodeShape.CIRCLE ) {
3979                 if ( getOptions().getDefaultNodeFill() == NodeFill.GRADIENT ) {
3980                     drawOvalGradient( x - half_box_size, y - half_box_size, box_size, box_size, g, to_pdf ? Color.WHITE
3981                             : outline_color, to_pdf ? outline_color : getBackground(), outline_color );
3982                 }
3983                 else if ( getOptions().getDefaultNodeFill() == NodeFill.NONE ) {
3984                     Color background = getBackground();
3985                     if ( to_pdf ) {
3986                         background = Color.WHITE;
3987                     }
3988                     drawOvalGradient( x - half_box_size,
3989                                       y - half_box_size,
3990                                       box_size,
3991                                       box_size,
3992                                       g,
3993                                       background,
3994                                       background,
3995                                       outline_color );
3996                 }
3997                 else if ( getOptions().getDefaultNodeFill() == NodeVisualization.NodeFill.SOLID ) {
3998                     g.setColor( outline_color );
3999                     drawOvalFilled( x - half_box_size, y - half_box_size, box_size, box_size, g );
4000                 }
4001             }
4002             else if ( getOptions().getDefaultNodeShape() == NodeVisualization.NodeShape.RECTANGLE ) {
4003                 if ( getOptions().getDefaultNodeFill() == NodeVisualization.NodeFill.GRADIENT ) {
4004                     drawRectGradient( x - half_box_size, y - half_box_size, box_size, box_size, g, to_pdf ? Color.WHITE
4005                             : outline_color, to_pdf ? outline_color : getBackground(), outline_color );
4006                 }
4007                 else if ( getOptions().getDefaultNodeFill() == NodeVisualization.NodeFill.NONE ) {
4008                     Color background = getBackground();
4009                     if ( to_pdf ) {
4010                         background = Color.WHITE;
4011                     }
4012                     drawRectGradient( x - half_box_size,
4013                                       y - half_box_size,
4014                                       box_size,
4015                                       box_size,
4016                                       g,
4017                                       background,
4018                                       background,
4019                                       outline_color );
4020                 }
4021                 else if ( getOptions().getDefaultNodeFill() == NodeVisualization.NodeFill.SOLID ) {
4022                     g.setColor( outline_color );
4023                     drawRectFilled( x - half_box_size, y - half_box_size, box_size, box_size, g );
4024                 }
4025             }
4026         }
4027     }
4028
4029     final private void paintNodeData( final Graphics2D g,
4030                                       final PhylogenyNode node,
4031                                       final boolean to_graphics_file,
4032                                       final boolean to_pdf,
4033                                       final boolean is_in_found_nodes ) {
4034         if ( isNodeDataInvisible( node ) && !to_graphics_file && !to_pdf ) {
4035             return;
4036         }
4037         if ( getOptions().isShowBranchLengthValues()
4038                 && ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR )
4039                         || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) )
4040                 && ( !node.isRoot() ) && ( node.getDistanceToParent() != PhylogenyDataUtil.BRANCH_LENGTH_DEFAULT ) ) {
4041             paintBranchLength( g, node, to_pdf, to_graphics_file );
4042         }
4043         if ( !getControlPanel().isShowInternalData() && !node.isExternal() && !node.isCollapse() ) {
4044             return;
4045         }
4046         _sb.setLength( 0 );
4047         int x = 0;
4048         final int half_box_size = getOptions().getDefaultNodeShapeSize() / 2;
4049         if ( getControlPanel().isShowTaxonomyImages()
4050                 && ( getImageMap() != null )
4051                 && !getImageMap().isEmpty()
4052                 && node.getNodeData().isHasTaxonomy()
4053                 && ( ( node.getNodeData().getTaxonomy().getUris() != null ) && !node.getNodeData().getTaxonomy()
4054                         .getUris().isEmpty() ) ) {
4055             x += drawTaxonomyImage( node.getXcoord() + 2 + half_box_size, node.getYcoord(), node, g );
4056         }
4057         if ( ( getControlPanel().isShowTaxonomyCode() || getControlPanel().isShowTaxonomyScientificNames() || getControlPanel()
4058                 .isShowTaxonomyCommonNames() ) && node.getNodeData().isHasTaxonomy() ) {
4059             x += paintTaxonomy( g, node, is_in_found_nodes, to_pdf, to_graphics_file, x );
4060         }
4061         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
4062             g.setColor( Color.BLACK );
4063         }
4064         else if ( is_in_found_nodes ) {
4065             g.setColor( getColorForFoundNode( node ) );
4066         }
4067         else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
4068             g.setColor( getTaxonomyBasedColor( node ) );
4069         }
4070         else if ( getControlPanel().isColorAccordingToAnnotation()
4071                 && ( node.getNodeData().isHasSequence() && ( node.getNodeData().getSequence().getAnnotations() != null ) && ( !node
4072                         .getNodeData().getSequence().getAnnotations().isEmpty() ) ) ) {
4073             g.setColor( calculateColorForAnnotation( node.getNodeData().getSequence().getAnnotations() ) );
4074         }
4075         else if ( getOptions().isColorLabelsSameAsParentBranch() && getControlPanel().isColorBranches()
4076                 && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
4077             g.setColor( PhylogenyMethods.getBranchColorValue( node ) );
4078         }
4079         else if ( to_pdf ) {
4080             g.setColor( Color.BLACK );
4081         }
4082         else {
4083             g.setColor( getTreeColorSet().getSequenceColor() );
4084         }
4085         if ( node.isCollapse() && ( ( !node.isRoot() && !node.getParent().isCollapse() ) || node.isRoot() ) ) {
4086             if ( _sb.length() > 0 ) {
4087                 _sb.setLength( 0 );
4088                 _sb.append( "(" );
4089                 _sb.append( node.getAllExternalDescendants().size() );
4090                 _sb.append( ")" );
4091             }
4092         }
4093         else {
4094             _sb.setLength( 0 );
4095         }
4096         if ( getControlPanel().isShowNodeNames() && ( node.getName().length() > 0 ) ) {
4097             if ( _sb.length() > 0 ) {
4098                 _sb.append( " " );
4099             }
4100             _sb.append( node.getName() );
4101         }
4102         if ( node.getNodeData().isHasSequence() ) {
4103             if ( getControlPanel().isShowSeqSymbols() && ( node.getNodeData().getSequence().getSymbol().length() > 0 ) ) {
4104                 if ( _sb.length() > 0 ) {
4105                     _sb.append( " " );
4106                 }
4107                 _sb.append( node.getNodeData().getSequence().getSymbol() );
4108             }
4109             if ( getControlPanel().isShowGeneNames() && ( node.getNodeData().getSequence().getGeneName().length() > 0 ) ) {
4110                 if ( _sb.length() > 0 ) {
4111                     _sb.append( " " );
4112                 }
4113                 _sb.append( node.getNodeData().getSequence().getGeneName() );
4114             }
4115             if ( getControlPanel().isShowSeqNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
4116                 if ( _sb.length() > 0 ) {
4117                     _sb.append( " " );
4118                 }
4119                 _sb.append( node.getNodeData().getSequence().getName() );
4120             }
4121             if ( getControlPanel().isShowSequenceAcc() && ( node.getNodeData().getSequence().getAccession() != null ) ) {
4122                 if ( _sb.length() > 0 ) {
4123                     _sb.append( " " );
4124                 }
4125                 if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().getSource() ) ) {
4126                     _sb.append( node.getNodeData().getSequence().getAccession().getSource() );
4127                     _sb.append( ":" );
4128                 }
4129                 _sb.append( node.getNodeData().getSequence().getAccession().getValue() );
4130             }
4131         }
4132         if ( getControlPanel().isShowProperties() && node.getNodeData().isHasProperties() ) {
4133             if ( _sb.length() > 0 ) {
4134                 _sb.append( " " );
4135             }
4136             _sb.append( propertiesToString( node ) );
4137         }
4138         g.setFont( getTreeFontSet().getLargeFont() );
4139         if ( is_in_found_nodes ) {
4140             g.setFont( getTreeFontSet().getLargeFont().deriveFont( Font.BOLD ) );
4141         }
4142         double down_shift_factor = 3.0;
4143         if ( !node.isExternal() && ( node.getNumberOfDescendants() == 1 ) ) {
4144             down_shift_factor = 1;
4145         }
4146         final double pos_x = node.getXcoord() + x + 2 + half_box_size;
4147         final double pos_y = ( node.getYcoord() + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ) );
4148         final String sb_str = _sb.toString();
4149         // GUILHEM_BEG ______________
4150         if ( _control_panel.isShowSequenceRelations() && node.getNodeData().isHasSequence()
4151                 && ( _query_sequence != null ) ) {
4152             int nodeTextBoundsWidth = 0;
4153             if ( sb_str.length() > 0 ) {
4154                 final Rectangle2D node_text_bounds = new TextLayout( sb_str, g.getFont(), _frc ).getBounds(); //would like to remove this 'new', but how...
4155                 nodeTextBoundsWidth = ( int ) node_text_bounds.getWidth();
4156             }
4157             if ( node.getNodeData().getSequence().equals( _query_sequence ) ) {
4158                 if ( nodeTextBoundsWidth > 0 ) { // invert font color and background color to show that this is the query sequence
4159                     g.fillRect( ( int ) pos_x - 1, ( int ) pos_y - 8, nodeTextBoundsWidth + 5, 11 );
4160                     g.setColor( getTreeColorSet().getBackgroundColor() );
4161                 }
4162             }
4163             else {
4164                 final List<SequenceRelation> seqRelations = node.getNodeData().getSequence().getSequenceRelations();
4165                 for( final SequenceRelation seqRelation : seqRelations ) {
4166                     final boolean fGotRelationWithQuery = ( seqRelation.getRef0().isEqual( _query_sequence ) || seqRelation
4167                             .getRef1().isEqual( _query_sequence ) )
4168                             && seqRelation.getType().equals( getControlPanel().getSequenceRelationTypeBox()
4169                                     .getSelectedItem() );
4170                     if ( fGotRelationWithQuery ) { // we will underline the text to show that this sequence is ortholog to the query
4171                         final double linePosX = node.getXcoord() + 2 + half_box_size;
4172                         final String sConfidence = ( !getControlPanel().isShowSequenceRelationConfidence() || ( seqRelation
4173                                 .getConfidence() == null ) ) ? null : " (" + seqRelation.getConfidence().getValue()
4174                                 + ")";
4175                         if ( sConfidence != null ) {
4176                             double confidenceX = pos_x;
4177                             if ( sb_str.length() > 0 ) {
4178                                 confidenceX += new TextLayout( sb_str, g.getFont(), _frc ).getBounds().getWidth()
4179                                         + CONFIDENCE_LEFT_MARGIN;
4180                             }
4181                             if ( confidenceX > linePosX ) { // let's only display confidence value if we are already displaying at least one of Prot/Gene Name and Taxonomy Code 
4182                                 final int confidenceWidth = ( int ) new TextLayout( sConfidence, g.getFont(), _frc )
4183                                         .getBounds().getWidth();
4184                                 TreePanel.drawString( sConfidence, confidenceX, pos_y, g );
4185                                 x += CONFIDENCE_LEFT_MARGIN + confidenceWidth;
4186                             }
4187                         }
4188                         if ( ( x + nodeTextBoundsWidth ) > 0 ) /* we only underline if there is something displayed */
4189                         {
4190                             if ( nodeTextBoundsWidth == 0 ) {
4191                                 nodeTextBoundsWidth -= 3; /* the gap between taxonomy code and node name should not be underlined if nothing comes after it */
4192                             }
4193                             else {
4194                                 nodeTextBoundsWidth += 2;
4195                             }
4196                             g.drawLine( ( int ) linePosX + 1, 3 + ( int ) pos_y, ( int ) linePosX + x
4197                                     + nodeTextBoundsWidth, 3 + ( int ) pos_y );
4198                             break;
4199                         }
4200                     }
4201                 }
4202             }
4203         }
4204         if ( sb_str.length() > 0 ) {
4205             TreePanel.drawString( sb_str, pos_x, pos_y, g );
4206         }
4207         // GUILHEM_END _____________
4208         // COMMENTED_OUT_BY_GUILHEM_BEG _______________
4209         // TODO FIXME need to check this one!
4210         //if ( _sb.length() > 0 ) {
4211         //    TreePanel.drawString( _sb.toString(), node.getXcoord() + x + 2 + TreePanel.HALF_BOX_SIZE, node.getYcoord()
4212         //            + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ), g );
4213         //}
4214         // COMMENTED_OUT_BY_GUILHEM_END ________________
4215         if ( getControlPanel().isShowAnnotation() && node.getNodeData().isHasSequence()
4216                 && ( node.getNodeData().getSequence().getAnnotations() != null )
4217                 && ( !node.getNodeData().getSequence().getAnnotations().isEmpty() ) ) {
4218             if ( _sb.length() > 0 ) {
4219                 x += getTreeFontSet()._fm_large.stringWidth( _sb.toString() ) + 5;
4220             }
4221             final SortedSet<Annotation> ann = node.getNodeData().getSequence().getAnnotations();
4222             if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
4223                 g.setColor( Color.BLACK );
4224             }
4225             else if ( getControlPanel().isColorAccordingToAnnotation() ) {
4226                 g.setColor( calculateColorForAnnotation( ann ) );
4227             }
4228             final String ann_str = TreePanelUtil.createAnnotationString( ann, getOptions().isShowAnnotationRefSource() );
4229             TreePanel.drawString( ann_str, node.getXcoord() + x + 3 + half_box_size, node.getYcoord()
4230                     + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ), g );
4231             _sb.setLength( 0 );
4232             _sb.append( ann_str );
4233         }
4234         if ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR )
4235                 || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE )
4236                 || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED ) ) {
4237             if ( ( getControlPanel().isShowBinaryCharacters() || getControlPanel().isShowBinaryCharacterCounts() )
4238                     && node.getNodeData().isHasBinaryCharacters() ) {
4239                 if ( _sb.length() > 0 ) {
4240                     x += getTreeFontSet()._fm_large.stringWidth( _sb.toString() ) + 5;
4241                 }
4242                 if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
4243                     g.setColor( Color.BLACK );
4244                 }
4245                 else {
4246                     g.setColor( getTreeColorSet().getBinaryDomainCombinationsColor() );
4247                 }
4248                 if ( getControlPanel().isShowBinaryCharacters() ) {
4249                     TreePanel.drawString( node.getNodeData().getBinaryCharacters().getPresentCharactersAsStringBuffer()
4250                             .toString(), node.getXcoord() + x + 1 + half_box_size, node.getYcoord()
4251                             + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ), g );
4252                     paintGainedAndLostCharacters( g, node, node.getNodeData().getBinaryCharacters()
4253                             .getGainedCharactersAsStringBuffer().toString(), node.getNodeData().getBinaryCharacters()
4254                             .getLostCharactersAsStringBuffer().toString() );
4255                 }
4256                 else {
4257                     TreePanel.drawString( " " + node.getNodeData().getBinaryCharacters().getPresentCount(),
4258                                           node.getXcoord() + x + 4 + half_box_size,
4259                                           node.getYcoord()
4260                                                   + ( getTreeFontSet()._fm_large.getAscent() / down_shift_factor ),
4261                                           g );
4262                     paintGainedAndLostCharacters( g, node, "+"
4263                             + node.getNodeData().getBinaryCharacters().getGainedCount(), "-"
4264                             + node.getNodeData().getBinaryCharacters().getLostCount() );
4265                 }
4266             }
4267         }
4268     }
4269
4270     final private void paintNodeDataUnrootedCirc( final Graphics2D g,
4271                                                   final PhylogenyNode node,
4272                                                   final boolean to_pdf,
4273                                                   final boolean to_graphics_file,
4274                                                   final boolean radial_labels,
4275                                                   final double ur_angle,
4276                                                   final boolean is_in_found_nodes ) {
4277         if ( isNodeDataInvisibleUnrootedCirc( node ) && !to_graphics_file && !to_pdf ) {
4278             return;
4279         }
4280         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
4281             g.setColor( Color.BLACK );
4282         }
4283         else if ( is_in_found_nodes ) {
4284             g.setColor( getColorForFoundNode( node ) );
4285         }
4286         else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
4287             g.setColor( getTaxonomyBasedColor( node ) );
4288         }
4289         else if ( getControlPanel().isColorAccordingToAnnotation()
4290                 && ( node.getNodeData().isHasSequence() && ( node.getNodeData().getSequence().getAnnotations() != null ) && ( !node
4291                         .getNodeData().getSequence().getAnnotations().isEmpty() ) ) ) {
4292             g.setColor( calculateColorForAnnotation( node.getNodeData().getSequence().getAnnotations() ) );
4293         }
4294         else {
4295             g.setColor( getTreeColorSet().getSequenceColor() );
4296         }
4297         _sb.setLength( 0 );
4298         _sb.append( " " );
4299         if ( node.getNodeData().isHasTaxonomy()
4300                 && ( getControlPanel().isShowTaxonomyCode() || getControlPanel().isShowTaxonomyScientificNames() || getControlPanel()
4301                         .isShowTaxonomyCommonNames() ) ) {
4302             final Taxonomy taxonomy = node.getNodeData().getTaxonomy();
4303             if ( _control_panel.isShowTaxonomyCode() && !ForesterUtil.isEmpty( taxonomy.getTaxonomyCode() ) ) {
4304                 _sb.append( taxonomy.getTaxonomyCode() );
4305                 _sb.append( " " );
4306             }
4307             if ( _control_panel.isShowTaxonomyScientificNames() && _control_panel.isShowTaxonomyCommonNames() ) {
4308                 if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() )
4309                         && !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
4310                     _sb.append( taxonomy.getScientificName() );
4311                     _sb.append( " (" );
4312                     _sb.append( taxonomy.getCommonName() );
4313                     _sb.append( ") " );
4314                 }
4315                 else if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() ) ) {
4316                     _sb.append( taxonomy.getScientificName() );
4317                     _sb.append( " " );
4318                 }
4319                 else if ( !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
4320                     _sb.append( taxonomy.getCommonName() );
4321                     _sb.append( " " );
4322                 }
4323             }
4324             else if ( _control_panel.isShowTaxonomyScientificNames() ) {
4325                 if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() ) ) {
4326                     _sb.append( taxonomy.getScientificName() );
4327                     _sb.append( " " );
4328                 }
4329             }
4330             else if ( _control_panel.isShowTaxonomyCommonNames() ) {
4331                 if ( !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
4332                     _sb.append( taxonomy.getCommonName() );
4333                     _sb.append( " " );
4334                 }
4335             }
4336         }
4337         if ( node.isCollapse() && ( ( !node.isRoot() && !node.getParent().isCollapse() ) || node.isRoot() ) ) {
4338             _sb.append( " [" );
4339             _sb.append( node.getAllExternalDescendants().size() );
4340             _sb.append( "]" );
4341         }
4342         if ( getControlPanel().isShowNodeNames() && ( node.getName().length() > 0 ) ) {
4343             if ( _sb.length() > 0 ) {
4344                 _sb.append( " " );
4345             }
4346             _sb.append( node.getName() );
4347         }
4348         if ( node.getNodeData().isHasSequence() ) {
4349             if ( getControlPanel().isShowSequenceAcc() && ( node.getNodeData().getSequence().getAccession() != null ) ) {
4350                 if ( _sb.length() > 0 ) {
4351                     _sb.append( " " );
4352                 }
4353                 if ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getAccession().getSource() ) ) {
4354                     _sb.append( node.getNodeData().getSequence().getAccession().getSource() );
4355                     _sb.append( ":" );
4356                 }
4357                 _sb.append( node.getNodeData().getSequence().getAccession().getValue() );
4358             }
4359             if ( getControlPanel().isShowSeqNames() && ( node.getNodeData().getSequence().getName().length() > 0 ) ) {
4360                 if ( _sb.length() > 0 ) {
4361                     _sb.append( " " );
4362                 }
4363                 _sb.append( node.getNodeData().getSequence().getName() );
4364             }
4365         }
4366         g.setFont( getTreeFontSet().getLargeFont() );
4367         if ( is_in_found_nodes ) {
4368             g.setFont( getTreeFontSet().getLargeFont().deriveFont( Font.BOLD ) );
4369         }
4370         if ( _sb.length() > 1 ) {
4371             final String sb_str = _sb.toString();
4372             double m = 0;
4373             if ( _graphics_type == PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) {
4374                 m = _urt_nodeid_angle_map.get( node.getId() ) % TWO_PI;
4375             }
4376             else {
4377                 m = ( float ) ( ur_angle % TWO_PI );
4378             }
4379             _at = g.getTransform();
4380             boolean need_to_reset = false;
4381             final float x_coord = node.getXcoord();
4382             final float y_coord = node.getYcoord() + ( getTreeFontSet()._fm_large.getAscent() / 3.0f );
4383             if ( radial_labels ) {
4384                 need_to_reset = true;
4385                 boolean left = false;
4386                 if ( ( m > HALF_PI ) && ( m < ONEHALF_PI ) ) {
4387                     m -= PI;
4388                     left = true;
4389                 }
4390                 g.rotate( m, x_coord, node.getYcoord() );
4391                 if ( left ) {
4392                     g.translate( -( getTreeFontSet()._fm_large.getStringBounds( sb_str, g ).getWidth() ), 0 );
4393                 }
4394             }
4395             else {
4396                 if ( ( m > HALF_PI ) && ( m < ONEHALF_PI ) ) {
4397                     need_to_reset = true;
4398                     g.translate( -getTreeFontSet()._fm_large.getStringBounds( sb_str, g ).getWidth(), 0 );
4399                 }
4400             }
4401             TreePanel.drawString( sb_str, x_coord, y_coord, g );
4402             if ( need_to_reset ) {
4403                 g.setTransform( _at );
4404             }
4405         }
4406     }
4407
4408     final private void paintNodeLite( final Graphics2D g, final PhylogenyNode node ) {
4409         if ( node.isCollapse() ) {
4410             if ( !node.isRoot() && !node.getParent().isCollapse() ) {
4411                 paintCollapsedNode( g, node, false, false, false );
4412             }
4413             return;
4414         }
4415         if ( isInFoundNodes( node ) || isInCurrentExternalNodes( node ) ) {
4416             g.setColor( getColorForFoundNode( node ) );
4417             drawRectFilled( node.getXSecondary() - OVERVIEW_FOUND_NODE_BOX_SIZE_HALF, node.getYSecondary()
4418                     - OVERVIEW_FOUND_NODE_BOX_SIZE_HALF, OVERVIEW_FOUND_NODE_BOX_SIZE, OVERVIEW_FOUND_NODE_BOX_SIZE, g );
4419         }
4420         float new_x = 0;
4421         if ( !node.isExternal() && !node.isCollapse() ) {
4422             boolean first_child = true;
4423             float y2 = 0.0f;
4424             final int parent_max_branch_to_leaf = getMaxBranchesToLeaf( node );
4425             for( int i = 0; i < node.getNumberOfDescendants(); ++i ) {
4426                 final PhylogenyNode child_node = node.getChildNode( i );
4427                 int factor_x;
4428                 if ( !isUniformBranchLengthsForCladogram() ) {
4429                     factor_x = node.getNumberOfExternalNodes() - child_node.getNumberOfExternalNodes();
4430                 }
4431                 else {
4432                     factor_x = parent_max_branch_to_leaf - getMaxBranchesToLeaf( child_node );
4433                 }
4434                 if ( first_child ) {
4435                     first_child = false;
4436                     y2 = node.getYSecondary()
4437                             - ( getOvYDistance() * ( node.getNumberOfExternalNodes() - child_node
4438                                     .getNumberOfExternalNodes() ) );
4439                 }
4440                 else {
4441                     y2 += getOvYDistance() * child_node.getNumberOfExternalNodes();
4442                 }
4443                 final float x2 = calculateOvBranchLengthToParent( child_node, factor_x );
4444                 new_x = x2 + node.getXSecondary();
4445                 final float diff_y = node.getYSecondary() - y2;
4446                 final float diff_x = node.getXSecondary() - new_x;
4447                 if ( ( diff_y > 2 ) || ( diff_y < -2 ) || ( diff_x > 2 ) || ( diff_x < -2 ) ) {
4448                     paintBranchLite( g, node.getXSecondary(), new_x, node.getYSecondary(), y2, child_node );
4449                 }
4450                 child_node.setXSecondary( new_x );
4451                 child_node.setYSecondary( y2 );
4452                 y2 += getOvYDistance() * child_node.getNumberOfExternalNodes();
4453             }
4454         }
4455     }
4456
4457     final private void paintNodeRectangular( final Graphics2D g,
4458                                              final PhylogenyNode node,
4459                                              final boolean to_pdf,
4460                                              final boolean dynamically_hide,
4461                                              final int dynamic_hiding_factor,
4462                                              final boolean to_graphics_file ) {
4463         final boolean is_in_found_nodes = isInFoundNodes( node ) || isInCurrentExternalNodes( node );
4464         if ( node.isCollapse() ) {
4465             if ( ( !node.isRoot() && !node.getParent().isCollapse() ) ) {
4466                 paintCollapsedNode( g, node, to_graphics_file, to_pdf, is_in_found_nodes );
4467             }
4468             return;
4469         }
4470         if ( node.isExternal() ) {
4471             ++_external_node_index;
4472         }
4473         // Confidence values
4474         if ( getControlPanel().isShowConfidenceValues()
4475                 && !node.isExternal()
4476                 && !node.isRoot()
4477                 && ( ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.ROUNDED )
4478                         || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR ) || ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE ) )
4479                 && node.getBranchData().isHasConfidences() ) {
4480             paintConfidenceValues( g, node, to_pdf, to_graphics_file );
4481         }
4482         // Draw a line to root:
4483         if ( node.isRoot() && _phylogeny.isRooted() ) {
4484             paintRootBranch( g, node.getXcoord(), node.getYcoord(), node, to_pdf, to_graphics_file );
4485         }
4486         float new_x = 0;
4487         float new_x_min = Float.MAX_VALUE;
4488         final boolean disallow_shortcutting = dynamic_hiding_factor < 40;
4489         float min_dist = 1.5f;
4490         if ( !disallow_shortcutting ) {
4491             //   System.out.println( dynamic_hiding_factor );
4492             if ( dynamic_hiding_factor > 4000 ) {
4493                 min_dist = 4;
4494             }
4495             else if ( dynamic_hiding_factor > 1000 ) {
4496                 min_dist = 3;
4497             }
4498             else if ( dynamic_hiding_factor > 100 ) {
4499                 min_dist = 2;
4500             }
4501         }
4502         if ( !node.isExternal() && !node.isCollapse() ) {
4503             boolean first_child = true;
4504             float y2 = 0.0f;
4505             final int parent_max_branch_to_leaf = getMaxBranchesToLeaf( node );
4506             for( int i = 0; i < node.getNumberOfDescendants(); ++i ) {
4507                 final PhylogenyNode child_node = node.getChildNode( i );
4508                 int factor_x;
4509                 if ( !isUniformBranchLengthsForCladogram() ) {
4510                     factor_x = node.getNumberOfExternalNodes() - child_node.getNumberOfExternalNodes();
4511                 }
4512                 else {
4513                     factor_x = parent_max_branch_to_leaf - getMaxBranchesToLeaf( child_node );
4514                 }
4515                 if ( first_child ) {
4516                     first_child = false;
4517                     y2 = node.getYcoord()
4518                             - ( _y_distance * ( node.getNumberOfExternalNodes() - child_node.getNumberOfExternalNodes() ) );
4519                 }
4520                 else {
4521                     y2 += _y_distance * child_node.getNumberOfExternalNodes();
4522                 }
4523                 final float x2 = calculateBranchLengthToParent( child_node, factor_x );
4524                 new_x = x2 + node.getXcoord();
4525                 if ( dynamically_hide && ( x2 < new_x_min ) ) {
4526                     new_x_min = x2;
4527                 }
4528                 final float diff_y = node.getYcoord() - y2;
4529                 final float diff_x = node.getXcoord() - new_x;
4530                 if ( disallow_shortcutting || ( diff_y > min_dist ) || ( diff_y < -min_dist ) || ( diff_x > min_dist )
4531                         || ( diff_x < -min_dist ) || to_graphics_file || to_pdf ) {
4532                     paintBranchRectangular( g,
4533                                             node.getXcoord(),
4534                                             new_x,
4535                                             node.getYcoord(),
4536                                             y2,
4537                                             child_node,
4538                                             to_pdf,
4539                                             to_graphics_file );
4540                 }
4541                 child_node.setXcoord( new_x );
4542                 child_node.setYcoord( y2 );
4543                 y2 += _y_distance * child_node.getNumberOfExternalNodes();
4544             }
4545             paintNodeBox( node.getXcoord(), node.getYcoord(), node, g, to_pdf, to_graphics_file );
4546         }
4547         if ( dynamically_hide
4548                 && !is_in_found_nodes
4549                 && ( ( node.isExternal() && ( ( _external_node_index % dynamic_hiding_factor ) != 1 ) ) || ( !node
4550                         .isExternal() && ( ( new_x_min < 20 ) || ( ( _y_distance * node.getNumberOfExternalNodes() ) < getTreeFontSet()._fm_large
4551                         .getHeight() ) ) ) ) ) {
4552             return;
4553         }
4554         paintNodeData( g, node, to_graphics_file, to_pdf, is_in_found_nodes );
4555         paintNodeWithRenderableData( g, node, to_graphics_file, to_pdf );
4556     }
4557
4558     final private void paintNodeWithRenderableData( final Graphics2D g,
4559                                                     final PhylogenyNode node,
4560                                                     final boolean to_graphics_file,
4561                                                     final boolean to_pdf ) {
4562         if ( isNodeDataInvisible( node ) && !to_graphics_file ) {
4563             return;
4564         }
4565         if ( ( !getControlPanel().isShowInternalData() && !node.isExternal() ) ) {
4566             return;
4567         }
4568         if ( getControlPanel().isShowDomainArchitectures() && node.getNodeData().isHasSequence()
4569                 && ( node.getNodeData().getSequence().getDomainArchitecture() != null ) ) {
4570             RenderableDomainArchitecture rds = null;
4571             if ( node.getNodeData().getSequence().getDomainArchitecture() instanceof RenderableDomainArchitecture ) {
4572                 try {
4573                     rds = ( RenderableDomainArchitecture ) node.getNodeData().getSequence().getDomainArchitecture();
4574                 }
4575                 catch ( final ClassCastException cce ) {
4576                     cce.printStackTrace();
4577                 }
4578                 if ( rds != null ) {
4579                     rds.setRenderingHeight( 6 );
4580                     int x = 0;
4581                     if ( node.getNodeData().isHasTaxonomy() ) {
4582                         if ( getControlPanel().isShowTaxonomyCode()
4583                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getTaxonomyCode() ) ) ) {
4584                             x += getTreeFontSet()._fm_large_italic.stringWidth( node.getNodeData().getTaxonomy()
4585                                     .getTaxonomyCode()
4586                                     + " " );
4587                         }
4588                         if ( getControlPanel().isShowTaxonomyScientificNames()
4589                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getScientificName() ) ) ) {
4590                             x += getTreeFontSet()._fm_large_italic.stringWidth( node.getNodeData().getTaxonomy()
4591                                     .getScientificName()
4592                                     + " " );
4593                         }
4594                         if ( getControlPanel().isShowTaxonomyCommonNames()
4595                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getTaxonomy().getCommonName() ) ) ) {
4596                             x += getTreeFontSet()._fm_large_italic.stringWidth( node.getNodeData().getTaxonomy()
4597                                     .getCommonName()
4598                                     + " " );
4599                         }
4600                     }
4601                     if ( node.getNodeData().isHasSequence() ) {
4602                         if ( getControlPanel().isShowSeqNames()
4603                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getName() ) ) ) {
4604                             x += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getName()
4605                                     + " " );
4606                         }
4607                         if ( getControlPanel().isShowSeqSymbols()
4608                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getSymbol() ) ) ) {
4609                             x += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getSymbol()
4610                                     + " " );
4611                         }
4612                         if ( getControlPanel().isShowGeneNames()
4613                                 && ( !ForesterUtil.isEmpty( node.getNodeData().getSequence().getGeneName() ) ) ) {
4614                             x += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence().getGeneName()
4615                                     + " " );
4616                         }
4617                         if ( getControlPanel().isShowSequenceAcc()
4618                                 && ( node.getNodeData().getSequence().getAccession() != null ) ) {
4619                             x += getTreeFontSet()._fm_large.stringWidth( node.getNodeData().getSequence()
4620                                     .getAccession().toString()
4621                                     + " " );
4622                         }
4623                         if ( getControlPanel().isShowAnnotation()
4624                                 && ( node.getNodeData().getSequence().getAnnotations() != null )
4625                                 && ( !node.getNodeData().getSequence().getAnnotations().isEmpty() ) ) {
4626                             x += getTreeFontSet()._fm_large.stringWidth( TreePanelUtil.createAnnotationString( node
4627                                     .getNodeData().getSequence().getAnnotations(), getOptions()
4628                                     .isShowAnnotationRefSource() )
4629                                     + " " );
4630                         }
4631                     }
4632                     if ( getControlPanel().isShowNodeNames() && !ForesterUtil.isEmpty( node.getName() ) ) {
4633                         x += getTreeFontSet()._fm_large.stringWidth( node.getName() + " " );
4634                     }
4635                     rds.render( node.getXcoord() + x, node.getYcoord() - 3, g, this, to_pdf );
4636                 }
4637             }
4638         }
4639         //////////////
4640         if ( getControlPanel().isShowVectorData() && ( node.getNodeData().getVector() != null )
4641                 && ( node.getNodeData().getVector().size() > 0 ) && ( getStatisticsForExpressionValues() != null ) ) {
4642             final RenderableVector rv = RenderableVector.createInstance( node.getNodeData().getVector(),
4643                                                                          getStatisticsForExpressionValues(),
4644                                                                          getConfiguration() );
4645             if ( rv != null ) {
4646                 int x = 0;
4647                 PhylogenyNode my_node = node;
4648                 if ( !getControlPanel().isDrawPhylogram() ) {
4649                     my_node = getPhylogeny().getFirstExternalNode();
4650                 }
4651                 if ( getControlPanel().isShowTaxonomyCode() && ( PhylogenyMethods.getSpecies( my_node ).length() > 0 ) ) {
4652                     x += getTreeFontSet()._fm_large_italic.stringWidth( PhylogenyMethods.getSpecies( my_node ) + " " );
4653                 }
4654                 if ( getControlPanel().isShowNodeNames() && ( my_node.getName().length() > 0 ) ) {
4655                     x += getTreeFontSet()._fm_large.stringWidth( my_node.getName() + " " );
4656                 }
4657                 rv.render( my_node.getXcoord() + x, node.getYcoord() - 5, g, this, to_pdf );
4658             }
4659         }
4660         //////////////
4661     }
4662
4663     final private void paintOvRectangle( final Graphics2D g ) {
4664         final float w_ratio = ( ( float ) getWidth() ) / getVisibleRect().width;
4665         final float h_ratio = ( ( float ) getHeight() ) / getVisibleRect().height;
4666         final float x_ratio = ( ( float ) getWidth() ) / getVisibleRect().x;
4667         final float y_ratio = ( ( float ) getHeight() ) / getVisibleRect().y;
4668         final float width = getOvMaxWidth() / w_ratio;
4669         final float height = getOvMaxHeight() / h_ratio;
4670         final float x = getVisibleRect().x + getOvXPosition() + ( getOvMaxWidth() / x_ratio );
4671         final float y = getVisibleRect().y + getOvYPosition() + ( getOvMaxHeight() / y_ratio );
4672         g.setColor( getTreeColorSet().getFoundColor0() );
4673         getOvRectangle().setRect( x, y, width, height );
4674         final Stroke s = g.getStroke();
4675         g.setStroke( STROKE_1 );
4676         if ( ( width < 6 ) && ( height < 6 ) ) {
4677             drawRectFilled( x, y, 6, 6, g );
4678             getOvVirtualRectangle().setRect( x, y, 6, 6 );
4679         }
4680         else if ( width < 6 ) {
4681             drawRectFilled( x, y, 6, height, g );
4682             getOvVirtualRectangle().setRect( x, y, 6, height );
4683         }
4684         else if ( height < 6 ) {
4685             drawRectFilled( x, y, width, 6, g );
4686             getOvVirtualRectangle().setRect( x, y, width, 6 );
4687         }
4688         else {
4689             drawRect( x, y, width, height, g );
4690             if ( isInOvRect() ) {
4691                 drawRect( x + 1, y + 1, width - 2, height - 2, g );
4692             }
4693             getOvVirtualRectangle().setRect( x, y, width, height );
4694         }
4695         g.setStroke( s );
4696     }
4697
4698     final private void paintPhylogenyLite( final Graphics2D g ) {
4699         _phylogeny
4700                 .getRoot()
4701                 .setXSecondary( ( float ) ( getVisibleRect().x + getOvXPosition() + ( MOVE / ( getVisibleRect().width / getOvRectangle()
4702                         .getWidth() ) ) ) );
4703         _phylogeny.getRoot().setYSecondary( ( getVisibleRect().y + getOvYStart() ) );
4704         final Stroke s = g.getStroke();
4705         g.setStroke( STROKE_05 );
4706         for( final PhylogenyNode element : _nodes_in_preorder ) {
4707             paintNodeLite( g, element );
4708         }
4709         g.setStroke( s );
4710         paintOvRectangle( g );
4711     }
4712
4713     /**
4714      * Paint the root branch. (Differs from others because it will always be a
4715      * single horizontal line).
4716      * @param to_graphics_file 
4717      * 
4718      * @return new x1 value
4719      */
4720     final private void paintRootBranch( final Graphics2D g,
4721                                         final float x1,
4722                                         final float y1,
4723                                         final PhylogenyNode root,
4724                                         final boolean to_pdf,
4725                                         final boolean to_graphics_file ) {
4726         assignGraphicsForBranchWithColorForParentBranch( root, false, g, to_pdf, to_graphics_file );
4727         float d = getXdistance();
4728         if ( getControlPanel().isDrawPhylogram() && ( root.getDistanceToParent() > 0.0 ) ) {
4729             d = ( float ) ( getXcorrectionFactor() * root.getDistanceToParent() );
4730         }
4731         if ( d < MIN_ROOT_LENGTH ) {
4732             d = MIN_ROOT_LENGTH;
4733         }
4734         if ( !getControlPanel().isWidthBranches() || ( PhylogenyMethods.getBranchWidthValue( root ) == 1 ) ) {
4735             drawLine( x1 - d, root.getYcoord(), x1, root.getYcoord(), g );
4736         }
4737         else {
4738             final double w = PhylogenyMethods.getBranchWidthValue( root );
4739             drawRectFilled( x1 - d, root.getYcoord() - ( w / 2 ), d, w, g );
4740         }
4741         paintNodeBox( x1, root.getYcoord(), root, g, to_pdf, to_graphics_file );
4742     }
4743
4744     final private void paintScale( final Graphics2D g,
4745                                    int x1,
4746                                    int y1,
4747                                    final boolean to_pdf,
4748                                    final boolean to_graphics_file ) {
4749         x1 += MOVE;
4750         final double x2 = x1 + ( getScaleDistance() * getXcorrectionFactor() );
4751         y1 -= 12;
4752         final int y2 = y1 - 8;
4753         final int y3 = y1 - 4;
4754         g.setFont( getTreeFontSet().getSmallFont() );
4755         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
4756             g.setColor( Color.BLACK );
4757         }
4758         else {
4759             g.setColor( getTreeColorSet().getBranchLengthColor() );
4760         }
4761         final Stroke s = g.getStroke();
4762         g.setStroke( STROKE_1 );
4763         drawLine( x1, y1, x1, y2, g );
4764         drawLine( x2, y1, x2, y2, g );
4765         drawLine( x1, y3, x2, y3, g );
4766         if ( getScaleLabel() != null ) {
4767             g.drawString( getScaleLabel(), ( x1 + 2 ), y3 - 2 );
4768         }
4769         g.setStroke( s );
4770     }
4771
4772     final private int paintTaxonomy( final Graphics2D g,
4773                                      final PhylogenyNode node,
4774                                      final boolean is_in_found_nodes,
4775                                      final boolean to_pdf,
4776                                      final boolean to_graphics_file,
4777                                      final double x_shift ) {
4778         final Taxonomy taxonomy = node.getNodeData().getTaxonomy();
4779         g.setFont( getTreeFontSet().getLargeItalicFont() );
4780         if ( ( to_pdf || to_graphics_file ) && getOptions().isPrintBlackAndWhite() ) {
4781             g.setColor( Color.BLACK );
4782         }
4783         else if ( is_in_found_nodes ) {
4784             g.setFont( getTreeFontSet().getLargeItalicFont().deriveFont( TreeFontSet.BOLD_AND_ITALIC ) );
4785             g.setColor( getColorForFoundNode( node ) );
4786         }
4787         else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
4788             g.setColor( getTaxonomyBasedColor( node ) );
4789         }
4790         else if ( getOptions().isColorLabelsSameAsParentBranch() && getControlPanel().isColorBranches()
4791                 && ( PhylogenyMethods.getBranchColorValue( node ) != null ) ) {
4792             g.setColor( PhylogenyMethods.getBranchColorValue( node ) );
4793         }
4794         else if ( to_pdf ) {
4795             g.setColor( Color.BLACK );
4796         }
4797         else {
4798             g.setColor( getTreeColorSet().getTaxonomyColor() );
4799         }
4800         final double start_x = node.getXcoord() + 3 + ( getOptions().getDefaultNodeShapeSize() / 2 ) + x_shift;
4801         final double start_y = node.getYcoord()
4802                 + ( getTreeFontSet()._fm_large.getAscent() / ( node.getNumberOfDescendants() == 1 ? 1 : 3.0 ) );
4803         _sb.setLength( 0 );
4804         if ( _control_panel.isShowTaxonomyCode() && !ForesterUtil.isEmpty( taxonomy.getTaxonomyCode() ) ) {
4805             _sb.append( taxonomy.getTaxonomyCode() );
4806             _sb.append( " " );
4807         }
4808         if ( _control_panel.isShowTaxonomyScientificNames() && _control_panel.isShowTaxonomyCommonNames() ) {
4809             if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() )
4810                     && !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
4811                 if ( getOptions().isAbbreviateScientificTaxonNames()
4812                         && ( taxonomy.getScientificName().indexOf( ' ' ) > 0 ) ) {
4813                     abbreviateScientificName( taxonomy.getScientificName() );
4814                 }
4815                 else {
4816                     _sb.append( taxonomy.getScientificName() );
4817                 }
4818                 _sb.append( " (" );
4819                 _sb.append( taxonomy.getCommonName() );
4820                 _sb.append( ") " );
4821             }
4822             else if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() ) ) {
4823                 if ( getOptions().isAbbreviateScientificTaxonNames()
4824                         && ( taxonomy.getScientificName().indexOf( ' ' ) > 0 ) ) {
4825                     abbreviateScientificName( taxonomy.getScientificName() );
4826                 }
4827                 else {
4828                     _sb.append( taxonomy.getScientificName() );
4829                 }
4830                 _sb.append( " " );
4831             }
4832             else if ( !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
4833                 _sb.append( taxonomy.getCommonName() );
4834                 _sb.append( " " );
4835             }
4836         }
4837         else if ( _control_panel.isShowTaxonomyScientificNames() ) {
4838             if ( !ForesterUtil.isEmpty( taxonomy.getScientificName() ) ) {
4839                 if ( getOptions().isAbbreviateScientificTaxonNames()
4840                         && ( taxonomy.getScientificName().indexOf( ' ' ) > 0 ) ) {
4841                     abbreviateScientificName( taxonomy.getScientificName() );
4842                 }
4843                 else {
4844                     _sb.append( taxonomy.getScientificName() );
4845                 }
4846                 _sb.append( " " );
4847             }
4848         }
4849         else if ( _control_panel.isShowTaxonomyCommonNames() ) {
4850             if ( !ForesterUtil.isEmpty( taxonomy.getCommonName() ) ) {
4851                 _sb.append( taxonomy.getCommonName() );
4852                 _sb.append( " " );
4853             }
4854         }
4855         final String label = _sb.toString();
4856         /* GUILHEM_BEG */
4857         if ( _control_panel.isShowSequenceRelations() && ( label.length() > 0 )
4858                 && ( node.getNodeData().isHasSequence() ) && node.getNodeData().getSequence().equals( _query_sequence ) ) {
4859             // invert font color and background color to show that this is the query sequence
4860             final Rectangle2D nodeTextBounds = new TextLayout( label, g.getFont(), new FontRenderContext( null,
4861                                                                                                           false,
4862                                                                                                           false ) )
4863                     .getBounds();
4864             g.fillRect( ( int ) start_x - 1, ( int ) start_y - 8, ( int ) nodeTextBounds.getWidth() + 4, 11 );
4865             g.setColor( getTreeColorSet().getBackgroundColor() );
4866         }
4867         /* GUILHEM_END */
4868         TreePanel.drawString( label, start_x, start_y, g );
4869         if ( is_in_found_nodes ) {
4870             return getTreeFontSet()._fm_large_italic_bold.stringWidth( label );
4871         }
4872         else {
4873             return getTreeFontSet()._fm_large_italic.stringWidth( label );
4874         }
4875     }
4876
4877     final private void paintUnrooted( final PhylogenyNode n,
4878                                       final double low_angle,
4879                                       final double high_angle,
4880                                       final boolean radial_labels,
4881                                       final Graphics2D g,
4882                                       final boolean to_pdf,
4883                                       final boolean to_graphics_file ) {
4884         if ( n.isRoot() ) {
4885             n.setXcoord( getWidth() / 2 );
4886             n.setYcoord( getHeight() / 2 );
4887         }
4888         if ( n.isExternal() ) {
4889             paintNodeDataUnrootedCirc( g,
4890                                        n,
4891                                        to_pdf,
4892                                        to_graphics_file,
4893                                        radial_labels,
4894                                        ( high_angle + low_angle ) / 2,
4895                                        isInFoundNodes( n ) || isInCurrentExternalNodes( n ) );
4896             return;
4897         }
4898         final float num_enclosed = n.getNumberOfExternalNodes();
4899         final float x = n.getXcoord();
4900         final float y = n.getYcoord();
4901         double current_angle = low_angle;
4902         // final boolean n_below = n.getYcoord() < getVisibleRect().getMinY() - 20;
4903         // final boolean n_above = n.getYcoord() > getVisibleRect().getMaxY() + 20;
4904         // final boolean n_left = n.getXcoord() < getVisibleRect().getMinX() - 20;
4905         // final boolean n_right = n.getXcoord() > getVisibleRect().getMaxX() + 20;
4906         for( int i = 0; i < n.getNumberOfDescendants(); ++i ) {
4907             final PhylogenyNode desc = n.getChildNode( i );
4908             ///  if ( ( ( n_below ) & ( desc.getYcoord() < getVisibleRect().getMinY() - 20 ) )
4909             //          || ( ( n_above ) & ( desc.getYcoord() > getVisibleRect().getMaxY() + 20 ) )
4910             //         || ( ( n_left ) & ( desc.getXcoord() < getVisibleRect().getMinX() - 20 ) )
4911             //          || ( ( n_right ) & ( desc.getXcoord() > getVisibleRect().getMaxX() + 20 ) ) ) {
4912             //     continue;
4913             // }
4914             //if ( ( desc.getYcoord() > n.getYcoord() ) && ( n.getYcoord() > getVisibleRect().getMaxY() - 20 ) ) {
4915             //    continue;
4916             //}
4917             //if ( ( desc.getYcoord() < n.getYcoord() ) && ( n.getYcoord() < getVisibleRect().getMinY() + 20 ) ) {
4918             //    continue;
4919             // }
4920             final int desc_num_enclosed = desc.getNumberOfExternalNodes();
4921             final double arc_size = ( desc_num_enclosed / num_enclosed ) * ( high_angle - low_angle );
4922             float length;
4923             if ( isPhyHasBranchLengths() && getControlPanel().isDrawPhylogram() ) {
4924                 if ( desc.getDistanceToParent() < 0 ) {
4925                     length = 0;
4926                 }
4927                 else {
4928                     length = ( float ) ( desc.getDistanceToParent() * getUrtFactor() );
4929                 }
4930             }
4931             else {
4932                 length = getUrtFactor();
4933             }
4934             final double mid_angle = current_angle + ( arc_size / 2 );
4935             final float new_x = ( float ) ( x + ( Math.cos( mid_angle ) * length ) );
4936             final float new_y = ( float ) ( y + ( Math.sin( mid_angle ) * length ) );
4937             desc.setXcoord( new_x );
4938             desc.setYcoord( new_y );
4939             paintUnrooted( desc, current_angle, current_angle + arc_size, radial_labels, g, to_pdf, to_graphics_file );
4940             current_angle += arc_size;
4941             assignGraphicsForBranchWithColorForParentBranch( desc, false, g, to_pdf, to_graphics_file );
4942             drawLine( x, y, new_x, new_y, g );
4943             paintNodeBox( new_x, new_y, desc, g, to_pdf, to_graphics_file );
4944         }
4945         if ( n.isRoot() ) {
4946             paintNodeBox( n.getXcoord(), n.getYcoord(), n, g, to_pdf, to_graphics_file );
4947         }
4948     }
4949
4950     final private void paintUnrootedLite( final PhylogenyNode n,
4951                                           final double low_angle,
4952                                           final double high_angle,
4953                                           final Graphics2D g,
4954                                           final float urt_ov_factor ) {
4955         if ( n.isRoot() ) {
4956             final int x_pos = ( int ) ( getVisibleRect().x + getOvXPosition() + ( getOvMaxWidth() / 2 ) );
4957             final int y_pos = ( int ) ( getVisibleRect().y + getOvYPosition() + ( getOvMaxHeight() / 2 ) );
4958             n.setXSecondary( x_pos );
4959             n.setYSecondary( y_pos );
4960         }
4961         if ( n.isExternal() ) {
4962             return;
4963         }
4964         final float num_enclosed = n.getNumberOfExternalNodes();
4965         final float x = n.getXSecondary();
4966         final float y = n.getYSecondary();
4967         double current_angle = low_angle;
4968         for( int i = 0; i < n.getNumberOfDescendants(); ++i ) {
4969             final PhylogenyNode desc = n.getChildNode( i );
4970             final int desc_num_enclosed = desc.getNumberOfExternalNodes();
4971             final double arc_size = ( desc_num_enclosed / num_enclosed ) * ( high_angle - low_angle );
4972             float length;
4973             if ( isPhyHasBranchLengths() && getControlPanel().isDrawPhylogram() ) {
4974                 if ( desc.getDistanceToParent() < 0 ) {
4975                     length = 0;
4976                 }
4977                 else {
4978                     length = ( float ) ( desc.getDistanceToParent() * urt_ov_factor );
4979                 }
4980             }
4981             else {
4982                 length = urt_ov_factor;
4983             }
4984             final double mid_angle = current_angle + ( arc_size / 2 );
4985             final float new_x = ( float ) ( x + ( Math.cos( mid_angle ) * length ) );
4986             final float new_y = ( float ) ( y + ( Math.sin( mid_angle ) * length ) );
4987             desc.setXSecondary( new_x );
4988             desc.setYSecondary( new_y );
4989             if ( isInFoundNodes( desc ) || isInCurrentExternalNodes( desc ) ) {
4990                 g.setColor( getColorForFoundNode( desc ) );
4991                 drawRectFilled( desc.getXSecondary() - OVERVIEW_FOUND_NODE_BOX_SIZE_HALF,
4992                                 desc.getYSecondary() - OVERVIEW_FOUND_NODE_BOX_SIZE_HALF,
4993                                 OVERVIEW_FOUND_NODE_BOX_SIZE,
4994                                 OVERVIEW_FOUND_NODE_BOX_SIZE,
4995                                 g );
4996                 g.setColor( getTreeColorSet().getOvColor() );
4997             }
4998             paintUnrootedLite( desc, current_angle, current_angle + arc_size, g, urt_ov_factor );
4999             current_angle += arc_size;
5000             drawLine( x, y, new_x, new_y, g );
5001         }
5002     }
5003
5004     final private void pasteSubtree( final PhylogenyNode node ) {
5005         if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
5006             errorMessageNoCutCopyPasteInUnrootedDisplay();
5007             return;
5008         }
5009         if ( ( getCutOrCopiedTree() == null ) || getCutOrCopiedTree().isEmpty() ) {
5010             JOptionPane.showMessageDialog( this,
5011                                            "No tree in buffer (need to copy or cut a subtree first)",
5012                                            "Attempt to paste with empty buffer",
5013                                            JOptionPane.ERROR_MESSAGE );
5014             return;
5015         }
5016         final String label = createASimpleTextRepresentationOfANode( getCutOrCopiedTree().getRoot() );
5017         final Object[] options = { "As sibling", "As descendant", "Cancel" };
5018         final int r = JOptionPane.showOptionDialog( this,
5019                                                     "How to paste subtree" + label + "?",
5020                                                     "Paste Subtree",
5021                                                     JOptionPane.CLOSED_OPTION,
5022                                                     JOptionPane.QUESTION_MESSAGE,
5023                                                     null,
5024                                                     options,
5025                                                     options[ 2 ] );
5026         boolean paste_as_sibling = true;
5027         if ( r == 1 ) {
5028             paste_as_sibling = false;
5029         }
5030         else if ( r != 0 ) {
5031             return;
5032         }
5033         final Phylogeny buffer_phy = getCutOrCopiedTree().copy();
5034         buffer_phy.setAllNodesToNotCollapse();
5035         PhylogenyMethods.preOrderReId( buffer_phy );
5036         buffer_phy.setRooted( true );
5037         boolean need_to_show_whole = false;
5038         if ( paste_as_sibling ) {
5039             if ( node.isRoot() ) {
5040                 JOptionPane.showMessageDialog( this,
5041                                                "Cannot paste sibling to root",
5042                                                "Attempt to paste sibling to root",
5043                                                JOptionPane.ERROR_MESSAGE );
5044                 return;
5045             }
5046             buffer_phy.addAsSibling( node );
5047         }
5048         else {
5049             if ( ( node.getNumberOfExternalNodes() == 1 ) && node.isRoot() ) {
5050                 need_to_show_whole = true;
5051                 _phylogeny = buffer_phy;
5052             }
5053             else {
5054                 buffer_phy.addAsChild( node );
5055             }
5056         }
5057         if ( getCopiedAndPastedNodes() == null ) {
5058             setCopiedAndPastedNodes( new HashSet<Long>() );
5059         }
5060         final List<PhylogenyNode> nodes = PhylogenyMethods.obtainAllNodesAsList( buffer_phy );
5061         final Set<Long> node_ids = new HashSet<Long>( nodes.size() );
5062         for( final PhylogenyNode n : nodes ) {
5063             node_ids.add( n.getId() );
5064         }
5065         node_ids.add( node.getId() );
5066         getCopiedAndPastedNodes().addAll( node_ids );
5067         setNodeInPreorderToNull();
5068         _phylogeny.externalNodesHaveChanged();
5069         _phylogeny.clearHashIdToNodeMap();
5070         _phylogeny.recalculateNumberOfExternalDescendants( true );
5071         resetNodeIdToDistToLeafMap();
5072         setEdited( true );
5073         if ( need_to_show_whole ) {
5074             getControlPanel().showWhole();
5075         }
5076         repaint();
5077     }
5078
5079     private final StringBuffer propertiesToString( final PhylogenyNode node ) {
5080         final PropertiesMap properties = node.getNodeData().getProperties();
5081         final StringBuffer sb = new StringBuffer();
5082         boolean first = true;
5083         for( final String ref : properties.getPropertyRefs() ) {
5084             if ( first ) {
5085                 first = false;
5086             }
5087             else {
5088                 sb.append( " " );
5089             }
5090             final Property p = properties.getProperty( ref );
5091             sb.append( TreePanelUtil.getPartAfterColon( p.getRef() ) );
5092             sb.append( "=" );
5093             sb.append( p.getValue() );
5094             if ( !ForesterUtil.isEmpty( p.getUnit() ) ) {
5095                 sb.append( TreePanelUtil.getPartAfterColon( p.getUnit() ) );
5096             }
5097         }
5098         return sb;
5099     }
5100
5101     final private void setCopiedAndPastedNodes( final Set<Long> nodeIds ) {
5102         getMainPanel().setCopiedAndPastedNodes( nodeIds );
5103     }
5104
5105     final private void setCutOrCopiedTree( final Phylogeny cut_or_copied_tree ) {
5106         getMainPanel().setCutOrCopiedTree( cut_or_copied_tree );
5107     }
5108
5109     final private void setInOv( final boolean in_ov ) {
5110         _in_ov = in_ov;
5111     }
5112
5113     final private void setOvMaxHeight( final float ov_max_height ) {
5114         _ov_max_height = ov_max_height;
5115     }
5116
5117     final private void setOvMaxWidth( final float ov_max_width ) {
5118         _ov_max_width = ov_max_width;
5119     }
5120
5121     final private void setOvXcorrectionFactor( final float f ) {
5122         _ov_x_correction_factor = f;
5123     }
5124
5125     final private void setOvXDistance( final float ov_x_distance ) {
5126         _ov_x_distance = ov_x_distance;
5127     }
5128
5129     final private void setOvXPosition( final int ov_x_position ) {
5130         _ov_x_position = ov_x_position;
5131     }
5132
5133     final private void setOvYDistance( final float ov_y_distance ) {
5134         _ov_y_distance = ov_y_distance;
5135     }
5136
5137     final private void setOvYPosition( final int ov_y_position ) {
5138         _ov_y_position = ov_y_position;
5139     }
5140
5141     final private void setOvYStart( final int ov_y_start ) {
5142         _ov_y_start = ov_y_start;
5143     }
5144
5145     final private void setScaleDistance( final double scale_distance ) {
5146         _scale_distance = scale_distance;
5147     }
5148
5149     final private void setScaleLabel( final String scale_label ) {
5150         _scale_label = scale_label;
5151     }
5152
5153     private final void setupStroke( final Graphics2D g ) {
5154         if ( getYdistance() < 0.001 ) {
5155             g.setStroke( STROKE_005 );
5156         }
5157         else if ( getYdistance() < 0.01 ) {
5158             g.setStroke( STROKE_01 );
5159         }
5160         else if ( getYdistance() < 0.5 ) {
5161             g.setStroke( STROKE_025 );
5162         }
5163         else if ( getYdistance() < 1 ) {
5164             g.setStroke( STROKE_05 );
5165         }
5166         else if ( getYdistance() < 2 ) {
5167             g.setStroke( STROKE_075 );
5168         }
5169         else if ( getYdistance() < 20 ) {
5170             g.setStroke( STROKE_1 );
5171         }
5172         else {
5173             g.setStroke( STROKE_2 );
5174         }
5175     }
5176
5177     final private void setUpUrtFactor() {
5178         final int d = getVisibleRect().width < getVisibleRect().height ? getVisibleRect().width
5179                 : getVisibleRect().height;
5180         if ( isPhyHasBranchLengths() && getControlPanel().isDrawPhylogram() ) {
5181             setUrtFactor( ( float ) ( d / ( 2 * getMaxDistanceToRoot() ) ) );
5182         }
5183         else {
5184             final int max_depth = _circ_max_depth;
5185             if ( max_depth > 0 ) {
5186                 setUrtFactor( d / ( 2 * max_depth ) );
5187             }
5188             else {
5189                 setUrtFactor( d / 2 );
5190             }
5191         }
5192         setUrtFactorOv( getUrtFactor() );
5193     }
5194
5195     final private void setUrtFactor( final float urt_factor ) {
5196         _urt_factor = urt_factor;
5197     }
5198
5199     final private void setUrtFactorOv( final float urt_factor_ov ) {
5200         _urt_factor_ov = urt_factor_ov;
5201     }
5202
5203     private void showExtDescNodeData( final PhylogenyNode node ) {
5204         final List<String> data = new ArrayList<String>();
5205         final List<PhylogenyNode> nodes = node.getAllExternalDescendants();
5206         if ( ( getFoundNodes0() != null ) && !getFoundNodes0().isEmpty() ) {
5207             for( final PhylogenyNode n : getFoundNodes0AsListOfPhylogenyNodes() ) {
5208                 if ( !nodes.contains( n ) ) {
5209                     nodes.add( n );
5210                 }
5211             }
5212         }
5213         if ( ( getFoundNodes1() != null ) && !getFoundNodes1().isEmpty() ) {
5214             for( final PhylogenyNode n : getFoundNodes1AsListOfPhylogenyNodes() ) {
5215                 if ( !nodes.contains( n ) ) {
5216                     nodes.add( n );
5217                 }
5218             }
5219         }
5220         for( final PhylogenyNode n : nodes ) {
5221             switch ( getOptions().getExtDescNodeDataToReturn() ) {
5222                 case NODE_NAME:
5223                     if ( !ForesterUtil.isEmpty( n.getName() ) ) {
5224                         data.add( n.getName() );
5225                     }
5226                     break;
5227                 case SEQUENCE_NAME:
5228                     if ( n.getNodeData().isHasSequence()
5229                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getName() ) ) {
5230                         data.add( n.getNodeData().getSequence().getName() );
5231                     }
5232                     break;
5233                 case GENE_NAME:
5234                     if ( n.getNodeData().isHasSequence()
5235                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getGeneName() ) ) {
5236                         data.add( n.getNodeData().getSequence().getGeneName() );
5237                     }
5238                     break;
5239                 case SEQUENCE_SYMBOL:
5240                     if ( n.getNodeData().isHasSequence()
5241                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getSymbol() ) ) {
5242                         data.add( n.getNodeData().getSequence().getSymbol() );
5243                     }
5244                     break;
5245                 case SEQUENCE_MOL_SEQ:
5246                     if ( n.getNodeData().isHasSequence()
5247                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getMolecularSequence() ) ) {
5248                         data.add( n.getNodeData().getSequence().getMolecularSequence() );
5249                     }
5250                     break;
5251                 case SEQUENCE_MOL_SEQ_FASTA:
5252                     final StringBuilder sb = new StringBuilder();
5253                     if ( n.getNodeData().isHasSequence()
5254                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getMolecularSequence() ) ) {
5255                         final StringBuilder ann = new StringBuilder();
5256                         if ( !ForesterUtil.isEmpty( n.getName() ) ) {
5257                             ann.append( n.getName() );
5258                             ann.append( "|" );
5259                         }
5260                         if ( !ForesterUtil.isEmpty( n.getNodeData().getSequence().getSymbol() ) ) {
5261                             ann.append( "SYM=" );
5262                             ann.append( n.getNodeData().getSequence().getSymbol() );
5263                             ann.append( "|" );
5264                         }
5265                         if ( !ForesterUtil.isEmpty( n.getNodeData().getSequence().getName() ) ) {
5266                             ann.append( "NAME=" );
5267                             ann.append( n.getNodeData().getSequence().getName() );
5268                             ann.append( "|" );
5269                         }
5270                         if ( !ForesterUtil.isEmpty( n.getNodeData().getSequence().getGeneName() ) ) {
5271                             ann.append( "GN=" );
5272                             ann.append( n.getNodeData().getSequence().getGeneName() );
5273                             ann.append( "|" );
5274                         }
5275                         if ( n.getNodeData().getSequence().getAccession() != null ) {
5276                             ann.append( "ACC=" );
5277                             ann.append( n.getNodeData().getSequence().getAccession().asText() );
5278                             ann.append( "|" );
5279                         }
5280                         if ( n.getNodeData().isHasTaxonomy() ) {
5281                             if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
5282                                 ann.append( "TAXID=" );
5283                                 ann.append( n.getNodeData().getTaxonomy().getTaxonomyCode() );
5284                                 ann.append( "|" );
5285                             }
5286                             if ( !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getScientificName() ) ) {
5287                                 ann.append( "SN=" );
5288                                 ann.append( n.getNodeData().getTaxonomy().getScientificName() );
5289                                 ann.append( "|" );
5290                             }
5291                         }
5292                         String ann_str;
5293                         if ( ann.charAt( ann.length() - 1 ) == '|' ) {
5294                             ann_str = ann.substring( 0, ann.length() - 1 );
5295                         }
5296                         else {
5297                             ann_str = ann.toString();
5298                         }
5299                         sb.append( SequenceWriter.toFasta( ann_str, n.getNodeData().getSequence()
5300                                 .getMolecularSequence(), 60 ) );
5301                         data.add( sb.toString() );
5302                     }
5303                     break;
5304                 case SEQUENCE_ACC:
5305                     if ( n.getNodeData().isHasSequence() && ( n.getNodeData().getSequence().getAccession() != null )
5306                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getAccession().toString() ) ) {
5307                         data.add( n.getNodeData().getSequence().getAccession().toString() );
5308                     }
5309                     break;
5310                 case TAXONOMY_SCIENTIFIC_NAME:
5311                     if ( n.getNodeData().isHasTaxonomy()
5312                             && !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getScientificName() ) ) {
5313                         data.add( n.getNodeData().getTaxonomy().getScientificName() );
5314                     }
5315                     break;
5316                 case TAXONOMY_COMM0N_NAME:
5317                     if ( n.getNodeData().isHasTaxonomy()
5318                             && !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getCommonName() ) ) {
5319                         data.add( n.getNodeData().getTaxonomy().getCommonName() );
5320                     }
5321                     break;
5322                 case TAXONOMY_CODE:
5323                     if ( n.getNodeData().isHasTaxonomy()
5324                             && !ForesterUtil.isEmpty( n.getNodeData().getTaxonomy().getTaxonomyCode() ) ) {
5325                         data.add( n.getNodeData().getTaxonomy().getTaxonomyCode() );
5326                     }
5327                     break;
5328                 case UNKNOWN:
5329                     TreePanelUtil.showExtDescNodeDataUserSelectedHelper( getControlPanel(), n, data );
5330                     break;
5331                 default:
5332                     throw new IllegalArgumentException( "unknown data element: "
5333                             + getOptions().getExtDescNodeDataToReturn() );
5334             }
5335         } // for loop
5336         final StringBuilder sb = new StringBuilder();
5337         final int size = TreePanelUtil.makeSB( data, getOptions(), sb );
5338         if ( ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.CONSOLE )
5339                 || ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.BUFFER_ONLY ) ) {
5340             if ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.CONSOLE ) {
5341                 System.out.println( sb );
5342             }
5343             if ( sb.length() < 1 ) {
5344                 clearCurrentExternalNodesDataBuffer();
5345             }
5346             else {
5347                 setCurrentExternalNodesDataBuffer( sb );
5348             }
5349         }
5350         else if ( getConfiguration().getExtNodeDataReturnOn() == EXT_NODE_DATA_RETURN_ON.WINODW ) {
5351             if ( sb.length() < 1 ) {
5352                 TreePanelUtil.showInformationMessage( this, "No Appropriate Data (" + obtainTitleForExtDescNodeData()
5353                         + ")", "Descendants of selected node do not contain selected data" );
5354                 clearCurrentExternalNodesDataBuffer();
5355             }
5356             else {
5357                 setCurrentExternalNodesDataBuffer( sb );
5358                 String title;
5359                 if ( ( getFoundNodes0() != null ) && !getFoundNodes0().isEmpty() ) {
5360                     title = ( getOptions().getExtDescNodeDataToReturn() == NODE_DATA.UNKNOWN ? "Data"
5361                             : obtainTitleForExtDescNodeData() )
5362                             + " for "
5363                             + data.size()
5364                             + " nodes, unique entries: "
5365                             + size;
5366                 }
5367                 else {
5368                     title = ( getOptions().getExtDescNodeDataToReturn() == NODE_DATA.UNKNOWN ? "Data"
5369                             : obtainTitleForExtDescNodeData() )
5370                             + " for "
5371                             + data.size()
5372                             + "/"
5373                             + node.getNumberOfExternalNodes()
5374                             + " external descendats of node "
5375                             + node
5376                             + ", unique entries: " + size;
5377                 }
5378                 final String s = sb.toString().trim();
5379                 if ( getMainPanel().getMainFrame() == null ) {
5380                     // Must be "E" applet version.
5381                     final ArchaeopteryxE ae = ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet();
5382                     ae.showTextFrame( s, title );
5383                 }
5384                 else {
5385                     getMainPanel().getMainFrame().showTextFrame( s, title );
5386                 }
5387             }
5388         }
5389     }
5390
5391     final private void showNodeDataPopup( final MouseEvent e, final PhylogenyNode node ) {
5392         try {
5393             if ( ( node.getName().length() > 0 )
5394                     || ( node.getNodeData().isHasTaxonomy() && !TreePanelUtil.isTaxonomyEmpty( node.getNodeData()
5395                             .getTaxonomy() ) )
5396                     || ( node.getNodeData().isHasSequence() && !TreePanelUtil.isSequenceEmpty( node.getNodeData()
5397                             .getSequence() ) ) || ( node.getNodeData().isHasDate() )
5398                     || ( node.getNodeData().isHasDistribution() ) || node.getBranchData().isHasConfidences() ) {
5399                 _popup_buffer.setLength( 0 );
5400                 short lines = 0;
5401                 if ( node.getName().length() > 0 ) {
5402                     lines++;
5403                     _popup_buffer.append( node.getName() );
5404                 }
5405                 if ( node.getNodeData().isHasTaxonomy()
5406                         && !TreePanelUtil.isTaxonomyEmpty( node.getNodeData().getTaxonomy() ) ) {
5407                     lines++;
5408                     boolean enc_data = false;
5409                     final Taxonomy tax = node.getNodeData().getTaxonomy();
5410                     if ( _popup_buffer.length() > 0 ) {
5411                         _popup_buffer.append( "\n" );
5412                     }
5413                     if ( !ForesterUtil.isEmpty( tax.getTaxonomyCode() ) ) {
5414                         _popup_buffer.append( "[" );
5415                         _popup_buffer.append( tax.getTaxonomyCode() );
5416                         _popup_buffer.append( "]" );
5417                         enc_data = true;
5418                     }
5419                     if ( !ForesterUtil.isEmpty( tax.getScientificName() ) ) {
5420                         if ( enc_data ) {
5421                             _popup_buffer.append( " " );
5422                         }
5423                         _popup_buffer.append( tax.getScientificName() );
5424                         enc_data = true;
5425                     }
5426                     if ( !ForesterUtil.isEmpty( tax.getCommonName() ) ) {
5427                         if ( enc_data ) {
5428                             _popup_buffer.append( " (" );
5429                         }
5430                         else {
5431                             _popup_buffer.append( "(" );
5432                         }
5433                         _popup_buffer.append( tax.getCommonName() );
5434                         _popup_buffer.append( ")" );
5435                         enc_data = true;
5436                     }
5437                     if ( !ForesterUtil.isEmpty( tax.getAuthority() ) ) {
5438                         if ( enc_data ) {
5439                             _popup_buffer.append( " (" );
5440                         }
5441                         else {
5442                             _popup_buffer.append( "(" );
5443                         }
5444                         _popup_buffer.append( tax.getAuthority() );
5445                         _popup_buffer.append( ")" );
5446                         enc_data = true;
5447                     }
5448                     if ( !ForesterUtil.isEmpty( tax.getRank() ) ) {
5449                         if ( enc_data ) {
5450                             _popup_buffer.append( " [" );
5451                         }
5452                         else {
5453                             _popup_buffer.append( "[" );
5454                         }
5455                         _popup_buffer.append( tax.getRank() );
5456                         _popup_buffer.append( "]" );
5457                         enc_data = true;
5458                     }
5459                     if ( tax.getSynonyms().size() > 0 ) {
5460                         if ( enc_data ) {
5461                             _popup_buffer.append( " " );
5462                         }
5463                         _popup_buffer.append( "[" );
5464                         int counter = 1;
5465                         for( final String syn : tax.getSynonyms() ) {
5466                             if ( !ForesterUtil.isEmpty( syn ) ) {
5467                                 enc_data = true;
5468                                 _popup_buffer.append( syn );
5469                                 if ( counter < tax.getSynonyms().size() ) {
5470                                     _popup_buffer.append( ", " );
5471                                 }
5472                             }
5473                             counter++;
5474                         }
5475                         _popup_buffer.append( "]" );
5476                     }
5477                     if ( !enc_data ) {
5478                         if ( ( tax.getIdentifier() != null ) && !ForesterUtil.isEmpty( tax.getIdentifier().getValue() ) ) {
5479                             if ( !ForesterUtil.isEmpty( tax.getIdentifier().getProvider() ) ) {
5480                                 _popup_buffer.append( "[" );
5481                                 _popup_buffer.append( tax.getIdentifier().getProvider() );
5482                                 _popup_buffer.append( "] " );
5483                             }
5484                             _popup_buffer.append( tax.getIdentifier().getValue() );
5485                         }
5486                     }
5487                 }
5488                 if ( node.getNodeData().isHasSequence()
5489                         && !TreePanelUtil.isSequenceEmpty( node.getNodeData().getSequence() ) ) {
5490                     lines++;
5491                     boolean enc_data = false;
5492                     if ( _popup_buffer.length() > 0 ) {
5493                         _popup_buffer.append( "\n" );
5494                     }
5495                     final Sequence seq = node.getNodeData().getSequence();
5496                     if ( seq.getAccession() != null ) {
5497                         _popup_buffer.append( "[" );
5498                         if ( !ForesterUtil.isEmpty( seq.getAccession().getSource() ) ) {
5499                             _popup_buffer.append( seq.getAccession().getSource() );
5500                             _popup_buffer.append( ":" );
5501                         }
5502                         _popup_buffer.append( seq.getAccession().getValue() );
5503                         _popup_buffer.append( "]" );
5504                         enc_data = true;
5505                     }
5506                     if ( !ForesterUtil.isEmpty( seq.getSymbol() ) ) {
5507                         if ( enc_data ) {
5508                             _popup_buffer.append( " [" );
5509                         }
5510                         else {
5511                             _popup_buffer.append( "[" );
5512                         }
5513                         _popup_buffer.append( seq.getSymbol() );
5514                         _popup_buffer.append( "]" );
5515                         enc_data = true;
5516                     }
5517                     if ( !ForesterUtil.isEmpty( seq.getGeneName() ) ) {
5518                         if ( enc_data ) {
5519                             _popup_buffer.append( " [" );
5520                         }
5521                         else {
5522                             _popup_buffer.append( "[" );
5523                         }
5524                         _popup_buffer.append( seq.getGeneName() );
5525                         _popup_buffer.append( "]" );
5526                         enc_data = true;
5527                     }
5528                     if ( !ForesterUtil.isEmpty( seq.getName() ) ) {
5529                         if ( enc_data ) {
5530                             _popup_buffer.append( " " );
5531                         }
5532                         _popup_buffer.append( seq.getName() );
5533                     }
5534                 }
5535                 if ( node.getNodeData().isHasDate() ) {
5536                     lines++;
5537                     if ( _popup_buffer.length() > 0 ) {
5538                         _popup_buffer.append( "\n" );
5539                     }
5540                     _popup_buffer.append( node.getNodeData().getDate().asSimpleText() );
5541                 }
5542                 if ( node.getNodeData().isHasDistribution() ) {
5543                     lines++;
5544                     if ( _popup_buffer.length() > 0 ) {
5545                         _popup_buffer.append( "\n" );
5546                     }
5547                     _popup_buffer.append( node.getNodeData().getDistribution().asSimpleText() );
5548                 }
5549                 if ( node.getBranchData().isHasConfidences() ) {
5550                     final List<Confidence> confs = node.getBranchData().getConfidences();
5551                     for( final Confidence confidence : confs ) {
5552                         lines++;
5553                         if ( _popup_buffer.length() > 0 ) {
5554                             _popup_buffer.append( "\n" );
5555                         }
5556                         if ( !ForesterUtil.isEmpty( confidence.getType() ) ) {
5557                             _popup_buffer.append( "[" );
5558                             _popup_buffer.append( confidence.getType() );
5559                             _popup_buffer.append( "] " );
5560                         }
5561                         _popup_buffer
5562                                 .append( FORMATTER_CONFIDENCE.format( ForesterUtil.round( confidence.getValue(),
5563                                                                                           getOptions()
5564                                                                                                   .getNumberOfDigitsAfterCommaForConfidenceValues() ) ) );
5565                         if ( confidence.getStandardDeviation() != Confidence.CONFIDENCE_DEFAULT_VALUE ) {
5566                             _popup_buffer.append( " (sd=" );
5567                             _popup_buffer.append( FORMATTER_CONFIDENCE.format( ForesterUtil.round( confidence
5568                                     .getStandardDeviation(), getOptions()
5569                                     .getNumberOfDigitsAfterCommaForConfidenceValues() ) ) );
5570                             _popup_buffer.append( ")" );
5571                         }
5572                     }
5573                 }
5574                 if ( node.getNodeData().isHasProperties() ) {
5575                     final PropertiesMap properties = node.getNodeData().getProperties();
5576                     for( final String ref : properties.getPropertyRefs() ) {
5577                         _popup_buffer.append( "\n" );
5578                         final Property p = properties.getProperty( ref );
5579                         _popup_buffer.append( TreePanelUtil.getPartAfterColon( p.getRef() ) );
5580                         _popup_buffer.append( "=" );
5581                         _popup_buffer.append( p.getValue() );
5582                         if ( !ForesterUtil.isEmpty( p.getUnit() ) ) {
5583                             _popup_buffer.append( TreePanelUtil.getPartAfterColon( p.getUnit() ) );
5584                         }
5585                     }
5586                 }
5587                 if ( _popup_buffer.length() > 0 ) {
5588                     if ( !getConfiguration().isUseNativeUI() ) {
5589                         _rollover_popup
5590                                 .setBorder( BorderFactory.createLineBorder( getTreeColorSet().getBranchColor() ) );
5591                         _rollover_popup.setBackground( getTreeColorSet().getBackgroundColor() );
5592                         if ( isInFoundNodes0( node ) && !isInFoundNodes1( node ) ) {
5593                             _rollover_popup.setForeground( getTreeColorSet().getFoundColor0() );
5594                         }
5595                         else if ( !isInFoundNodes0( node ) && isInFoundNodes1( node ) ) {
5596                             _rollover_popup.setForeground( getTreeColorSet().getFoundColor1() );
5597                         }
5598                         else if ( isInFoundNodes0( node ) && isInFoundNodes1( node ) ) {
5599                             _rollover_popup.setForeground( getTreeColorSet().getFoundColor0and1() );
5600                         }
5601                         else if ( getControlPanel().isColorAccordingToTaxonomy() ) {
5602                             _rollover_popup.setForeground( getTaxonomyBasedColor( node ) );
5603                         }
5604                         else {
5605                             _rollover_popup.setForeground( getTreeColorSet().getSequenceColor() );
5606                         }
5607                     }
5608                     else {
5609                         _rollover_popup.setBorder( BorderFactory.createLineBorder( Color.BLACK ) );
5610                     }
5611                     _rollover_popup.setText( _popup_buffer.toString() );
5612                     _node_desc_popup = PopupFactory.getSharedInstance().getPopup( null,
5613                                                                                   _rollover_popup,
5614                                                                                   e.getLocationOnScreen().x + 10,
5615                                                                                   e.getLocationOnScreen().y
5616                                                                                           - ( lines * 20 ) );
5617                     _node_desc_popup.show();
5618                 }
5619             }
5620         }
5621         catch ( final Exception ex ) {
5622             // Do nothing.
5623         }
5624     }
5625
5626     final private void showNodeEditFrame( final PhylogenyNode n ) {
5627         if ( _node_frame_index < TreePanel.MAX_NODE_FRAMES ) {
5628             // pop up edit box for single node
5629             _node_frames[ _node_frame_index ] = new NodeFrame( n, _phylogeny, this, _node_frame_index, "" );
5630             _node_frame_index++;
5631         }
5632         else {
5633             JOptionPane.showMessageDialog( this, "too many node windows are open" );
5634         }
5635     }
5636
5637     final private void showNodeFrame( final PhylogenyNode n ) {
5638         if ( _node_frame_index < TreePanel.MAX_NODE_FRAMES ) {
5639             // pop up edit box for single node
5640             _node_frames[ _node_frame_index ] = new NodeFrame( n, _phylogeny, this, _node_frame_index );
5641             _node_frame_index++;
5642         }
5643         else {
5644             JOptionPane.showMessageDialog( this, "too many node windows are open" );
5645         }
5646     }
5647
5648     final private void switchDisplaygetPhylogenyGraphicsType() {
5649         switch ( getPhylogenyGraphicsType() ) {
5650             case RECTANGULAR:
5651                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE );
5652                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.EURO_STYLE );
5653                 break;
5654             case EURO_STYLE:
5655                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.ROUNDED );
5656                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.ROUNDED );
5657                 break;
5658             case ROUNDED:
5659                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CURVED );
5660                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CURVED );
5661                 break;
5662             case CURVED:
5663                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR );
5664                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.TRIANGULAR );
5665                 break;
5666             case TRIANGULAR:
5667                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CONVEX );
5668                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CONVEX );
5669                 break;
5670             case CONVEX:
5671                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
5672                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.UNROOTED );
5673                 break;
5674             case UNROOTED:
5675                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CIRCULAR );
5676                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.CIRCULAR );
5677                 break;
5678             case CIRCULAR:
5679                 setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
5680                 getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
5681                 break;
5682             default:
5683                 throw new RuntimeException( "unkwnown display type: " + getPhylogenyGraphicsType() );
5684         }
5685         if ( getControlPanel().getDynamicallyHideData() != null ) {
5686             if ( getPhylogenyGraphicsType() == PHYLOGENY_GRAPHICS_TYPE.UNROOTED ) {
5687                 getControlPanel().getDynamicallyHideData().setEnabled( false );
5688             }
5689             else {
5690                 getControlPanel().getDynamicallyHideData().setEnabled( true );
5691             }
5692         }
5693         if ( isPhyHasBranchLengths() && ( getPhylogenyGraphicsType() != PHYLOGENY_GRAPHICS_TYPE.CIRCULAR ) ) {
5694             getControlPanel().setDrawPhylogramEnabled( true );
5695         }
5696         else {
5697             getControlPanel().setDrawPhylogramEnabled( false );
5698         }
5699         if ( getMainPanel().getMainFrame() == null ) {
5700             // Must be "E" applet version.
5701             ( ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet() )
5702                     .setSelectedTypeInTypeMenu( getPhylogenyGraphicsType() );
5703         }
5704         else {
5705             getMainPanel().getMainFrame().setSelectedTypeInTypeMenu( getPhylogenyGraphicsType() );
5706         }
5707     }
5708
5709     final private static void drawString( final String str, final double x, final double y, final Graphics2D g ) {
5710         g.drawString( str, ( int ) ( x + 0.5 ), ( int ) ( y + 0.5 ) );
5711     }
5712
5713     final private static boolean plusPressed( final int key_code ) {
5714         return ( ( key_code == KeyEvent.VK_ADD ) || ( key_code == KeyEvent.VK_PLUS )
5715                 || ( key_code == KeyEvent.VK_EQUALS ) || ( key_code == KeyEvent.VK_SEMICOLON ) || ( key_code == KeyEvent.VK_1 ) );
5716     }
5717
5718     final private class SubtreeColorizationActionListener implements ActionListener {
5719
5720         List<PhylogenyNode> _additional_nodes = null;
5721         JColorChooser       _chooser          = null;
5722         PhylogenyNode       _node             = null;
5723
5724         SubtreeColorizationActionListener( final JColorChooser chooser, final PhylogenyNode node ) {
5725             _chooser = chooser;
5726             _node = node;
5727         }
5728
5729         SubtreeColorizationActionListener( final JColorChooser chooser,
5730                                            final PhylogenyNode node,
5731                                            final List<PhylogenyNode> additional_nodes ) {
5732             _chooser = chooser;
5733             _node = node;
5734             _additional_nodes = additional_nodes;
5735         }
5736
5737         @Override
5738         public void actionPerformed( final ActionEvent e ) {
5739             final Color c = _chooser.getColor();
5740             if ( c != null ) {
5741                 colorizeSubtree( c, _node, _additional_nodes );
5742             }
5743         }
5744     }
5745 }