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