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