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