added AGRESSIVE tax extraction ^^
[jalview.git] / forester / java / src / org / forester / archaeopteryx / MainFrameApplication.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 // Copyright (C) 2003-2007 Ethalinda K.S. Cannon
8 // All rights reserved
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 //
24 // Contact: phylosoft @ gmail . com
25 // WWW: https://sites.google.com/site/cmzmasek/home/software/forester
26
27 package org.forester.archaeopteryx;
28
29 import java.awt.BorderLayout;
30 import java.awt.Font;
31 import java.awt.event.ActionEvent;
32 import java.awt.event.ComponentAdapter;
33 import java.awt.event.ComponentEvent;
34 import java.awt.event.WindowAdapter;
35 import java.awt.event.WindowEvent;
36 import java.io.File;
37 import java.io.FileInputStream;
38 import java.io.IOException;
39 import java.io.InputStream;
40 import java.net.MalformedURLException;
41 import java.net.URL;
42 import java.util.ArrayList;
43 import java.util.HashSet;
44 import java.util.List;
45 import java.util.Set;
46
47 import javax.swing.ButtonGroup;
48 import javax.swing.JCheckBoxMenuItem;
49 import javax.swing.JFileChooser;
50 import javax.swing.JMenu;
51 import javax.swing.JMenuBar;
52 import javax.swing.JMenuItem;
53 import javax.swing.JOptionPane;
54 import javax.swing.JRadioButtonMenuItem;
55 import javax.swing.UIManager;
56 import javax.swing.UnsupportedLookAndFeelException;
57 import javax.swing.WindowConstants;
58 import javax.swing.event.ChangeEvent;
59 import javax.swing.event.ChangeListener;
60 import javax.swing.filechooser.FileFilter;
61 import javax.swing.plaf.synth.SynthLookAndFeel;
62
63 import org.forester.analysis.TaxonomyDataManager;
64 import org.forester.archaeopteryx.AptxUtil.GraphicsExportType;
65 import org.forester.archaeopteryx.Options.CLADOGRAM_TYPE;
66 import org.forester.archaeopteryx.Options.NODE_LABEL_DIRECTION;
67 import org.forester.archaeopteryx.Options.PHYLOGENY_GRAPHICS_TYPE;
68 import org.forester.archaeopteryx.tools.AncestralTaxonomyInferrer;
69 import org.forester.archaeopteryx.tools.GoAnnotation;
70 import org.forester.archaeopteryx.tools.InferenceManager;
71 import org.forester.archaeopteryx.tools.PhyloInferenceDialog;
72 import org.forester.archaeopteryx.tools.PhylogeneticInferenceOptions;
73 import org.forester.archaeopteryx.tools.PhylogeneticInferrer;
74 import org.forester.archaeopteryx.tools.SequenceDataRetriver;
75 import org.forester.archaeopteryx.webservices.PhylogeniesWebserviceClient;
76 import org.forester.archaeopteryx.webservices.WebservicesManager;
77 import org.forester.io.parsers.FastaParser;
78 import org.forester.io.parsers.GeneralMsaParser;
79 import org.forester.io.parsers.PhylogenyParser;
80 import org.forester.io.parsers.nexus.NexusPhylogeniesParser;
81 import org.forester.io.parsers.nhx.NHXParser;
82 import org.forester.io.parsers.nhx.NHXParser.TAXONOMY_EXTRACTION;
83 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
84 import org.forester.io.parsers.phyloxml.PhyloXmlParser;
85 import org.forester.io.parsers.phyloxml.PhyloXmlUtil;
86 import org.forester.io.parsers.tol.TolParser;
87 import org.forester.io.parsers.util.ParserUtils;
88 import org.forester.io.writers.PhylogenyWriter;
89 import org.forester.io.writers.SequenceWriter;
90 import org.forester.msa.Msa;
91 import org.forester.msa.MsaFormatException;
92 import org.forester.phylogeny.Phylogeny;
93 import org.forester.phylogeny.PhylogenyMethods;
94 import org.forester.phylogeny.PhylogenyNode;
95 import org.forester.phylogeny.PhylogenyNode.NH_CONVERSION_SUPPORT_VALUE_STYLE;
96 import org.forester.phylogeny.data.Confidence;
97 import org.forester.phylogeny.data.Taxonomy;
98 import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
99 import org.forester.phylogeny.factories.PhylogenyFactory;
100 import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
101 import org.forester.sdi.GSDI;
102 import org.forester.sdi.GSDIR;
103 import org.forester.sdi.SDIException;
104 import org.forester.sdi.SDIR;
105 import org.forester.sequence.Sequence;
106 import org.forester.util.BasicDescriptiveStatistics;
107 import org.forester.util.BasicTable;
108 import org.forester.util.BasicTableParser;
109 import org.forester.util.DescriptiveStatistics;
110 import org.forester.util.ForesterUtil;
111 import org.forester.util.WindowsUtils;
112
113 public final class MainFrameApplication extends MainFrame {
114
115     static final String                      INFER_ANCESTOR_TAXONOMIES             = "Infer Ancestor Taxonomies";
116     static final String                      OBTAIN_DETAILED_TAXONOMIC_INFORMATION = "Obtain Detailed Taxonomic Information";
117     private final static int                 FRAME_X_SIZE                          = 800;
118     private final static int                 FRAME_Y_SIZE                          = 800;
119     // Filters for the file-open dialog (classes defined in this file)
120     private final static NHFilter            nhfilter                              = new NHFilter();
121     private final static NHXFilter           nhxfilter                             = new NHXFilter();
122     private final static XMLFilter           xmlfilter                             = new XMLFilter();
123     private final static TolFilter           tolfilter                             = new TolFilter();
124     private final static NexusFilter         nexusfilter                           = new NexusFilter();
125     private final static PdfFilter           pdffilter                             = new PdfFilter();
126     private final static GraphicsFileFilter  graphicsfilefilter                    = new GraphicsFileFilter();
127     private final static MsaFileFilter       msafilter                             = new MsaFileFilter();
128     private final static SequencesFileFilter seqsfilter                            = new SequencesFileFilter();
129     private final static DefaultFilter       defaultfilter                         = new DefaultFilter();
130     private static final long                serialVersionUID                      = -799735726778865234L;
131     private final JFileChooser               _values_filechooser;
132     private final JFileChooser               _sequences_filechooser;
133     private final JFileChooser               _open_filechooser;
134     private final JFileChooser               _msa_filechooser;
135     private final JFileChooser               _seqs_pi_filechooser;
136     private final JFileChooser               _open_filechooser_for_species_tree;
137     private final JFileChooser               _save_filechooser;
138     private final JFileChooser               _writetopdf_filechooser;
139     private final JFileChooser               _writetographics_filechooser;
140     // Analysis menu
141     private JMenu                            _analysis_menu;
142     private JMenuItem                        _load_species_tree_item;
143     private JMenuItem                        _gsdi_item;
144     private JMenuItem                        _gsdir_item;
145     private JMenuItem                        _root_min_dups_item;
146     private JMenuItem                        _root_min_cost_l_item;
147     private JMenuItem                        _lineage_inference;
148     private JMenuItem                        _function_analysis;
149     // Application-only print menu items
150     private JMenuItem                        _print_item;
151     private JMenuItem                        _write_to_pdf_item;
152     private JMenuItem                        _write_to_jpg_item;
153     private JMenuItem                        _write_to_gif_item;
154     private JMenuItem                        _write_to_tif_item;
155     private JMenuItem                        _write_to_png_item;
156     private JMenuItem                        _write_to_bmp_item;
157     private Phylogeny                        _species_tree;
158     private File                             _current_dir;
159     private ButtonGroup                      _radio_group_1;
160     private ButtonGroup                      _radio_group_2;
161     // Others:
162     double                                   _min_not_collapse                     = Constants.MIN_NOT_COLLAPSE_DEFAULT;
163     // Phylogeny Inference menu
164     private JMenu                            _inference_menu;
165     private JMenuItem                        _inference_from_msa_item;
166     private JMenuItem                        _inference_from_seqs_item;
167     // Phylogeny Inference
168     private PhylogeneticInferenceOptions     _phylogenetic_inference_options       = null;
169     private Msa                              _msa                                  = null;
170     private File                             _msa_file                             = null;
171     private List<Sequence>                   _seqs                                 = null;
172     private File                             _seqs_file                            = null;
173     JMenuItem                                _read_values_jmi;
174     JMenuItem                                _read_seqs_jmi;
175
176     private MainFrameApplication( final Phylogeny[] phys, final Configuration config ) {
177         _configuration = config;
178         if ( _configuration == null ) {
179             throw new IllegalArgumentException( "configuration is null" );
180         }
181         setVisible( false );
182         setOptions( Options.createInstance( _configuration ) );
183         _mainpanel = new MainPanel( _configuration, this );
184         _open_filechooser = null;
185         _open_filechooser_for_species_tree = null;
186         _save_filechooser = null;
187         _writetopdf_filechooser = null;
188         _writetographics_filechooser = null;
189         _msa_filechooser = null;
190         _seqs_pi_filechooser = null;
191         _values_filechooser = null;
192         _sequences_filechooser = null;
193         _jmenubar = new JMenuBar();
194         buildFileMenu();
195         buildTypeMenu();
196         _contentpane = getContentPane();
197         _contentpane.setLayout( new BorderLayout() );
198         _contentpane.add( _mainpanel, BorderLayout.CENTER );
199         // App is this big
200         setSize( MainFrameApplication.FRAME_X_SIZE, MainFrameApplication.FRAME_Y_SIZE );
201         // The window listener
202         setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE );
203         addWindowListener( new WindowAdapter() {
204
205             @Override
206             public void windowClosing( final WindowEvent e ) {
207                 exit();
208             }
209         } );
210         //   setVisible( true );
211         if ( ( phys != null ) && ( phys.length > 0 ) ) {
212             AptxUtil.addPhylogeniesToTabs( phys, "", null, _configuration, _mainpanel );
213             validate();
214             getMainPanel().getControlPanel().showWholeAll();
215             getMainPanel().getControlPanel().showWhole();
216         }
217         //activateSaveAllIfNeeded();
218         // ...and its children
219         _contentpane.repaint();
220     }
221
222     private MainFrameApplication( final Phylogeny[] phys, final Configuration config, final String title ) {
223         this( phys, config, title, null );
224     }
225
226     private MainFrameApplication( final Phylogeny[] phys,
227                                   final Configuration config,
228                                   final String title,
229                                   final File current_dir ) {
230         super();
231         _configuration = config;
232         if ( _configuration == null ) {
233             throw new IllegalArgumentException( "configuration is null" );
234         }
235         try {
236             boolean synth_exception = false;
237             if ( Constants.__SYNTH_LF ) {
238                 try {
239                     final SynthLookAndFeel synth = new SynthLookAndFeel();
240                     synth.load( MainFrameApplication.class.getResourceAsStream( "/resources/synth_look_and_feel_1.xml" ),
241                                 MainFrameApplication.class );
242                     UIManager.setLookAndFeel( synth );
243                 }
244                 catch ( final Exception ex ) {
245                     synth_exception = true;
246                     ForesterUtil.printWarningMessage( Constants.PRG_NAME,
247                                                       "could not create synth look and feel: "
248                                                               + ex.getLocalizedMessage() );
249                 }
250             }
251             if ( !Constants.__SYNTH_LF || synth_exception ) {
252                 if ( _configuration.isUseNativeUI() ) {
253                     UIManager.setLookAndFeel( UIManager.getSystemLookAndFeelClassName() );
254                 }
255                 else {
256                     UIManager.setLookAndFeel( UIManager.getCrossPlatformLookAndFeelClassName() );
257                 }
258             }
259             //UIManager.setLookAndFeel( "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel" );
260         }
261         catch ( final UnsupportedLookAndFeelException e ) {
262             AptxUtil.dieWithSystemError( "unsupported look and feel: " + e.toString() );
263         }
264         catch ( final ClassNotFoundException e ) {
265             AptxUtil.dieWithSystemError( "class not found exception: " + e.toString() );
266         }
267         catch ( final InstantiationException e ) {
268             AptxUtil.dieWithSystemError( "instantiation exception: " + e.toString() );
269         }
270         catch ( final IllegalAccessException e ) {
271             AptxUtil.dieWithSystemError( "illegal access exception: " + e.toString() );
272         }
273         if ( ( current_dir != null ) && current_dir.canRead() && current_dir.isDirectory() ) {
274             setCurrentDir( current_dir );
275         }
276         // hide until everything is ready
277         setVisible( false );
278         setOptions( Options.createInstance( _configuration ) );
279         setInferenceManager( InferenceManager.createInstance( _configuration ) );
280         setPhylogeneticInferenceOptions( PhylogeneticInferenceOptions.createInstance( _configuration ) );
281         //     _textframe = null; #~~~~
282         _species_tree = null;
283         // set title
284         setTitle( Constants.PRG_NAME + " " + Constants.VERSION + " (" + Constants.PRG_DATE + ")" );
285         _mainpanel = new MainPanel( _configuration, this );
286         // The file dialogs
287         _open_filechooser = new JFileChooser();
288         _open_filechooser.setCurrentDirectory( new File( "." ) );
289         _open_filechooser.setMultiSelectionEnabled( false );
290         _open_filechooser.addChoosableFileFilter( MainFrameApplication.xmlfilter );
291         _open_filechooser.addChoosableFileFilter( MainFrameApplication.nhxfilter );
292         _open_filechooser.addChoosableFileFilter( MainFrameApplication.nhfilter );
293         _open_filechooser.addChoosableFileFilter( MainFrameApplication.nexusfilter );
294         _open_filechooser.addChoosableFileFilter( MainFrameApplication.tolfilter );
295         _open_filechooser.addChoosableFileFilter( _open_filechooser.getAcceptAllFileFilter() );
296         _open_filechooser.setFileFilter( MainFrameApplication.defaultfilter );
297         _open_filechooser_for_species_tree = new JFileChooser();
298         _open_filechooser_for_species_tree.setCurrentDirectory( new File( "." ) );
299         _open_filechooser_for_species_tree.setMultiSelectionEnabled( false );
300         _open_filechooser_for_species_tree.addChoosableFileFilter( MainFrameApplication.xmlfilter );
301         _open_filechooser_for_species_tree.addChoosableFileFilter( MainFrameApplication.tolfilter );
302         _open_filechooser_for_species_tree.setFileFilter( MainFrameApplication.xmlfilter );
303         _save_filechooser = new JFileChooser();
304         _save_filechooser.setCurrentDirectory( new File( "." ) );
305         _save_filechooser.setMultiSelectionEnabled( false );
306         _save_filechooser.setFileFilter( MainFrameApplication.xmlfilter );
307         _save_filechooser.addChoosableFileFilter( MainFrameApplication.nhfilter );
308         _save_filechooser.addChoosableFileFilter( MainFrameApplication.nexusfilter );
309         _save_filechooser.addChoosableFileFilter( _save_filechooser.getAcceptAllFileFilter() );
310         _writetopdf_filechooser = new JFileChooser();
311         _writetopdf_filechooser.addChoosableFileFilter( MainFrameApplication.pdffilter );
312         _writetographics_filechooser = new JFileChooser();
313         _writetographics_filechooser.addChoosableFileFilter( MainFrameApplication.graphicsfilefilter );
314         // Msa:
315         _msa_filechooser = new JFileChooser();
316         _msa_filechooser.setName( "Read Multiple Sequence Alignment File" );
317         _msa_filechooser.setCurrentDirectory( new File( "." ) );
318         _msa_filechooser.setMultiSelectionEnabled( false );
319         _msa_filechooser.addChoosableFileFilter( _msa_filechooser.getAcceptAllFileFilter() );
320         _msa_filechooser.addChoosableFileFilter( MainFrameApplication.msafilter );
321         // Seqs:
322         _seqs_pi_filechooser = new JFileChooser();
323         _seqs_pi_filechooser.setName( "Read Sequences File" );
324         _seqs_pi_filechooser.setCurrentDirectory( new File( "." ) );
325         _seqs_pi_filechooser.setMultiSelectionEnabled( false );
326         _seqs_pi_filechooser.addChoosableFileFilter( _seqs_pi_filechooser.getAcceptAllFileFilter() );
327         _seqs_pi_filechooser.addChoosableFileFilter( MainFrameApplication.seqsfilter );
328         // Expression
329         _values_filechooser = new JFileChooser();
330         _values_filechooser.setCurrentDirectory( new File( "." ) );
331         _values_filechooser.setMultiSelectionEnabled( false );
332         // Sequences
333         _sequences_filechooser = new JFileChooser();
334         _sequences_filechooser.setCurrentDirectory( new File( "." ) );
335         _sequences_filechooser.setMultiSelectionEnabled( false );
336         // build the menu bar
337         _jmenubar = new JMenuBar();
338         if ( !_configuration.isUseNativeUI() ) {
339             _jmenubar.setBackground( getConfiguration().getGuiMenuBackgroundColor() );
340         }
341         buildFileMenu();
342         if ( Constants.__ALLOW_PHYLOGENETIC_INFERENCE ) {
343             buildPhylogeneticInferenceMenu();
344         }
345         buildAnalysisMenu();
346         buildToolsMenu();
347         buildViewMenu();
348         buildFontSizeMenu();
349         buildOptionsMenu();
350         buildTypeMenu();
351         buildHelpMenu();
352         setJMenuBar( _jmenubar );
353         _jmenubar.add( _help_jmenu );
354         _contentpane = getContentPane();
355         _contentpane.setLayout( new BorderLayout() );
356         _contentpane.add( _mainpanel, BorderLayout.CENTER );
357         // App is this big
358         setSize( MainFrameApplication.FRAME_X_SIZE, MainFrameApplication.FRAME_Y_SIZE );
359         //        addWindowFocusListener( new WindowAdapter() {
360         //
361         //            @Override
362         //            public void windowGainedFocus( WindowEvent e ) {
363         //                requestFocusInWindow();
364         //            }
365         //        } );
366         // The window listener
367         setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE );
368         addWindowListener( new WindowAdapter() {
369
370             @Override
371             public void windowClosing( final WindowEvent e ) {
372                 if ( isUnsavedDataPresent() ) {
373                     final int r = JOptionPane.showConfirmDialog( null,
374                                                                  "Exit despite potentially unsaved changes?",
375                                                                  "Exit?",
376                                                                  JOptionPane.YES_NO_OPTION );
377                     if ( r != JOptionPane.YES_OPTION ) {
378                         return;
379                     }
380                 }
381                 else {
382                     final int r = JOptionPane.showConfirmDialog( null,
383                                                                  "Exit Archaeopteryx?",
384                                                                  "Exit?",
385                                                                  JOptionPane.YES_NO_OPTION );
386                     if ( r != JOptionPane.YES_OPTION ) {
387                         return;
388                     }
389                 }
390                 exit();
391             }
392         } );
393         // The component listener
394         addComponentListener( new ComponentAdapter() {
395
396             @Override
397             public void componentResized( final ComponentEvent e ) {
398                 if ( _mainpanel.getCurrentTreePanel() != null ) {
399                     _mainpanel.getCurrentTreePanel().calcParametersForPainting( _mainpanel.getCurrentTreePanel()
400                                                                                         .getWidth(),
401                                                                                 _mainpanel.getCurrentTreePanel()
402                                                                                         .getHeight(),
403                                                                                 getOptions().isAllowFontSizeChange() );
404                 }
405             }
406         } );
407         requestFocusInWindow();
408         // addKeyListener( this );
409         setVisible( true );
410         if ( ( phys != null ) && ( phys.length > 0 ) ) {
411             AptxUtil.addPhylogeniesToTabs( phys, title, null, _configuration, _mainpanel );
412             validate();
413             getMainPanel().getControlPanel().showWholeAll();
414             getMainPanel().getControlPanel().showWhole();
415         }
416         activateSaveAllIfNeeded();
417         // ...and its children
418         _contentpane.repaint();
419         System.gc();
420     }
421
422     private MainFrameApplication( final Phylogeny[] phys, final String config_file, final String title ) {
423         // Reads the config file (false, false => not url, not applet):
424         this( phys, new Configuration( config_file, false, false, true ), title );
425     }
426
427     @Override
428     public void actionPerformed( final ActionEvent e ) {
429         try {
430             super.actionPerformed( e );
431             final Object o = e.getSource();
432             // Handle app-specific actions here:
433             if ( o == _open_item ) {
434                 readPhylogeniesFromFile();
435             }
436             else if ( o == _save_item ) {
437                 writeToFile( _mainpanel.getCurrentPhylogeny() );
438                 // If subtree currently displayed, save it, instead of complete
439                 // tree.
440             }
441             else if ( o == _new_item ) {
442                 newTree();
443             }
444             else if ( o == _save_all_item ) {
445                 writeAllToFile();
446             }
447             else if ( o == _close_item ) {
448                 closeCurrentPane();
449             }
450             else if ( o == _write_to_pdf_item ) {
451                 writeToPdf( _mainpanel.getCurrentPhylogeny() );
452             }
453             else if ( o == _write_to_jpg_item ) {
454                 writeToGraphicsFile( _mainpanel.getCurrentPhylogeny(), GraphicsExportType.JPG );
455             }
456             else if ( o == _write_to_png_item ) {
457                 writeToGraphicsFile( _mainpanel.getCurrentPhylogeny(), GraphicsExportType.PNG );
458             }
459             else if ( o == _write_to_gif_item ) {
460                 writeToGraphicsFile( _mainpanel.getCurrentPhylogeny(), GraphicsExportType.GIF );
461             }
462             else if ( o == _write_to_tif_item ) {
463                 writeToGraphicsFile( _mainpanel.getCurrentPhylogeny(), GraphicsExportType.TIFF );
464             }
465             else if ( o == _write_to_bmp_item ) {
466                 writeToGraphicsFile( _mainpanel.getCurrentPhylogeny(), GraphicsExportType.BMP );
467             }
468             else if ( o == _print_item ) {
469                 print();
470             }
471             else if ( o == _load_species_tree_item ) {
472                 readSpeciesTreeFromFile();
473             }
474             else if ( o == _lineage_inference ) {
475                 if ( isSubtreeDisplayed() ) {
476                     JOptionPane.showMessageDialog( this,
477                                                    "Subtree is shown.",
478                                                    "Cannot infer ancestral taxonomies",
479                                                    JOptionPane.ERROR_MESSAGE );
480                     return;
481                 }
482                 executeLineageInference();
483             }
484             else if ( o == _function_analysis ) {
485                 executeFunctionAnalysis();
486             }
487             else if ( o == _obtain_detailed_taxonomic_information_jmi ) {
488                 if ( isSubtreeDisplayed() ) {
489                     return;
490                 }
491                 obtainDetailedTaxonomicInformation();
492             }
493             else if ( o == _obtain_detailed_taxonomic_information_deleting_jmi ) {
494                 if ( isSubtreeDisplayed() ) {
495                     return;
496                 }
497                 obtainDetailedTaxonomicInformationDelete();
498             }
499             else if ( o == _obtain_seq_information_jmi ) {
500                 obtainSequenceInformation();
501             }
502             else if ( o == _read_values_jmi ) {
503                 if ( isSubtreeDisplayed() ) {
504                     return;
505                 }
506                 addExpressionValuesFromFile();
507             }
508             else if ( o == _read_seqs_jmi ) {
509                 if ( isSubtreeDisplayed() ) {
510                     return;
511                 }
512                 addSequencesFromFile();
513             }
514             else if ( o == _move_node_names_to_tax_sn_jmi ) {
515                 moveNodeNamesToTaxSn();
516             }
517             else if ( o == _move_node_names_to_seq_names_jmi ) {
518                 moveNodeNamesToSeqNames();
519             }
520             else if ( o == _extract_tax_code_from_node_names_jmi ) {
521                 extractTaxDataFromNodeNames();
522             }
523             else if ( o == _gsdi_item ) {
524                 if ( isSubtreeDisplayed() ) {
525                     return;
526                 }
527                 executeGSDI();
528             }
529             else if ( o == _gsdir_item ) {
530                 if ( isSubtreeDisplayed() ) {
531                     return;
532                 }
533                 executeGSDIR();
534             }
535             else if ( o == _root_min_dups_item ) {
536                 if ( isSubtreeDisplayed() ) {
537                     return;
538                 }
539                 executeSDIR( false );
540             }
541             else if ( o == _root_min_cost_l_item ) {
542                 if ( isSubtreeDisplayed() ) {
543                     return;
544                 }
545                 executeSDIR( true );
546             }
547             else if ( o == _graphics_export_visible_only_cbmi ) {
548                 updateOptions( getOptions() );
549             }
550             else if ( o == _antialias_print_cbmi ) {
551                 updateOptions( getOptions() );
552             }
553             else if ( o == _print_black_and_white_cbmi ) {
554                 updateOptions( getOptions() );
555             }
556             else if ( o == _print_using_actual_size_cbmi ) {
557                 updateOptions( getOptions() );
558             }
559             else if ( o == _graphics_export_using_actual_size_cbmi ) {
560                 updateOptions( getOptions() );
561             }
562             else if ( o == _print_size_mi ) {
563                 choosePrintSize();
564             }
565             else if ( o == _choose_pdf_width_mi ) {
566                 choosePdfWidth();
567             }
568             else if ( o == _internal_number_are_confidence_for_nh_parsing_cbmi ) {
569                 updateOptions( getOptions() );
570             }
571             else if ( o == _replace_underscores_cbmi ) {
572                 if ( ( _extract_taxonomy_no_rbmi != null ) && !_extract_taxonomy_no_rbmi.isSelected() ) {
573                     _extract_taxonomy_no_rbmi.setSelected( true );
574                 }
575                 updateOptions( getOptions() );
576             }
577             else if ( o == _collapse_below_threshold ) {
578                 if ( isSubtreeDisplayed() ) {
579                     return;
580                 }
581                 collapseBelowThreshold();
582             }
583             else if ( ( o == _extract_taxonomy_pfam_rbmi ) || ( o == _extract_taxonomy_yes_rbmi ) ) {
584                 if ( _replace_underscores_cbmi != null ) {
585                     _replace_underscores_cbmi.setSelected( false );
586                 }
587                 updateOptions( getOptions() );
588             }
589             else if ( o == _inference_from_msa_item ) {
590                 executePhyleneticInference( false );
591             }
592             else if ( o == _inference_from_seqs_item ) {
593                 executePhyleneticInference( true );
594             }
595             _contentpane.repaint();
596         }
597         catch ( final Exception ex ) {
598             AptxUtil.unexpectedException( ex );
599         }
600         catch ( final Error err ) {
601             AptxUtil.unexpectedError( err );
602         }
603     }
604
605     public void end() {
606         _mainpanel.terminate();
607         _contentpane.removeAll();
608         setVisible( false );
609         dispose();
610     }
611
612     @Override
613     public MainPanel getMainPanel() {
614         return _mainpanel;
615     }
616
617     public Msa getMsa() {
618         return _msa;
619     }
620
621     public File getMsaFile() {
622         return _msa_file;
623     }
624
625     public List<Sequence> getSeqs() {
626         return _seqs;
627     }
628
629     public File getSeqsFile() {
630         return _seqs_file;
631     }
632
633     public void readMsaFromFile() {
634         // Set an initial directory if none set yet
635         final File my_dir = getCurrentDir();
636         _msa_filechooser.setMultiSelectionEnabled( false );
637         // Open file-open dialog and set current directory
638         if ( my_dir != null ) {
639             _msa_filechooser.setCurrentDirectory( my_dir );
640         }
641         final int result = _msa_filechooser.showOpenDialog( _contentpane );
642         // All done: get the msa
643         final File file = _msa_filechooser.getSelectedFile();
644         setCurrentDir( _msa_filechooser.getCurrentDirectory() );
645         if ( ( file != null ) && !file.isDirectory() && ( result == JFileChooser.APPROVE_OPTION ) ) {
646             setMsaFile( null );
647             setMsa( null );
648             Msa msa = null;
649             try {
650                 final InputStream is = new FileInputStream( file );
651                 if ( FastaParser.isLikelyFasta( file ) ) {
652                     msa = FastaParser.parseMsa( is );
653                 }
654                 else {
655                     msa = GeneralMsaParser.parse( is );
656                 }
657             }
658             catch ( final MsaFormatException e ) {
659                 setArrowCursor();
660                 JOptionPane.showMessageDialog( this,
661                                                e.getLocalizedMessage(),
662                                                "Multiple sequence alignment format error",
663                                                JOptionPane.ERROR_MESSAGE );
664                 return;
665             }
666             catch ( final IOException e ) {
667                 setArrowCursor();
668                 JOptionPane.showMessageDialog( this,
669                                                e.getLocalizedMessage(),
670                                                "Failed to read multiple sequence alignment",
671                                                JOptionPane.ERROR_MESSAGE );
672                 return;
673             }
674             catch ( final IllegalArgumentException e ) {
675                 setArrowCursor();
676                 JOptionPane.showMessageDialog( this,
677                                                e.getLocalizedMessage(),
678                                                "Unexpected error during reading of multiple sequence alignment",
679                                                JOptionPane.ERROR_MESSAGE );
680                 return;
681             }
682             catch ( final Exception e ) {
683                 setArrowCursor();
684                 e.printStackTrace();
685                 JOptionPane.showMessageDialog( this,
686                                                e.getLocalizedMessage(),
687                                                "Unexpected error during reading of multiple sequence alignment",
688                                                JOptionPane.ERROR_MESSAGE );
689                 return;
690             }
691             if ( ( msa == null ) || ( msa.getNumberOfSequences() < 1 ) ) {
692                 JOptionPane.showMessageDialog( this,
693                                                "Multiple sequence alignment is empty",
694                                                "Illegal Multiple Sequence Alignment",
695                                                JOptionPane.ERROR_MESSAGE );
696                 return;
697             }
698             if ( msa.getNumberOfSequences() < 4 ) {
699                 JOptionPane.showMessageDialog( this,
700                                                "Multiple sequence alignment needs to contain at least 3 sequences",
701                                                "Illegal multiple sequence alignment",
702                                                JOptionPane.ERROR_MESSAGE );
703                 return;
704             }
705             if ( msa.getLength() < 2 ) {
706                 JOptionPane.showMessageDialog( this,
707                                                "Multiple sequence alignment needs to contain at least 2 residues",
708                                                "Illegal multiple sequence alignment",
709                                                JOptionPane.ERROR_MESSAGE );
710                 return;
711             }
712             System.gc();
713             setMsaFile( _msa_filechooser.getSelectedFile() );
714             setMsa( msa );
715         }
716     }
717
718     public void readSeqsFromFileforPI() {
719         // Set an initial directory if none set yet
720         final File my_dir = getCurrentDir();
721         _seqs_pi_filechooser.setMultiSelectionEnabled( false );
722         // Open file-open dialog and set current directory
723         if ( my_dir != null ) {
724             _seqs_pi_filechooser.setCurrentDirectory( my_dir );
725         }
726         final int result = _seqs_pi_filechooser.showOpenDialog( _contentpane );
727         // All done: get the seqs
728         final File file = _seqs_pi_filechooser.getSelectedFile();
729         setCurrentDir( _seqs_pi_filechooser.getCurrentDirectory() );
730         if ( ( file != null ) && !file.isDirectory() && ( result == JFileChooser.APPROVE_OPTION ) ) {
731             setSeqsFile( null );
732             setSeqs( null );
733             List<Sequence> seqs = null;
734             try {
735                 if ( FastaParser.isLikelyFasta( new FileInputStream( file ) ) ) {
736                     seqs = FastaParser.parse( new FileInputStream( file ) );
737                     for( final Sequence seq : seqs ) {
738                         System.out.println( SequenceWriter.toFasta( seq, 60 ) );
739                     }
740                 }
741                 else {
742                     //TODO error
743                 }
744             }
745             catch ( final MsaFormatException e ) {
746                 setArrowCursor();
747                 JOptionPane.showMessageDialog( this,
748                                                e.getLocalizedMessage(),
749                                                "Multiple sequence file format error",
750                                                JOptionPane.ERROR_MESSAGE );
751                 return;
752             }
753             catch ( final IOException e ) {
754                 setArrowCursor();
755                 JOptionPane.showMessageDialog( this,
756                                                e.getLocalizedMessage(),
757                                                "Failed to read multiple sequence file",
758                                                JOptionPane.ERROR_MESSAGE );
759                 return;
760             }
761             catch ( final IllegalArgumentException e ) {
762                 setArrowCursor();
763                 JOptionPane.showMessageDialog( this,
764                                                e.getLocalizedMessage(),
765                                                "Unexpected error during reading of multiple sequence file",
766                                                JOptionPane.ERROR_MESSAGE );
767                 return;
768             }
769             catch ( final Exception e ) {
770                 setArrowCursor();
771                 e.printStackTrace();
772                 JOptionPane.showMessageDialog( this,
773                                                e.getLocalizedMessage(),
774                                                "Unexpected error during reading of multiple sequence file",
775                                                JOptionPane.ERROR_MESSAGE );
776                 return;
777             }
778             if ( ( seqs == null ) || ( seqs.size() < 1 ) ) {
779                 JOptionPane.showMessageDialog( this,
780                                                "Multiple sequence file is empty",
781                                                "Illegal multiple sequence file",
782                                                JOptionPane.ERROR_MESSAGE );
783                 return;
784             }
785             if ( seqs.size() < 4 ) {
786                 JOptionPane.showMessageDialog( this,
787                                                "Multiple sequence file needs to contain at least 3 sequences",
788                                                "Illegal multiple sequence file",
789                                                JOptionPane.ERROR_MESSAGE );
790                 return;
791             }
792             //  if ( msa.getLength() < 2 ) {
793             //       JOptionPane.showMessageDialog( this,
794             //                                      "Multiple sequence alignment needs to contain at least 2 residues",
795             //                                      "Illegal multiple sequence file",
796             //                                      JOptionPane.ERROR_MESSAGE );
797             //       return;
798             //   }
799             System.gc();
800             setSeqsFile( _seqs_pi_filechooser.getSelectedFile() );
801             setSeqs( seqs );
802         }
803     }
804
805     void buildAnalysisMenu() {
806         _analysis_menu = MainFrame.createMenu( "Analysis", getConfiguration() );
807         _analysis_menu.add( _gsdi_item = new JMenuItem( "GSDI (Generalized Speciation Duplication Inference)" ) );
808         _analysis_menu.add( _gsdir_item = new JMenuItem( "GSDIR (re-rooting)" ) );
809         _analysis_menu.addSeparator();
810         _analysis_menu.add( _root_min_dups_item = new JMenuItem( "Root by Minimizing Duplications | Height (SDI)" ) );
811         _analysis_menu.add( _root_min_cost_l_item = new JMenuItem( "Root by Minimizing Cost L | Height (SDI)" ) );
812         _analysis_menu.addSeparator();
813         _analysis_menu.add( _load_species_tree_item = new JMenuItem( "Load Species Tree..." ) );
814         customizeJMenuItem( _gsdi_item );
815         customizeJMenuItem( _gsdir_item );
816         customizeJMenuItem( _root_min_dups_item );
817         customizeJMenuItem( _root_min_cost_l_item );
818         customizeJMenuItem( _load_species_tree_item );
819         _analysis_menu.addSeparator();
820         _analysis_menu.add( _lineage_inference = new JMenuItem( INFER_ANCESTOR_TAXONOMIES ) );
821         customizeJMenuItem( _lineage_inference );
822         _lineage_inference.setToolTipText( "Inference of ancestor taxonomies/lineages" );
823         _jmenubar.add( _analysis_menu );
824     }
825
826     @Override
827     void buildFileMenu() {
828         _file_jmenu = MainFrame.createMenu( "File", getConfiguration() );
829         _file_jmenu.add( _open_item = new JMenuItem( "Read Tree from File..." ) );
830         _file_jmenu.addSeparator();
831         _file_jmenu.add( _open_url_item = new JMenuItem( "Read Tree from URL/Webservice..." ) );
832         _file_jmenu.addSeparator();
833         final WebservicesManager webservices_manager = WebservicesManager.getInstance();
834         _load_phylogeny_from_webservice_menu_items = new JMenuItem[ webservices_manager
835                 .getAvailablePhylogeniesWebserviceClients().size() ];
836         for( int i = 0; i < webservices_manager.getAvailablePhylogeniesWebserviceClients().size(); ++i ) {
837             final PhylogeniesWebserviceClient client = webservices_manager.getAvailablePhylogeniesWebserviceClient( i );
838             _load_phylogeny_from_webservice_menu_items[ i ] = new JMenuItem( client.getMenuName() );
839             _file_jmenu.add( _load_phylogeny_from_webservice_menu_items[ i ] );
840         }
841         if ( getConfiguration().isEditable() ) {
842             _file_jmenu.addSeparator();
843             _file_jmenu.add( _new_item = new JMenuItem( "New" ) );
844             _new_item.setToolTipText( "to create a new tree with one node, as source for manual tree construction" );
845         }
846         _file_jmenu.addSeparator();
847         _file_jmenu.add( _save_item = new JMenuItem( "Save Tree As..." ) );
848         _file_jmenu.add( _save_all_item = new JMenuItem( "Save All Trees As..." ) );
849         _save_all_item.setToolTipText( "Write all phylogenies to one file." );
850         _save_all_item.setEnabled( false );
851         _file_jmenu.addSeparator();
852         _file_jmenu.add( _write_to_pdf_item = new JMenuItem( "Export to PDF file ..." ) );
853         if ( AptxUtil.canWriteFormat( "tif" ) || AptxUtil.canWriteFormat( "tiff" ) || AptxUtil.canWriteFormat( "TIF" ) ) {
854             _file_jmenu.add( _write_to_tif_item = new JMenuItem( "Export to TIFF file..." ) );
855         }
856         _file_jmenu.add( _write_to_png_item = new JMenuItem( "Export to PNG file..." ) );
857         _file_jmenu.add( _write_to_jpg_item = new JMenuItem( "Export to JPG file..." ) );
858         if ( AptxUtil.canWriteFormat( "gif" ) ) {
859             _file_jmenu.add( _write_to_gif_item = new JMenuItem( "Export to GIF file..." ) );
860         }
861         if ( AptxUtil.canWriteFormat( "bmp" ) ) {
862             _file_jmenu.add( _write_to_bmp_item = new JMenuItem( "Export to BMP file..." ) );
863         }
864         _file_jmenu.addSeparator();
865         _file_jmenu.add( _print_item = new JMenuItem( "Print..." ) );
866         _file_jmenu.addSeparator();
867         _file_jmenu.add( _close_item = new JMenuItem( "Close Tab" ) );
868         _close_item.setToolTipText( "To close the current pane." );
869         _close_item.setEnabled( true );
870         _file_jmenu.addSeparator();
871         _file_jmenu.add( _exit_item = new JMenuItem( "Exit" ) );
872         // For print in color option item
873         customizeJMenuItem( _open_item );
874         _open_item
875                 .setFont( new Font( _open_item.getFont().getFontName(), Font.BOLD, _open_item.getFont().getSize() + 4 ) );
876         customizeJMenuItem( _open_url_item );
877         for( int i = 0; i < webservices_manager.getAvailablePhylogeniesWebserviceClients().size(); ++i ) {
878             customizeJMenuItem( _load_phylogeny_from_webservice_menu_items[ i ] );
879         }
880         customizeJMenuItem( _save_item );
881         if ( getConfiguration().isEditable() ) {
882             customizeJMenuItem( _new_item );
883         }
884         customizeJMenuItem( _close_item );
885         customizeJMenuItem( _save_all_item );
886         customizeJMenuItem( _write_to_pdf_item );
887         customizeJMenuItem( _write_to_png_item );
888         customizeJMenuItem( _write_to_jpg_item );
889         customizeJMenuItem( _write_to_gif_item );
890         customizeJMenuItem( _write_to_tif_item );
891         customizeJMenuItem( _write_to_bmp_item );
892         customizeJMenuItem( _print_item );
893         customizeJMenuItem( _exit_item );
894         _jmenubar.add( _file_jmenu );
895     }
896
897     void buildOptionsMenu() {
898         _options_jmenu = MainFrame.createMenu( OPTIONS_HEADER, getConfiguration() );
899         _options_jmenu.addChangeListener( new ChangeListener() {
900
901             @Override
902             public void stateChanged( final ChangeEvent e ) {
903                 MainFrame.setOvPlacementColorChooseMenuItem( _overview_placment_mi, getOptions() );
904                 MainFrame.setTextColorChooseMenuItem( _switch_colors_mi, getCurrentTreePanel() );
905                 MainFrame
906                         .setTextMinSupportMenuItem( _choose_minimal_confidence_mi, getOptions(), getCurrentTreePanel() );
907                 MainFrame.setTextForFontChooserMenuItem( _choose_font_mi, MainFrame
908                         .createCurrentFontDesc( getMainPanel().getTreeFontSet() ) );
909                 setTextForGraphicsSizeChooserMenuItem( _print_size_mi, getOptions() );
910                 setTextForPdfLineWidthChooserMenuItem( _choose_pdf_width_mi, getOptions() );
911                 MainFrame.updateOptionsMenuDependingOnPhylogenyType( getMainPanel(),
912                                                                      _show_scale_cbmi,
913                                                                      _show_branch_length_values_cbmi,
914                                                                      _non_lined_up_cladograms_rbmi,
915                                                                      _uniform_cladograms_rbmi,
916                                                                      _ext_node_dependent_cladogram_rbmi,
917                                                                      _label_direction_cbmi );
918                 MainFrame.setCycleNodeFillMenuItem( _cycle_node_fill_mi, getOptions() );
919                 MainFrame.setCycleNodeShapeMenuItem( _cycle_node_shape_mi, getOptions() );
920                 MainFrame.setTextNodeSizeMenuItem( _choose_node_size_mi, getOptions() );
921             }
922         } );
923         _options_jmenu.add( customizeMenuItemAsLabel( new JMenuItem( DISPLAY_SUBHEADER ), getConfiguration() ) );
924         _options_jmenu
925                 .add( _ext_node_dependent_cladogram_rbmi = new JRadioButtonMenuItem( MainFrame.NONUNIFORM_CLADOGRAMS_LABEL ) );
926         _options_jmenu.add( _uniform_cladograms_rbmi = new JRadioButtonMenuItem( MainFrame.UNIFORM_CLADOGRAMS_LABEL ) );
927         _options_jmenu.add( _non_lined_up_cladograms_rbmi = new JRadioButtonMenuItem( NON_LINED_UP_CLADOGRAMS_LABEL ) );
928         _radio_group_1 = new ButtonGroup();
929         _radio_group_1.add( _ext_node_dependent_cladogram_rbmi );
930         _radio_group_1.add( _uniform_cladograms_rbmi );
931         _radio_group_1.add( _non_lined_up_cladograms_rbmi );
932         _options_jmenu.add( _show_overview_cbmi = new JCheckBoxMenuItem( SHOW_OVERVIEW_LABEL ) );
933         _options_jmenu.add( _show_scale_cbmi = new JCheckBoxMenuItem( DISPLAY_SCALE_LABEL ) );
934         _options_jmenu
935                 .add( _show_branch_length_values_cbmi = new JCheckBoxMenuItem( DISPLAY_BRANCH_LENGTH_VALUES_LABEL ) );
936         _options_jmenu.add( _show_confidence_stddev_cbmi = new JCheckBoxMenuItem( SHOW_CONF_STDDEV_LABEL ) );
937         _options_jmenu
938                 .add( _show_default_node_shapes_internal_cbmi = new JCheckBoxMenuItem( DISPLAY_NODE_BOXES_LABEL_INT ) );
939         _options_jmenu
940                 .add( _show_default_node_shapes_external_cbmi = new JCheckBoxMenuItem( DISPLAY_NODE_BOXES_LABEL_EXT ) );
941         _options_jmenu
942                 .add( _taxonomy_colorize_node_shapes_cbmi = new JCheckBoxMenuItem( MainFrame.TAXONOMY_COLORIZE_NODE_SHAPES_LABEL ) );
943         _options_jmenu.add( _cycle_node_shape_mi = new JMenuItem( MainFrame.CYCLE_NODE_SHAPE_LABEL ) );
944         _options_jmenu.add( _cycle_node_fill_mi = new JMenuItem( MainFrame.CYCLE_NODE_FILL_LABEL ) );
945         _options_jmenu.add( _choose_node_size_mi = new JMenuItem( MainFrame.CHOOSE_NODE_SIZE_LABEL ) );
946         _options_jmenu.add( _label_direction_cbmi = new JCheckBoxMenuItem( LABEL_DIRECTION_LABEL ) );
947         _label_direction_cbmi.setToolTipText( LABEL_DIRECTION_TIP );
948         _options_jmenu.add( _color_labels_same_as_parent_branch = new JCheckBoxMenuItem( COLOR_LABELS_LABEL ) );
949         _color_labels_same_as_parent_branch.setToolTipText( MainFrame.COLOR_LABELS_TIP );
950         _options_jmenu.add( _abbreviate_scientific_names = new JCheckBoxMenuItem( ABBREV_SN_LABEL ) );
951         _options_jmenu.add( _screen_antialias_cbmi = new JCheckBoxMenuItem( SCREEN_ANTIALIAS_LABEL ) );
952         _options_jmenu.add( _background_gradient_cbmi = new JCheckBoxMenuItem( BG_GRAD_LABEL ) );
953         if ( getConfiguration().doDisplayOption( Configuration.show_domain_architectures ) ) {
954             _options_jmenu.add( _show_domain_labels = new JCheckBoxMenuItem( SHOW_DOMAIN_LABELS_LABEL ) );
955         }
956         _options_jmenu.add( _choose_minimal_confidence_mi = new JMenuItem( "" ) );
957         _options_jmenu.add( _overview_placment_mi = new JMenuItem( "" ) );
958         _options_jmenu.add( _switch_colors_mi = new JMenuItem( "" ) );
959         _options_jmenu.add( _choose_font_mi = new JMenuItem( "" ) );
960         _options_jmenu.addSeparator();
961         _options_jmenu.add( customizeMenuItemAsLabel( new JMenuItem( SEARCH_SUBHEADER ), getConfiguration() ) );
962         _options_jmenu.add( _search_case_senstive_cbmi = new JCheckBoxMenuItem( SEARCH_CASE_SENSITIVE_LABEL ) );
963         _options_jmenu.add( _search_whole_words_only_cbmi = new JCheckBoxMenuItem( SEARCH_TERMS_ONLY_LABEL ) );
964         _options_jmenu.add( _inverse_search_result_cbmi = new JCheckBoxMenuItem( INVERSE_SEARCH_RESULT_LABEL ) );
965         _options_jmenu.addSeparator();
966         _options_jmenu.add( customizeMenuItemAsLabel( new JMenuItem( "Graphics Export & Printing:" ),
967                                                       getConfiguration() ) );
968         _options_jmenu.add( _antialias_print_cbmi = new JCheckBoxMenuItem( "Antialias" ) );
969         _options_jmenu.add( _print_black_and_white_cbmi = new JCheckBoxMenuItem( "Export in Black and White" ) );
970         _options_jmenu
971                 .add( _print_using_actual_size_cbmi = new JCheckBoxMenuItem( "Use Current Image Size for PDF export and Printing" ) );
972         _options_jmenu
973                 .add( _graphics_export_using_actual_size_cbmi = new JCheckBoxMenuItem( "Use Current Image Size for PNG, JPG, and GIF export" ) );
974         _options_jmenu
975                 .add( _graphics_export_visible_only_cbmi = new JCheckBoxMenuItem( "Limit to Visible ('Screenshot') for PNG, JPG, and GIF export" ) );
976         _options_jmenu.add( _print_size_mi = new JMenuItem( "" ) );
977         _options_jmenu.add( _choose_pdf_width_mi = new JMenuItem( "" ) );
978         _options_jmenu.addSeparator();
979         _options_jmenu.add( customizeMenuItemAsLabel( new JMenuItem( "Newick/NHX/Nexus Input:" ), getConfiguration() ) );
980         _options_jmenu
981                 .add( _internal_number_are_confidence_for_nh_parsing_cbmi = new JCheckBoxMenuItem( "Internal Node Names are Confidence Values" ) );
982         _options_jmenu.add( _replace_underscores_cbmi = new JCheckBoxMenuItem( "Replace Underscores with Spaces" ) );
983         //
984         _options_jmenu.add( _extract_taxonomy_no_rbmi = new JRadioButtonMenuItem( "No Taxonomy Extraction" ) );
985         _options_jmenu
986                 .add( _extract_taxonomy_pfam_rbmi = new JRadioButtonMenuItem( "Extract Taxonomy Codes from Pfam-style Node Names" ) );
987         _extract_taxonomy_pfam_rbmi
988                 .setToolTipText( "To extract 5-letter taxonomy codes from node names in the form of \"BCL2_MOUSE/134-298\"" );
989         _options_jmenu
990                 .add( _extract_taxonomy_yes_rbmi = new JRadioButtonMenuItem( "Extract Taxonomy Codes from Node Names" ) );
991         _extract_taxonomy_yes_rbmi
992                 .setToolTipText( "To extract 5-letter taxonomy codes from node names in the form of \"BCL2_MOUSE\" or \"BCL2_MOUSE B-cell lymphoma 2...\"" );
993         _radio_group_2 = new ButtonGroup();
994         _radio_group_2.add( _extract_taxonomy_no_rbmi );
995         _radio_group_2.add( _extract_taxonomy_pfam_rbmi );
996         _radio_group_2.add( _extract_taxonomy_yes_rbmi );
997         // 
998         _options_jmenu.add( customizeMenuItemAsLabel( new JMenuItem( "Newick/Nexus Output:" ), getConfiguration() ) );
999         _options_jmenu
1000                 .add( _use_brackets_for_conf_in_nh_export_cbmi = new JCheckBoxMenuItem( USE_BRACKETS_FOR_CONF_IN_NH_LABEL ) );
1001         _use_brackets_for_conf_in_nh_export_cbmi
1002                 .setToolTipText( "e.g. \"0.1[90]\" for a branch with support 90 and a length of 0.1" );
1003         _options_jmenu
1004                 .add( _use_internal_names_for_conf_in_nh_export_cbmi = new JCheckBoxMenuItem( USE_INTERNAL_NAMES_FOR_CONF_IN_NH_LABEL ) );
1005         customizeJMenuItem( _choose_font_mi );
1006         customizeJMenuItem( _choose_minimal_confidence_mi );
1007         customizeJMenuItem( _switch_colors_mi );
1008         customizeJMenuItem( _print_size_mi );
1009         customizeJMenuItem( _choose_pdf_width_mi );
1010         customizeJMenuItem( _overview_placment_mi );
1011         customizeCheckBoxMenuItem( _show_default_node_shapes_external_cbmi, getOptions()
1012                 .isShowDefaultNodeShapesExternal() );
1013         customizeCheckBoxMenuItem( _show_default_node_shapes_internal_cbmi, getOptions()
1014                 .isShowDefaultNodeShapesInternal() );
1015         customizeCheckBoxMenuItem( _taxonomy_colorize_node_shapes_cbmi, getOptions().isTaxonomyColorizeNodeShapes() );
1016         customizeJMenuItem( _cycle_node_shape_mi );
1017         customizeJMenuItem( _cycle_node_fill_mi );
1018         customizeJMenuItem( _choose_node_size_mi );
1019         customizeCheckBoxMenuItem( _color_labels_same_as_parent_branch, getOptions().isColorLabelsSameAsParentBranch() );
1020         customizeCheckBoxMenuItem( _screen_antialias_cbmi, getOptions().isAntialiasScreen() );
1021         customizeCheckBoxMenuItem( _background_gradient_cbmi, getOptions().isBackgroundColorGradient() );
1022         customizeCheckBoxMenuItem( _show_domain_labels, getOptions().isShowDomainLabels() );
1023         customizeCheckBoxMenuItem( _abbreviate_scientific_names, getOptions().isAbbreviateScientificTaxonNames() );
1024         customizeCheckBoxMenuItem( _search_case_senstive_cbmi, getOptions().isSearchCaseSensitive() );
1025         customizeCheckBoxMenuItem( _show_scale_cbmi, getOptions().isShowScale() );
1026         customizeRadioButtonMenuItem( _non_lined_up_cladograms_rbmi,
1027                                       getOptions().getCladogramType() == CLADOGRAM_TYPE.NON_LINED_UP );
1028         customizeRadioButtonMenuItem( _uniform_cladograms_rbmi,
1029                                       getOptions().getCladogramType() == CLADOGRAM_TYPE.TOTAL_NODE_SUM_DEP );
1030         customizeRadioButtonMenuItem( _ext_node_dependent_cladogram_rbmi,
1031                                       getOptions().getCladogramType() == CLADOGRAM_TYPE.EXT_NODE_SUM_DEP );
1032         customizeCheckBoxMenuItem( _show_branch_length_values_cbmi, getOptions().isShowBranchLengthValues() );
1033         customizeCheckBoxMenuItem( _show_overview_cbmi, getOptions().isShowOverview() );
1034         customizeCheckBoxMenuItem( _label_direction_cbmi,
1035                                    getOptions().getNodeLabelDirection() == NODE_LABEL_DIRECTION.RADIAL );
1036         customizeCheckBoxMenuItem( _antialias_print_cbmi, getOptions().isAntialiasPrint() );
1037         customizeCheckBoxMenuItem( _print_black_and_white_cbmi, getOptions().isPrintBlackAndWhite() );
1038         customizeCheckBoxMenuItem( _internal_number_are_confidence_for_nh_parsing_cbmi, getOptions()
1039                 .isInternalNumberAreConfidenceForNhParsing() );
1040         customizeRadioButtonMenuItem( _extract_taxonomy_no_rbmi,
1041                                       getOptions().getTaxonomyExtraction() == TAXONOMY_EXTRACTION.NO );
1042         customizeRadioButtonMenuItem( _extract_taxonomy_yes_rbmi,
1043                                       getOptions().getTaxonomyExtraction() == TAXONOMY_EXTRACTION.PFAM_STYLE_RELAXED );
1044         customizeRadioButtonMenuItem( _extract_taxonomy_pfam_rbmi,
1045                                       getOptions().getTaxonomyExtraction() == TAXONOMY_EXTRACTION.PFAM_STYLE_STRICT );
1046         customizeCheckBoxMenuItem( _replace_underscores_cbmi, getOptions().isReplaceUnderscoresInNhParsing() );
1047         customizeCheckBoxMenuItem( _search_whole_words_only_cbmi, getOptions().isMatchWholeTermsOnly() );
1048         customizeCheckBoxMenuItem( _inverse_search_result_cbmi, getOptions().isInverseSearchResult() );
1049         customizeCheckBoxMenuItem( _graphics_export_visible_only_cbmi, getOptions().isGraphicsExportVisibleOnly() );
1050         customizeCheckBoxMenuItem( _print_using_actual_size_cbmi, getOptions().isPrintUsingActualSize() );
1051         customizeCheckBoxMenuItem( _graphics_export_using_actual_size_cbmi, getOptions()
1052                 .isGraphicsExportUsingActualSize() );
1053         customizeCheckBoxMenuItem( _show_confidence_stddev_cbmi, getOptions().isShowConfidenceStddev() );
1054         customizeCheckBoxMenuItem( _use_brackets_for_conf_in_nh_export_cbmi, getOptions()
1055                 .getNhConversionSupportValueStyle() == NH_CONVERSION_SUPPORT_VALUE_STYLE.IN_SQUARE_BRACKETS );
1056         customizeCheckBoxMenuItem( _use_internal_names_for_conf_in_nh_export_cbmi, getOptions()
1057                 .getNhConversionSupportValueStyle() == NH_CONVERSION_SUPPORT_VALUE_STYLE.AS_INTERNAL_NODE_NAMES );
1058         _jmenubar.add( _options_jmenu );
1059     }
1060
1061     void buildPhylogeneticInferenceMenu() {
1062         final InferenceManager im = getInferenceManager();
1063         _inference_menu = MainFrame.createMenu( "Inference", getConfiguration() );
1064         _inference_menu.add( _inference_from_msa_item = new JMenuItem( "From Multiple Sequence Alignment..." ) );
1065         customizeJMenuItem( _inference_from_msa_item );
1066         _inference_from_msa_item.setToolTipText( "Basic phylogenetic inference from MSA" );
1067         if ( im.canDoMsa() ) {
1068             _inference_menu.add( _inference_from_seqs_item = new JMenuItem( "From Unaligned Sequences..." ) );
1069             customizeJMenuItem( _inference_from_seqs_item );
1070             _inference_from_seqs_item
1071                     .setToolTipText( "Basic phylogenetic inference including multiple sequence alignment" );
1072         }
1073         else {
1074             _inference_menu
1075                     .add( _inference_from_seqs_item = new JMenuItem( "From Unaligned Sequences (no program found)" ) );
1076             customizeJMenuItem( _inference_from_seqs_item );
1077             _inference_from_seqs_item.setEnabled( false );
1078         }
1079         _jmenubar.add( _inference_menu );
1080     }
1081
1082     void buildToolsMenu() {
1083         _tools_menu = createMenu( "Tools", getConfiguration() );
1084         _tools_menu.add( _confcolor_item = new JMenuItem( "Colorize Branches Depending on Confidence" ) );
1085         customizeJMenuItem( _confcolor_item );
1086         _tools_menu.add( _color_rank_jmi = new JMenuItem( "Colorize Subtrees via Taxonomic Rank" ) );
1087         customizeJMenuItem( _color_rank_jmi );
1088         _color_rank_jmi.setToolTipText( "for example, at \"Class\" level, colorize mammal specific subtree red" );
1089         _tools_menu.add( _taxcolor_item = new JMenuItem( "Taxonomy Colorize Branches" ) );
1090         customizeJMenuItem( _taxcolor_item );
1091         _tools_menu.add( _remove_branch_color_item = new JMenuItem( "Delete Branch Colors" ) );
1092         _remove_branch_color_item.setToolTipText( "To delete branch color values from the current phylogeny" );
1093         customizeJMenuItem( _remove_branch_color_item );
1094         _tools_menu.addSeparator();
1095         _tools_menu.add( _annotate_item = new JMenuItem( "Annotate Sequences of Selected Nodes" ) );
1096         customizeJMenuItem( _annotate_item );
1097         _tools_menu.addSeparator();
1098         _tools_menu.add( _midpoint_root_item = new JMenuItem( "Midpoint-Root" ) );
1099         customizeJMenuItem( _midpoint_root_item );
1100         _tools_menu.addSeparator();
1101         _tools_menu.add( _collapse_species_specific_subtrees = new JMenuItem( "Collapse Species-Specific Subtrees" ) );
1102         customizeJMenuItem( _collapse_species_specific_subtrees );
1103         _tools_menu
1104                 .add( _collapse_below_threshold = new JMenuItem( "Collapse Branches with Confidence Below Threshold into Multifurcations" ) );
1105         customizeJMenuItem( _collapse_below_threshold );
1106         _collapse_below_threshold
1107                 .setToolTipText( "To collapse branches with confidence values below a threshold into multifurcations (in the case of multiple confidences per branch: without at least one confidence value above a threshold)" );
1108         _tools_menu.addSeparator();
1109         _tools_menu
1110                 .add( _extract_tax_code_from_node_names_jmi = new JMenuItem( "Extract Taxonomic Data from Node Names" ) );
1111         customizeJMenuItem( _extract_tax_code_from_node_names_jmi );
1112         _extract_tax_code_from_node_names_jmi
1113                 .setToolTipText( "To extract SwissProt/Uniprot taxonomic codes (mnemonics) from nodes names in the form of 'xyz_CAEEL', Uniprot/NCBI identifiers form of 'xyz_6239', or scientific names form of 'xyz_Caenorhabditis_elegans'" );
1114         _tools_menu
1115                 .add( _move_node_names_to_tax_sn_jmi = new JMenuItem( "Transfer Node Names to Taxonomic Scientific Names" ) );
1116         customizeJMenuItem( _move_node_names_to_tax_sn_jmi );
1117         _move_node_names_to_tax_sn_jmi.setToolTipText( "To interpret node names as taxonomic scientific names" );
1118         _tools_menu.add( _move_node_names_to_seq_names_jmi = new JMenuItem( "Transfer Node Names to Sequence Names" ) );
1119         customizeJMenuItem( _move_node_names_to_seq_names_jmi );
1120         _move_node_names_to_seq_names_jmi.setToolTipText( "To interpret node names as sequence (protein, gene) names" );
1121         _tools_menu.addSeparator();
1122         _tools_menu
1123                 .add( _obtain_detailed_taxonomic_information_jmi = new JMenuItem( OBTAIN_DETAILED_TAXONOMIC_INFORMATION ) );
1124         customizeJMenuItem( _obtain_detailed_taxonomic_information_jmi );
1125         _obtain_detailed_taxonomic_information_jmi
1126                 .setToolTipText( "To add additional taxonomic information (from UniProt Taxonomy)" );
1127         _tools_menu
1128                 .add( _obtain_detailed_taxonomic_information_deleting_jmi = new JMenuItem( "Obtain Detailed Taxonomic Information (deletes nodes!)" ) );
1129         customizeJMenuItem( _obtain_detailed_taxonomic_information_deleting_jmi );
1130         _obtain_detailed_taxonomic_information_deleting_jmi
1131                 .setToolTipText( "To add additional taxonomic information, deletes nodes for which taxonomy cannot found (from UniProt Taxonomy)" );
1132         _tools_menu.add( _obtain_seq_information_jmi = new JMenuItem( "Obtain Sequence Information" ) );
1133         customizeJMenuItem( _obtain_seq_information_jmi );
1134         _obtain_seq_information_jmi.setToolTipText( "To add additional sequence information" );
1135         _tools_menu.addSeparator();
1136         if ( !Constants.__RELEASE ) {
1137             _tools_menu.add( _function_analysis = new JMenuItem( "Add UniProtKB Annotations" ) );
1138             customizeJMenuItem( _function_analysis );
1139             _function_analysis
1140                     .setToolTipText( "To add UniProtKB annotations for sequences with appropriate identifiers" );
1141             _tools_menu.addSeparator();
1142         }
1143         _tools_menu.add( _read_values_jmi = new JMenuItem( "Attach Vector/Expression Values" ) );
1144         customizeJMenuItem( _read_values_jmi );
1145         _read_values_jmi.setToolTipText( "To attach vector (e.g. gene expression) values to tree nodes (beta)" );
1146         _jmenubar.add( _tools_menu );
1147         _tools_menu.add( _read_seqs_jmi = new JMenuItem( "Attach Molecular Sequences" ) );
1148         customizeJMenuItem( _read_seqs_jmi );
1149         _read_seqs_jmi
1150                 .setToolTipText( "To attach molecular sequences to tree nodes (from Fasta-formatted file) (beta)" );
1151         _jmenubar.add( _tools_menu );
1152     }
1153
1154     @Override
1155     void close() {
1156         if ( isUnsavedDataPresent() ) {
1157             final int r = JOptionPane.showConfirmDialog( this,
1158                                                          "Exit despite potentially unsaved changes?",
1159                                                          "Exit?",
1160                                                          JOptionPane.YES_NO_OPTION );
1161             if ( r != JOptionPane.YES_OPTION ) {
1162                 return;
1163             }
1164         }
1165         exit();
1166     }
1167
1168     void executeFunctionAnalysis() {
1169         if ( ( _mainpanel.getCurrentPhylogeny() == null ) || ( _mainpanel.getCurrentPhylogeny().isEmpty() ) ) {
1170             return;
1171         }
1172         final GoAnnotation a = new GoAnnotation( this,
1173                                                  _mainpanel.getCurrentTreePanel(),
1174                                                  _mainpanel.getCurrentPhylogeny() );
1175         new Thread( a ).start();
1176     }
1177
1178     void executeGSDI() {
1179         if ( !isOKforSDI( false, true ) ) {
1180             return;
1181         }
1182         if ( !_mainpanel.getCurrentPhylogeny().isRooted() ) {
1183             JOptionPane.showMessageDialog( this,
1184                                            "Gene tree is not rooted.",
1185                                            "Cannot execute GSDI",
1186                                            JOptionPane.ERROR_MESSAGE );
1187             return;
1188         }
1189         final Phylogeny gene_tree = _mainpanel.getCurrentPhylogeny().copy();
1190         gene_tree.setAllNodesToNotCollapse();
1191         gene_tree.recalculateNumberOfExternalDescendants( false );
1192         GSDI gsdi = null;
1193         final Phylogeny species_tree = _species_tree.copy();
1194         try {
1195             gsdi = new GSDI( gene_tree, species_tree, false, true, true );
1196         }
1197         catch ( final SDIException e ) {
1198             JOptionPane.showMessageDialog( this,
1199                                            e.getLocalizedMessage(),
1200                                            "Error during GSDI",
1201                                            JOptionPane.ERROR_MESSAGE );
1202             return;
1203         }
1204         catch ( final Exception e ) {
1205             AptxUtil.unexpectedException( e );
1206             return;
1207         }
1208         gene_tree.setRerootable( false );
1209         _mainpanel.getCurrentTreePanel().setTree( gene_tree );
1210         _mainpanel.getCurrentPhylogeny().clearHashIdToNodeMap();
1211         _mainpanel.getCurrentPhylogeny().recalculateNumberOfExternalDescendants( true );
1212         _mainpanel.getCurrentTreePanel().resetNodeIdToDistToLeafMap();
1213         _mainpanel.getCurrentTreePanel().setEdited( true );
1214         getControlPanel().setShowEvents( true );
1215         showWhole();
1216         final int selected = _mainpanel.getTabbedPane().getSelectedIndex();
1217         _mainpanel.addPhylogenyInNewTab( species_tree, getConfiguration(), "species tree", null );
1218         showWhole();
1219         _mainpanel.getTabbedPane().setSelectedIndex( selected );
1220         showWhole();
1221         _mainpanel.getCurrentTreePanel().setEdited( true );
1222         JOptionPane.showMessageDialog( this, "Duplications: " + gsdi.getDuplicationsSum() + "\n"
1223                 + "Potential duplications: " + gsdi.getSpeciationOrDuplicationEventsSum() + "\n" + "Speciations: "
1224                 + gsdi.getSpeciationsSum(), "GSDI successfully completed", JOptionPane.INFORMATION_MESSAGE );
1225     }
1226
1227     void executeGSDIR() {
1228         if ( !isOKforSDI( false, true ) ) {
1229             return;
1230         }
1231         final Phylogeny gene_tree = _mainpanel.getCurrentPhylogeny().copy();
1232         gene_tree.setAllNodesToNotCollapse();
1233         gene_tree.recalculateNumberOfExternalDescendants( false );
1234         GSDIR gsdir = null;
1235         final Phylogeny species_tree = _species_tree.copy();
1236         try {
1237             gsdir = new GSDIR( gene_tree, species_tree, true, true );
1238         }
1239         catch ( final SDIException e ) {
1240             JOptionPane.showMessageDialog( this,
1241                                            e.getLocalizedMessage(),
1242                                            "Error during GSDIR",
1243                                            JOptionPane.ERROR_MESSAGE );
1244             return;
1245         }
1246         catch ( final Exception e ) {
1247             AptxUtil.unexpectedException( e );
1248             return;
1249         }
1250         final Phylogeny result_gene_tree = gsdir.getMinDuplicationsSumGeneTree();
1251         result_gene_tree.setRerootable( false );
1252         result_gene_tree.clearHashIdToNodeMap();
1253         result_gene_tree.recalculateNumberOfExternalDescendants( true );
1254         _mainpanel.addPhylogenyInNewTab( result_gene_tree, getConfiguration(), "gene tree", null );
1255         getControlPanel().setShowEvents( true );
1256         showWhole();
1257         final int selected = _mainpanel.getTabbedPane().getSelectedIndex();
1258         _mainpanel.addPhylogenyInNewTab( species_tree, getConfiguration(), "species tree", null );
1259         showWhole();
1260         _mainpanel.getTabbedPane().setSelectedIndex( selected );
1261         showWhole();
1262         _mainpanel.getCurrentTreePanel().setEdited( true );
1263         JOptionPane.showMessageDialog( this,
1264                                        "Duplications (min): " + gsdir.getMinDuplicationsSum() + "\n" + "Speciations: "
1265                                                + gsdir.getSpeciationsSum(),
1266                                        "GSDIR successfully completed",
1267                                        JOptionPane.INFORMATION_MESSAGE );
1268     }
1269
1270     void executeLineageInference() {
1271         if ( ( _mainpanel.getCurrentPhylogeny() == null ) || ( _mainpanel.getCurrentPhylogeny().isEmpty() ) ) {
1272             return;
1273         }
1274         if ( !_mainpanel.getCurrentPhylogeny().isRooted() ) {
1275             JOptionPane.showMessageDialog( this,
1276                                            "Phylogeny is not rooted.",
1277                                            "Cannot infer ancestral taxonomies",
1278                                            JOptionPane.ERROR_MESSAGE );
1279             return;
1280         }
1281         final AncestralTaxonomyInferrer inferrer = new AncestralTaxonomyInferrer( this,
1282                                                                                   _mainpanel.getCurrentTreePanel(),
1283                                                                                   _mainpanel.getCurrentPhylogeny()
1284                                                                                           .copy() );
1285         new Thread( inferrer ).start();
1286     }
1287
1288     void executeSDIR( final boolean minimize_cost ) {
1289         if ( !isOKforSDI( true, true ) ) {
1290             return;
1291         }
1292         Phylogeny gene_tree = _mainpanel.getCurrentPhylogeny().copy();
1293         final SDIR sdiunrooted = new SDIR();
1294         gene_tree.setAllNodesToNotCollapse();
1295         gene_tree.recalculateNumberOfExternalDescendants( false );
1296         try {
1297             gene_tree = sdiunrooted.infer( gene_tree, _species_tree, minimize_cost, // minimize cost
1298                                            !minimize_cost, // minimize sum of dups
1299                                            true, // minimize height
1300                                            true, // return tree(s)
1301                                            1 )[ 0 ]; // # of trees to return
1302         }
1303         catch ( final Exception e ) {
1304             JOptionPane.showMessageDialog( this, e.toString(), "Error during SDIR", JOptionPane.ERROR_MESSAGE );
1305             return;
1306         }
1307         final int duplications = sdiunrooted.getMinimalDuplications();
1308         gene_tree.setRerootable( false );
1309         _mainpanel.getCurrentTreePanel().setTree( gene_tree );
1310         getControlPanel().setShowEvents( true );
1311         showWhole();
1312         _mainpanel.getCurrentTreePanel().setEdited( true );
1313         JOptionPane.showMessageDialog( this,
1314                                        "Number of duplications: " + duplications,
1315                                        "SDIR successfully completed",
1316                                        JOptionPane.INFORMATION_MESSAGE );
1317     }
1318
1319     void exit() {
1320         removeAllTextFrames();
1321         _mainpanel.terminate();
1322         _contentpane.removeAll();
1323         setVisible( false );
1324         dispose();
1325         System.exit( 0 );
1326     }
1327
1328     boolean isOKforSDI( final boolean species_tree_has_to_binary, final boolean gene_tree_has_to_binary ) {
1329         if ( ( _mainpanel.getCurrentPhylogeny() == null ) || _mainpanel.getCurrentPhylogeny().isEmpty() ) {
1330             return false;
1331         }
1332         else if ( ( _species_tree == null ) || _species_tree.isEmpty() ) {
1333             JOptionPane.showMessageDialog( this,
1334                                            "No species tree loaded",
1335                                            "Cannot execute SDI",
1336                                            JOptionPane.ERROR_MESSAGE );
1337             return false;
1338         }
1339         else if ( species_tree_has_to_binary && !_species_tree.isCompletelyBinary() ) {
1340             JOptionPane.showMessageDialog( this,
1341                                            "Species tree is not completely binary",
1342                                            "Cannot execute SDI",
1343                                            JOptionPane.ERROR_MESSAGE );
1344             return false;
1345         }
1346         else if ( gene_tree_has_to_binary && !_mainpanel.getCurrentPhylogeny().isCompletelyBinary() ) {
1347             JOptionPane.showMessageDialog( this,
1348                                            "Gene tree is not completely binary",
1349                                            "Cannot execute SDI",
1350                                            JOptionPane.ERROR_MESSAGE );
1351             return false;
1352         }
1353         else {
1354             return true;
1355         }
1356     }
1357
1358     @Override
1359     void readPhylogeniesFromURL() {
1360         URL url = null;
1361         Phylogeny[] phys = null;
1362         final String message = "Please enter a complete URL, for example \"http://www.phyloxml.org/examples/apaf.xml\"";
1363         final String url_string = JOptionPane.showInputDialog( this,
1364                                                                message,
1365                                                                "Use URL/webservice to obtain a phylogeny",
1366                                                                JOptionPane.QUESTION_MESSAGE );
1367         boolean nhx_or_nexus = false;
1368         if ( ( url_string != null ) && ( url_string.length() > 0 ) ) {
1369             try {
1370                 url = new URL( url_string );
1371                 PhylogenyParser parser = null;
1372                 if ( url.getHost().toLowerCase().indexOf( "tolweb" ) >= 0 ) {
1373                     parser = new TolParser();
1374                 }
1375                 else {
1376                     parser = ParserUtils.createParserDependingOnUrlContents( url, getConfiguration()
1377                             .isValidatePhyloXmlAgainstSchema() );
1378                 }
1379                 if ( parser instanceof NexusPhylogeniesParser ) {
1380                     nhx_or_nexus = true;
1381                 }
1382                 else if ( parser instanceof NHXParser ) {
1383                     nhx_or_nexus = true;
1384                 }
1385                 if ( _mainpanel.getCurrentTreePanel() != null ) {
1386                     _mainpanel.getCurrentTreePanel().setWaitCursor();
1387                 }
1388                 else {
1389                     _mainpanel.setWaitCursor();
1390                 }
1391                 final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance();
1392                 phys = factory.create( url.openStream(), parser );
1393             }
1394             catch ( final MalformedURLException e ) {
1395                 JOptionPane.showMessageDialog( this,
1396                                                "Malformed URL: " + url + "\n" + e.getLocalizedMessage(),
1397                                                "Malformed URL",
1398                                                JOptionPane.ERROR_MESSAGE );
1399             }
1400             catch ( final IOException e ) {
1401                 JOptionPane.showMessageDialog( this,
1402                                                "Could not read from " + url + "\n"
1403                                                        + ForesterUtil.wordWrap( e.getLocalizedMessage(), 80 ),
1404                                                "Failed to read URL",
1405                                                JOptionPane.ERROR_MESSAGE );
1406             }
1407             catch ( final Exception e ) {
1408                 JOptionPane.showMessageDialog( this,
1409                                                ForesterUtil.wordWrap( e.getLocalizedMessage(), 80 ),
1410                                                "Unexpected Exception",
1411                                                JOptionPane.ERROR_MESSAGE );
1412             }
1413             finally {
1414                 if ( _mainpanel.getCurrentTreePanel() != null ) {
1415                     _mainpanel.getCurrentTreePanel().setArrowCursor();
1416                 }
1417                 else {
1418                     _mainpanel.setArrowCursor();
1419                 }
1420             }
1421             if ( ( phys != null ) && ( phys.length > 0 ) ) {
1422                 if ( nhx_or_nexus && getOptions().isInternalNumberAreConfidenceForNhParsing() ) {
1423                     for( final Phylogeny phy : phys ) {
1424                         PhylogenyMethods.transferInternalNodeNamesToConfidence( phy );
1425                     }
1426                 }
1427                 AptxUtil.addPhylogeniesToTabs( phys,
1428                                                new File( url.getFile() ).getName(),
1429                                                new File( url.getFile() ).toString(),
1430                                                getConfiguration(),
1431                                                getMainPanel() );
1432                 _mainpanel.getControlPanel().showWhole();
1433             }
1434         }
1435         activateSaveAllIfNeeded();
1436         System.gc();
1437     }
1438
1439     void setMsa( final Msa msa ) {
1440         _msa = msa;
1441     }
1442
1443     void setMsaFile( final File msa_file ) {
1444         _msa_file = msa_file;
1445     }
1446
1447     void setSeqs( final List<Sequence> seqs ) {
1448         _seqs = seqs;
1449     }
1450
1451     void setSeqsFile( final File seqs_file ) {
1452         _seqs_file = seqs_file;
1453     }
1454
1455     void writePhylogenyToGraphicsFile( final String file_name, final GraphicsExportType type ) {
1456         _mainpanel.getCurrentTreePanel().calcParametersForPainting( _mainpanel.getCurrentTreePanel().getWidth(),
1457                                                                     _mainpanel.getCurrentTreePanel().getHeight(),
1458                                                                     true );
1459         String file_written_to = "";
1460         boolean error = false;
1461         try {
1462             file_written_to = AptxUtil.writePhylogenyToGraphicsFile( file_name,
1463                                                                      _mainpanel.getCurrentTreePanel().getWidth(),
1464                                                                      _mainpanel.getCurrentTreePanel().getHeight(),
1465                                                                      _mainpanel.getCurrentTreePanel(),
1466                                                                      _mainpanel.getControlPanel(),
1467                                                                      type,
1468                                                                      getOptions() );
1469         }
1470         catch ( final IOException e ) {
1471             error = true;
1472             JOptionPane.showMessageDialog( this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE );
1473         }
1474         if ( !error ) {
1475             if ( ( file_written_to != null ) && ( file_written_to.length() > 0 ) ) {
1476                 JOptionPane.showMessageDialog( this,
1477                                                "Wrote image to: " + file_written_to,
1478                                                "Graphics Export",
1479                                                JOptionPane.INFORMATION_MESSAGE );
1480             }
1481             else {
1482                 JOptionPane.showMessageDialog( this,
1483                                                "There was an unknown problem when attempting to write to an image file: \""
1484                                                        + file_name + "\"",
1485                                                "Error",
1486                                                JOptionPane.ERROR_MESSAGE );
1487             }
1488         }
1489         _contentpane.repaint();
1490     }
1491
1492     private void addSequencesFromFile() {
1493         if ( ( getCurrentTreePanel() == null ) || ( getCurrentTreePanel().getPhylogeny() == null ) ) {
1494             JOptionPane.showMessageDialog( this,
1495                                            "Need to load evolutionary tree first",
1496                                            "Can Not Read Sequences",
1497                                            JOptionPane.WARNING_MESSAGE );
1498             return;
1499         }
1500         final File my_dir = getCurrentDir();
1501         if ( my_dir != null ) {
1502             _sequences_filechooser.setCurrentDirectory( my_dir );
1503         }
1504         final int result = _sequences_filechooser.showOpenDialog( _contentpane );
1505         final File file = _sequences_filechooser.getSelectedFile();
1506         List<Sequence> seqs = null;
1507         if ( ( file != null ) && !file.isDirectory() && ( result == JFileChooser.APPROVE_OPTION ) ) {
1508             try {
1509                 if ( FastaParser.isLikelyFasta( new FileInputStream( file ) ) ) {
1510                     seqs = FastaParser.parse( new FileInputStream( file ) );
1511                 }
1512                 else {
1513                     JOptionPane.showMessageDialog( this,
1514                                                    "Format does not appear to be Fasta",
1515                                                    "Multiple sequence file format error",
1516                                                    JOptionPane.ERROR_MESSAGE );
1517                     return;
1518                 }
1519             }
1520             catch ( final MsaFormatException e ) {
1521                 setArrowCursor();
1522                 JOptionPane.showMessageDialog( this,
1523                                                e.getLocalizedMessage(),
1524                                                "Multiple sequence file format error",
1525                                                JOptionPane.ERROR_MESSAGE );
1526                 return;
1527             }
1528             catch ( final IOException e ) {
1529                 setArrowCursor();
1530                 JOptionPane.showMessageDialog( this,
1531                                                e.getLocalizedMessage(),
1532                                                "Failed to read multiple sequence file",
1533                                                JOptionPane.ERROR_MESSAGE );
1534                 return;
1535             }
1536             catch ( final Exception e ) {
1537                 setArrowCursor();
1538                 e.printStackTrace();
1539                 JOptionPane.showMessageDialog( this,
1540                                                e.getLocalizedMessage(),
1541                                                "Unexpected error during reading of multiple sequence file",
1542                                                JOptionPane.ERROR_MESSAGE );
1543                 return;
1544             }
1545             if ( ( seqs == null ) || ( seqs.size() < 1 ) ) {
1546                 JOptionPane.showMessageDialog( this,
1547                                                "Multiple sequence file is empty",
1548                                                "Empty multiple sequence file",
1549                                                JOptionPane.ERROR_MESSAGE );
1550                 setArrowCursor();
1551                 return;
1552             }
1553         }
1554         if ( seqs != null ) {
1555             for( final Sequence seq : seqs ) {
1556                 System.out.println( seq.getIdentifier() );
1557             }
1558             final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
1559             int total_counter = 0;
1560             int attached_counter = 0;
1561             for( final Sequence seq : seqs ) {
1562                 ++total_counter;
1563                 final String seq_name = seq.getIdentifier();
1564                 if ( !ForesterUtil.isEmpty( seq_name ) ) {
1565                     List<PhylogenyNode> nodes = phy.getNodesViaSequenceName( seq_name );
1566                     if ( nodes.isEmpty() ) {
1567                         nodes = phy.getNodesViaSequenceSymbol( seq_name );
1568                     }
1569                     if ( nodes.isEmpty() ) {
1570                         nodes = phy.getNodes( seq_name );
1571                     }
1572                     if ( nodes.size() > 1 ) {
1573                         JOptionPane.showMessageDialog( this,
1574                                                        "Sequence name \"" + seq_name + "\" is not unique",
1575                                                        "Sequence name not unique",
1576                                                        JOptionPane.ERROR_MESSAGE );
1577                         setArrowCursor();
1578                         return;
1579                     }
1580                     final String[] a = seq_name.split( "\\s" );
1581                     if ( nodes.isEmpty() && ( a.length > 1 ) ) {
1582                         final String seq_name_split = a[ 0 ];
1583                         nodes = phy.getNodesViaSequenceName( seq_name_split );
1584                         if ( nodes.isEmpty() ) {
1585                             nodes = phy.getNodesViaSequenceSymbol( seq_name_split );
1586                         }
1587                         if ( nodes.isEmpty() ) {
1588                             nodes = phy.getNodes( seq_name_split );
1589                         }
1590                         if ( nodes.size() > 1 ) {
1591                             JOptionPane.showMessageDialog( this, "Split sequence name \"" + seq_name_split
1592                                     + "\" is not unique", "Sequence name not unique", JOptionPane.ERROR_MESSAGE );
1593                             setArrowCursor();
1594                             return;
1595                         }
1596                     }
1597                     if ( nodes.size() == 1 ) {
1598                         ++attached_counter;
1599                         final PhylogenyNode n = nodes.get( 0 );
1600                         if ( !n.getNodeData().isHasSequence() ) {
1601                             n.getNodeData().addSequence( new org.forester.phylogeny.data.Sequence() );
1602                         }
1603                         n.getNodeData().getSequence().setMolecularSequence( seq.getMolecularSequenceAsString() );
1604                         if ( ForesterUtil.isEmpty( n.getNodeData().getSequence().getName() ) ) {
1605                             n.getNodeData().getSequence().setName( seq_name );
1606                         }
1607                     }
1608                 }
1609             }
1610             if ( attached_counter > 0 ) {
1611                 int ext_nodes = 0;
1612                 int ext_nodes_with_seq = 0;
1613                 for( final PhylogenyNodeIterator iter = phy.iteratorExternalForward(); iter.hasNext(); ) {
1614                     ++ext_nodes;
1615                     final PhylogenyNode n = iter.next();
1616                     if ( n.getNodeData().isHasSequence()
1617                             && !ForesterUtil.isEmpty( n.getNodeData().getSequence().getMolecularSequence() ) ) {
1618                         ++ext_nodes_with_seq;
1619                     }
1620                 }
1621                 final String s;
1622                 if ( ext_nodes == ext_nodes_with_seq ) {
1623                     s = "All " + ext_nodes_with_seq + " external nodes now have a molecular sequence attached to them.";
1624                 }
1625                 else {
1626                     s = ext_nodes_with_seq + " out of " + ext_nodes
1627                             + " external nodes now have a molecular sequence attached to them.";
1628                 }
1629                 if ( ( attached_counter == total_counter ) && ( ext_nodes == ext_nodes_with_seq ) ) {
1630                     JOptionPane.showMessageDialog( this,
1631                                                    "Attached all " + total_counter + " sequences to tree nodes.\n" + s,
1632                                                    "All sequences attached",
1633                                                    JOptionPane.INFORMATION_MESSAGE );
1634                 }
1635                 else {
1636                     JOptionPane.showMessageDialog( this, "Attached " + attached_counter
1637                             + " sequences out of a total of " + total_counter + " sequences.\n" + s, attached_counter
1638                             + " sequences attached", JOptionPane.WARNING_MESSAGE );
1639                 }
1640             }
1641             else {
1642                 JOptionPane.showMessageDialog( this, "No maching tree node for any of the " + total_counter
1643                         + " sequences", "Could not attach any sequences", JOptionPane.ERROR_MESSAGE );
1644             }
1645         }
1646     }
1647
1648     private void setArrowCursor() {
1649         try {
1650             _mainpanel.getCurrentTreePanel().setArrowCursor();
1651         }
1652         catch ( final Exception ex ) {
1653             // Do nothing.
1654         }
1655     }
1656
1657     private void addExpressionValuesFromFile() {
1658         if ( ( getCurrentTreePanel() == null ) || ( getCurrentTreePanel().getPhylogeny() == null ) ) {
1659             JOptionPane.showMessageDialog( this,
1660                                            "Need to load evolutionary tree first",
1661                                            "Can Not Read Expression Values",
1662                                            JOptionPane.WARNING_MESSAGE );
1663             return;
1664         }
1665         final File my_dir = getCurrentDir();
1666         if ( my_dir != null ) {
1667             _values_filechooser.setCurrentDirectory( my_dir );
1668         }
1669         final int result = _values_filechooser.showOpenDialog( _contentpane );
1670         final File file = _values_filechooser.getSelectedFile();
1671         if ( ( file != null ) && ( file.length() > 0 ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
1672             BasicTable<String> t = null;
1673             try {
1674                 t = BasicTableParser.parse( file, "\t" );
1675                 if ( t.getNumberOfColumns() < 2 ) {
1676                     t = BasicTableParser.parse( file, "," );
1677                 }
1678                 if ( t.getNumberOfColumns() < 2 ) {
1679                     t = BasicTableParser.parse( file, " " );
1680                 }
1681             }
1682             catch ( final IOException e ) {
1683                 JOptionPane.showMessageDialog( this,
1684                                                e.getMessage(),
1685                                                "Could Not Read Expression Value Table",
1686                                                JOptionPane.ERROR_MESSAGE );
1687                 return;
1688             }
1689             if ( t.getNumberOfColumns() < 2 ) {
1690                 JOptionPane.showMessageDialog( this,
1691                                                "Table contains " + t.getNumberOfColumns() + " column(s)",
1692                                                "Problem with Expression Value Table",
1693                                                JOptionPane.ERROR_MESSAGE );
1694                 return;
1695             }
1696             if ( t.getNumberOfRows() < 1 ) {
1697                 JOptionPane.showMessageDialog( this,
1698                                                "Table contains zero rows",
1699                                                "Problem with Expression Value Table",
1700                                                JOptionPane.ERROR_MESSAGE );
1701                 return;
1702             }
1703             final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
1704             if ( t.getNumberOfRows() != phy.getNumberOfExternalNodes() ) {
1705                 JOptionPane.showMessageDialog( this,
1706                                                "Table contains " + t.getNumberOfRows() + " rows, but tree contains "
1707                                                        + phy.getNumberOfExternalNodes() + " external nodes",
1708                                                "Warning",
1709                                                JOptionPane.WARNING_MESSAGE );
1710             }
1711             final DescriptiveStatistics stats = new BasicDescriptiveStatistics();
1712             int not_found = 0;
1713             for( final PhylogenyNodeIterator iter = phy.iteratorPreorder(); iter.hasNext(); ) {
1714                 final PhylogenyNode node = iter.next();
1715                 final String node_name = node.getName();
1716                 if ( !ForesterUtil.isEmpty( node_name ) ) {
1717                     int row = -1;
1718                     try {
1719                         row = t.findRow( node_name );
1720                     }
1721                     catch ( final IllegalArgumentException e ) {
1722                         JOptionPane
1723                                 .showMessageDialog( this,
1724                                                     e.getMessage(),
1725                                                     "Error Mapping Node Identifiers to Expression Value Identifiers",
1726                                                     JOptionPane.ERROR_MESSAGE );
1727                         return;
1728                     }
1729                     if ( row < 0 ) {
1730                         if ( node.isExternal() ) {
1731                             not_found++;
1732                         }
1733                         continue;
1734                     }
1735                     final List<Double> l = new ArrayList<Double>();
1736                     for( int col = 1; col < t.getNumberOfColumns(); ++col ) {
1737                         double d = -100;
1738                         try {
1739                             d = Double.parseDouble( t.getValueAsString( col, row ) );
1740                         }
1741                         catch ( final NumberFormatException e ) {
1742                             JOptionPane.showMessageDialog( this,
1743                                                            "Could not parse \"" + t.getValueAsString( col, row )
1744                                                                    + "\" into a decimal value",
1745                                                            "Issue with Expression Value Table",
1746                                                            JOptionPane.ERROR_MESSAGE );
1747                             return;
1748                         }
1749                         stats.addValue( d );
1750                         l.add( d );
1751                     }
1752                     if ( !l.isEmpty() ) {
1753                         if ( node.getNodeData().getProperties() != null ) {
1754                             node.getNodeData().getProperties()
1755                                     .removePropertiesWithGivenReferencePrefix( PhyloXmlUtil.VECTOR_PROPERTY_REF );
1756                         }
1757                         node.getNodeData().setVector( l );
1758                     }
1759                 }
1760             }
1761             if ( not_found > 0 ) {
1762                 JOptionPane.showMessageDialog( this, "Could not fine expression values for " + not_found
1763                         + " external node(s)", "Warning", JOptionPane.WARNING_MESSAGE );
1764             }
1765             getCurrentTreePanel().setStatisticsForExpressionValues( stats );
1766         }
1767     }
1768
1769     private void choosePdfWidth() {
1770         final String s = ( String ) JOptionPane.showInputDialog( this,
1771                                                                  "Please enter the default line width for PDF export.\n"
1772                                                                          + "[current value: "
1773                                                                          + getOptions().getPrintLineWidth() + "]\n",
1774                                                                  "Line Width for PDF Export",
1775                                                                  JOptionPane.QUESTION_MESSAGE,
1776                                                                  null,
1777                                                                  null,
1778                                                                  getOptions().getPrintLineWidth() );
1779         if ( !ForesterUtil.isEmpty( s ) ) {
1780             boolean success = true;
1781             float f = 0.0f;
1782             final String m_str = s.trim();
1783             if ( !ForesterUtil.isEmpty( m_str ) ) {
1784                 try {
1785                     f = Float.parseFloat( m_str );
1786                 }
1787                 catch ( final Exception ex ) {
1788                     success = false;
1789                 }
1790             }
1791             else {
1792                 success = false;
1793             }
1794             if ( success && ( f > 0.0 ) ) {
1795                 getOptions().setPrintLineWidth( f );
1796             }
1797         }
1798     }
1799
1800     private void choosePrintSize() {
1801         final String s = ( String ) JOptionPane.showInputDialog( this,
1802                                                                  "Please enter values for width and height,\nseparated by a comma.\n"
1803                                                                          + "[current values: "
1804                                                                          + getOptions().getPrintSizeX() + ", "
1805                                                                          + getOptions().getPrintSizeY() + "]\n"
1806                                                                          + "[A4: " + Constants.A4_SIZE_X + ", "
1807                                                                          + Constants.A4_SIZE_Y + "]\n" + "[US Letter: "
1808                                                                          + Constants.US_LETTER_SIZE_X + ", "
1809                                                                          + Constants.US_LETTER_SIZE_Y + "]",
1810                                                                  "Default Size for Graphics Export",
1811                                                                  JOptionPane.QUESTION_MESSAGE,
1812                                                                  null,
1813                                                                  null,
1814                                                                  getOptions().getPrintSizeX() + ", "
1815                                                                          + getOptions().getPrintSizeY() );
1816         if ( !ForesterUtil.isEmpty( s ) && ( s.indexOf( ',' ) > 0 ) ) {
1817             boolean success = true;
1818             int x = 0;
1819             int y = 0;
1820             final String[] str_ary = s.split( "," );
1821             if ( str_ary.length == 2 ) {
1822                 final String x_str = str_ary[ 0 ].trim();
1823                 final String y_str = str_ary[ 1 ].trim();
1824                 if ( !ForesterUtil.isEmpty( x_str ) && !ForesterUtil.isEmpty( y_str ) ) {
1825                     try {
1826                         x = Integer.parseInt( x_str );
1827                         y = Integer.parseInt( y_str );
1828                     }
1829                     catch ( final Exception ex ) {
1830                         success = false;
1831                     }
1832                 }
1833                 else {
1834                     success = false;
1835                 }
1836             }
1837             else {
1838                 success = false;
1839             }
1840             if ( success && ( x > 1 ) && ( y > 1 ) ) {
1841                 getOptions().setPrintSizeX( x );
1842                 getOptions().setPrintSizeY( y );
1843             }
1844         }
1845     }
1846
1847     private void closeCurrentPane() {
1848         if ( getMainPanel().getCurrentTreePanel() != null ) {
1849             if ( getMainPanel().getCurrentTreePanel().isEdited() ) {
1850                 final int r = JOptionPane.showConfirmDialog( this,
1851                                                              "Close tab despite potentially unsaved changes?",
1852                                                              "Close Tab?",
1853                                                              JOptionPane.YES_NO_OPTION );
1854                 if ( r != JOptionPane.YES_OPTION ) {
1855                     return;
1856                 }
1857             }
1858             getMainPanel().closeCurrentPane();
1859             activateSaveAllIfNeeded();
1860         }
1861     }
1862
1863     private void collapse( final Phylogeny phy, final double m ) {
1864         final PhylogenyNodeIterator it = phy.iteratorPostorder();
1865         final List<PhylogenyNode> to_be_removed = new ArrayList<PhylogenyNode>();
1866         double min_support = Double.MAX_VALUE;
1867         boolean conf_present = false;
1868         while ( it.hasNext() ) {
1869             final PhylogenyNode n = it.next();
1870             if ( !n.isExternal() && !n.isRoot() ) {
1871                 final List<Confidence> c = n.getBranchData().getConfidences();
1872                 if ( ( c != null ) && ( c.size() > 0 ) ) {
1873                     conf_present = true;
1874                     double max = 0;
1875                     for( final Confidence confidence : c ) {
1876                         if ( confidence.getValue() > max ) {
1877                             max = confidence.getValue();
1878                         }
1879                     }
1880                     if ( max < getMinNotCollapseConfidenceValue() ) {
1881                         to_be_removed.add( n );
1882                     }
1883                     if ( max < min_support ) {
1884                         min_support = max;
1885                     }
1886                 }
1887             }
1888         }
1889         if ( conf_present ) {
1890             for( final PhylogenyNode node : to_be_removed ) {
1891                 PhylogenyMethods.removeNode( node, phy );
1892             }
1893             if ( to_be_removed.size() > 0 ) {
1894                 phy.externalNodesHaveChanged();
1895                 phy.clearHashIdToNodeMap();
1896                 phy.recalculateNumberOfExternalDescendants( true );
1897                 getCurrentTreePanel().resetNodeIdToDistToLeafMap();
1898                 getCurrentTreePanel().updateSetOfCollapsedExternalNodes();
1899                 getCurrentTreePanel().calculateLongestExtNodeInfo();
1900                 getCurrentTreePanel().setNodeInPreorderToNull();
1901                 getCurrentTreePanel().recalculateMaxDistanceToRoot();
1902                 getCurrentTreePanel().resetPreferredSize();
1903                 getCurrentTreePanel().setEdited( true );
1904                 getCurrentTreePanel().repaint();
1905                 repaint();
1906             }
1907             if ( to_be_removed.size() > 0 ) {
1908                 JOptionPane.showMessageDialog( this, "Collapsed " + to_be_removed.size()
1909                         + " branches with\nconfidence values below " + getMinNotCollapseConfidenceValue(), "Collapsed "
1910                         + to_be_removed.size() + " branches", JOptionPane.INFORMATION_MESSAGE );
1911             }
1912             else {
1913                 JOptionPane.showMessageDialog( this, "No branch collapsed,\nminimum confidence value per branch is "
1914                         + min_support, "No branch collapsed", JOptionPane.INFORMATION_MESSAGE );
1915             }
1916         }
1917         else {
1918             JOptionPane.showMessageDialog( this,
1919                                            "No branch collapsed because no confidence values present",
1920                                            "No confidence values present",
1921                                            JOptionPane.INFORMATION_MESSAGE );
1922         }
1923     }
1924
1925     private void collapseBelowThreshold() {
1926         if ( getCurrentTreePanel() != null ) {
1927             final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
1928             if ( ( phy != null ) && !phy.isEmpty() ) {
1929                 final String s = ( String ) JOptionPane.showInputDialog( this,
1930                                                                          "Please enter the minimum confidence value\n",
1931                                                                          "Minimal Confidence Value",
1932                                                                          JOptionPane.QUESTION_MESSAGE,
1933                                                                          null,
1934                                                                          null,
1935                                                                          getMinNotCollapseConfidenceValue() );
1936                 if ( !ForesterUtil.isEmpty( s ) ) {
1937                     boolean success = true;
1938                     double m = 0.0;
1939                     final String m_str = s.trim();
1940                     if ( !ForesterUtil.isEmpty( m_str ) ) {
1941                         try {
1942                             m = Double.parseDouble( m_str );
1943                         }
1944                         catch ( final Exception ex ) {
1945                             success = false;
1946                         }
1947                     }
1948                     else {
1949                         success = false;
1950                     }
1951                     if ( success && ( m >= 0.0 ) ) {
1952                         setMinNotCollapseConfidenceValue( m );
1953                         collapse( phy, m );
1954                     }
1955                 }
1956             }
1957         }
1958     }
1959
1960     private PhyloXmlParser createPhyloXmlParser() {
1961         PhyloXmlParser xml_parser = null;
1962         if ( getConfiguration().isValidatePhyloXmlAgainstSchema() ) {
1963             try {
1964                 xml_parser = PhyloXmlParser.createPhyloXmlParserXsdValidating();
1965             }
1966             catch ( final Exception e ) {
1967                 JOptionPane.showMessageDialog( this,
1968                                                e.getLocalizedMessage(),
1969                                                "failed to create validating XML parser",
1970                                                JOptionPane.WARNING_MESSAGE );
1971             }
1972         }
1973         if ( xml_parser == null ) {
1974             xml_parser = new PhyloXmlParser();
1975         }
1976         return xml_parser;
1977     }
1978
1979     private void executePhyleneticInference( final boolean from_unaligned_seqs ) {
1980         final PhyloInferenceDialog dialog = new PhyloInferenceDialog( this,
1981                                                                       getPhylogeneticInferenceOptions(),
1982                                                                       from_unaligned_seqs );
1983         dialog.activate();
1984         if ( dialog.getValue() == JOptionPane.OK_OPTION ) {
1985             if ( !from_unaligned_seqs ) {
1986                 if ( getMsa() != null ) {
1987                     final PhylogeneticInferrer inferrer = new PhylogeneticInferrer( getMsa(),
1988                                                                                     getPhylogeneticInferenceOptions()
1989                                                                                             .copy(), this );
1990                     new Thread( inferrer ).start();
1991                 }
1992                 else {
1993                     JOptionPane.showMessageDialog( this,
1994                                                    "No multiple sequence alignment selected",
1995                                                    "Phylogenetic Inference Not Launched",
1996                                                    JOptionPane.WARNING_MESSAGE );
1997                 }
1998             }
1999             else {
2000                 if ( getSeqs() != null ) {
2001                     final PhylogeneticInferrer inferrer = new PhylogeneticInferrer( getSeqs(),
2002                                                                                     getPhylogeneticInferenceOptions()
2003                                                                                             .copy(), this );
2004                     new Thread( inferrer ).start();
2005                 }
2006                 else {
2007                     JOptionPane.showMessageDialog( this,
2008                                                    "No input sequences selected",
2009                                                    "Phylogenetic Inference Not Launched",
2010                                                    JOptionPane.WARNING_MESSAGE );
2011                 }
2012             }
2013         }
2014     }
2015
2016     private void extractTaxDataFromNodeNames() throws PhyloXmlDataFormatException {
2017         final StringBuilder sb = new StringBuilder();
2018         final StringBuilder sb_failed = new StringBuilder();
2019         int counter = 0;
2020         int counter_failed = 0;
2021         if ( getCurrentTreePanel() != null ) {
2022             final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
2023             if ( ( phy != null ) && !phy.isEmpty() ) {
2024                 final PhylogenyNodeIterator it = phy.iteratorExternalForward();
2025                 while ( it.hasNext() ) {
2026                     final PhylogenyNode n = it.next();
2027                     final String name = n.getName().trim();
2028                     if ( !ForesterUtil.isEmpty( name ) ) {
2029                         final String nt = ParserUtils
2030                                 .extractTaxonomyDataFromNodeName( n, TAXONOMY_EXTRACTION.PFAM_STYLE_RELAXED );
2031                         if ( !ForesterUtil.isEmpty( nt ) ) {
2032                             if ( counter < 15 ) {
2033                                 sb.append( name + ": " + nt + "\n" );
2034                             }
2035                             else if ( counter == 15 ) {
2036                                 sb.append( "...\n" );
2037                             }
2038                             counter++;
2039                         }
2040                         else {
2041                             if ( counter_failed < 15 ) {
2042                                 sb_failed.append( name + "\n" );
2043                             }
2044                             else if ( counter_failed == 15 ) {
2045                                 sb_failed.append( "...\n" );
2046                             }
2047                             counter_failed++;
2048                         }
2049                     }
2050                 }
2051                 if ( counter > 0 ) {
2052                     String failed = "";
2053                     String all = "all ";
2054                     if ( counter_failed > 0 ) {
2055                         all = "";
2056                         failed = "\nCould not extract taxonomic data for " + counter_failed
2057                                 + " named external nodes:\n" + sb_failed;
2058                     }
2059                     JOptionPane.showMessageDialog( this,
2060                                                    "Extracted taxonomic data from " + all + counter
2061                                                            + " named external nodes:\n" + sb.toString() + failed,
2062                                                    "Taxonomic Data Extraction Completed",
2063                                                    counter_failed > 0 ? JOptionPane.WARNING_MESSAGE
2064                                                            : JOptionPane.INFORMATION_MESSAGE );
2065                 }
2066                 else {
2067                     JOptionPane
2068                             .showMessageDialog( this,
2069                                                 "Could not extract any taxonomic data.\nMaybe node names are empty\n"
2070                                                         + "or not in the forms \"XYZ_CAEEL\", \"XYZ_6239\", or \"XYZ_Caenorhabditis_elegans\"\n"
2071                                                         + "or nodes already have taxonomic data?\n",
2072                                                 "No Taxonomic Data Extracted",
2073                                                 JOptionPane.ERROR_MESSAGE );
2074                 }
2075             }
2076         }
2077     }
2078
2079     private ControlPanel getControlPanel() {
2080         return getMainPanel().getControlPanel();
2081     }
2082
2083     private File getCurrentDir() {
2084         if ( ( _current_dir == null ) || !_current_dir.canRead() ) {
2085             if ( ForesterUtil.isWindowns() ) {
2086                 try {
2087                     _current_dir = new File( WindowsUtils.getCurrentUserDesktopPath() );
2088                 }
2089                 catch ( final Exception e ) {
2090                     _current_dir = null;
2091                 }
2092             }
2093         }
2094         if ( ( _current_dir == null ) || !_current_dir.canRead() ) {
2095             if ( System.getProperty( "user.home" ) != null ) {
2096                 _current_dir = new File( System.getProperty( "user.home" ) );
2097             }
2098             else if ( System.getProperty( "user.dir" ) != null ) {
2099                 _current_dir = new File( System.getProperty( "user.dir" ) );
2100             }
2101         }
2102         return _current_dir;
2103     }
2104
2105     private double getMinNotCollapseConfidenceValue() {
2106         return _min_not_collapse;
2107     }
2108
2109     private PhylogeneticInferenceOptions getPhylogeneticInferenceOptions() {
2110         if ( _phylogenetic_inference_options == null ) {
2111             _phylogenetic_inference_options = new PhylogeneticInferenceOptions();
2112         }
2113         return _phylogenetic_inference_options;
2114     }
2115
2116     private boolean isUnsavedDataPresent() {
2117         final List<TreePanel> tps = getMainPanel().getTreePanels();
2118         for( final TreePanel tp : tps ) {
2119             if ( tp.isEdited() ) {
2120                 return true;
2121             }
2122         }
2123         return false;
2124     }
2125
2126     private void moveNodeNamesToSeqNames() throws PhyloXmlDataFormatException {
2127         if ( getCurrentTreePanel() != null ) {
2128             final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
2129             if ( ( phy != null ) && !phy.isEmpty() ) {
2130                 PhylogenyMethods
2131                         .transferNodeNameToField( phy, PhylogenyMethods.PhylogenyNodeField.SEQUENCE_NAME, false );
2132             }
2133         }
2134     }
2135
2136     private void moveNodeNamesToTaxSn() throws PhyloXmlDataFormatException {
2137         if ( getCurrentTreePanel() != null ) {
2138             final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
2139             if ( ( phy != null ) && !phy.isEmpty() ) {
2140                 PhylogenyMethods.transferNodeNameToField( phy,
2141                                                           PhylogenyMethods.PhylogenyNodeField.TAXONOMY_SCIENTIFIC_NAME,
2142                                                           false );
2143             }
2144         }
2145     }
2146
2147     private void newTree() {
2148         final Phylogeny[] phys = new Phylogeny[ 1 ];
2149         final Phylogeny phy = new Phylogeny();
2150         final PhylogenyNode node = new PhylogenyNode();
2151         phy.setRoot( node );
2152         phy.setRooted( true );
2153         phys[ 0 ] = phy;
2154         AptxUtil.addPhylogeniesToTabs( phys, "", "", getConfiguration(), getMainPanel() );
2155         _mainpanel.getControlPanel().showWhole();
2156         _mainpanel.getCurrentTreePanel().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
2157         _mainpanel.getOptions().setPhylogenyGraphicsType( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
2158         if ( getMainPanel().getMainFrame() == null ) {
2159             // Must be "E" applet version.
2160             ( ( ArchaeopteryxE ) ( ( MainPanelApplets ) getMainPanel() ).getApplet() )
2161                     .setSelectedTypeInTypeMenu( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
2162         }
2163         else {
2164             getMainPanel().getMainFrame().setSelectedTypeInTypeMenu( PHYLOGENY_GRAPHICS_TYPE.RECTANGULAR );
2165         }
2166         activateSaveAllIfNeeded();
2167         System.gc();
2168     }
2169
2170     private void obtainDetailedTaxonomicInformation() {
2171         if ( getCurrentTreePanel() != null ) {
2172             final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
2173             if ( ( phy != null ) && !phy.isEmpty() ) {
2174                 final TaxonomyDataManager t = new TaxonomyDataManager( this,
2175                                                                        _mainpanel.getCurrentTreePanel(),
2176                                                                        phy.copy(),
2177                                                                        false,
2178                                                                        true );
2179                 new Thread( t ).start();
2180             }
2181         }
2182     }
2183
2184     private void obtainDetailedTaxonomicInformationDelete() {
2185         if ( getCurrentTreePanel() != null ) {
2186             final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
2187             if ( ( phy != null ) && !phy.isEmpty() ) {
2188                 final TaxonomyDataManager t = new TaxonomyDataManager( this,
2189                                                                        _mainpanel.getCurrentTreePanel(),
2190                                                                        phy.copy(),
2191                                                                        true,
2192                                                                        true );
2193                 new Thread( t ).start();
2194             }
2195         }
2196     }
2197
2198     private void obtainSequenceInformation() {
2199         if ( getCurrentTreePanel() != null ) {
2200             final Phylogeny phy = getCurrentTreePanel().getPhylogeny();
2201             if ( ( phy != null ) && !phy.isEmpty() ) {
2202                 final SequenceDataRetriver u = new SequenceDataRetriver( this,
2203                                                                          _mainpanel.getCurrentTreePanel(),
2204                                                                          phy.copy() );
2205                 new Thread( u ).start();
2206             }
2207         }
2208     }
2209
2210     private void print() {
2211         if ( ( getCurrentTreePanel() == null ) || ( getCurrentTreePanel().getPhylogeny() == null )
2212                 || getCurrentTreePanel().getPhylogeny().isEmpty() ) {
2213             return;
2214         }
2215         if ( !getOptions().isPrintUsingActualSize() ) {
2216             getCurrentTreePanel().calcParametersForPainting( getOptions().getPrintSizeX() - 80,
2217                                                              getOptions().getPrintSizeY() - 140,
2218                                                              true );
2219             getCurrentTreePanel().resetPreferredSize();
2220             getCurrentTreePanel().repaint();
2221         }
2222         final String job_name = Constants.PRG_NAME;
2223         boolean error = false;
2224         String printer_name = null;
2225         try {
2226             printer_name = Printer.print( getCurrentTreePanel(), job_name );
2227         }
2228         catch ( final Exception e ) {
2229             error = true;
2230             JOptionPane.showMessageDialog( this, e.getMessage(), "Printing Error", JOptionPane.ERROR_MESSAGE );
2231         }
2232         if ( !error && ( printer_name != null ) ) {
2233             String msg = "Printing data sent to printer";
2234             if ( printer_name.length() > 1 ) {
2235                 msg += " [" + printer_name + "]";
2236             }
2237             JOptionPane.showMessageDialog( this, msg, "Printing...", JOptionPane.INFORMATION_MESSAGE );
2238         }
2239         if ( !getOptions().isPrintUsingActualSize() ) {
2240             getControlPanel().showWhole();
2241         }
2242     }
2243
2244     private void printPhylogenyToPdf( final String file_name ) {
2245         if ( !getOptions().isPrintUsingActualSize() ) {
2246             getCurrentTreePanel().calcParametersForPainting( getOptions().getPrintSizeX(),
2247                                                              getOptions().getPrintSizeY(),
2248                                                              true );
2249             getCurrentTreePanel().resetPreferredSize();
2250             getCurrentTreePanel().repaint();
2251         }
2252         String pdf_written_to = "";
2253         boolean error = false;
2254         try {
2255             if ( getOptions().isPrintUsingActualSize() ) {
2256                 pdf_written_to = PdfExporter.writePhylogenyToPdf( file_name,
2257                                                                   getCurrentTreePanel(),
2258                                                                   getCurrentTreePanel().getWidth(),
2259                                                                   getCurrentTreePanel().getHeight() );
2260             }
2261             else {
2262                 pdf_written_to = PdfExporter.writePhylogenyToPdf( file_name, getCurrentTreePanel(), getOptions()
2263                         .getPrintSizeX(), getOptions().getPrintSizeY() );
2264             }
2265         }
2266         catch ( final IOException e ) {
2267             error = true;
2268             JOptionPane.showMessageDialog( this, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE );
2269         }
2270         if ( !error ) {
2271             if ( !ForesterUtil.isEmpty( pdf_written_to ) ) {
2272                 JOptionPane.showMessageDialog( this,
2273                                                "Wrote PDF to: " + pdf_written_to,
2274                                                "Information",
2275                                                JOptionPane.INFORMATION_MESSAGE );
2276             }
2277             else {
2278                 JOptionPane.showMessageDialog( this,
2279                                                "There was an unknown problem when attempting to write to PDF file: \""
2280                                                        + file_name + "\"",
2281                                                "Error",
2282                                                JOptionPane.ERROR_MESSAGE );
2283             }
2284         }
2285         if ( !getOptions().isPrintUsingActualSize() ) {
2286             getControlPanel().showWhole();
2287         }
2288     }
2289
2290     private void readPhylogeniesFromFile() {
2291         boolean exception = false;
2292         Phylogeny[] phys = null;
2293         // Set an initial directory if none set yet
2294         final File my_dir = getCurrentDir();
2295         _open_filechooser.setMultiSelectionEnabled( true );
2296         // Open file-open dialog and set current directory
2297         if ( my_dir != null ) {
2298             _open_filechooser.setCurrentDirectory( my_dir );
2299         }
2300         final int result = _open_filechooser.showOpenDialog( _contentpane );
2301         // All done: get the file
2302         final File[] files = _open_filechooser.getSelectedFiles();
2303         setCurrentDir( _open_filechooser.getCurrentDirectory() );
2304         boolean nhx_or_nexus = false;
2305         if ( ( files != null ) && ( files.length > 0 ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
2306             for( final File file : files ) {
2307                 if ( ( file != null ) && !file.isDirectory() ) {
2308                     if ( _mainpanel.getCurrentTreePanel() != null ) {
2309                         _mainpanel.getCurrentTreePanel().setWaitCursor();
2310                     }
2311                     else {
2312                         _mainpanel.setWaitCursor();
2313                     }
2314                     if ( ( _open_filechooser.getFileFilter() == MainFrameApplication.nhfilter )
2315                             || ( _open_filechooser.getFileFilter() == MainFrameApplication.nhxfilter ) ) {
2316                         try {
2317                             final NHXParser nhx = new NHXParser();
2318                             setSpecialOptionsForNhxParser( nhx );
2319                             phys = PhylogenyMethods.readPhylogenies( nhx, file );
2320                             nhx_or_nexus = true;
2321                         }
2322                         catch ( final Exception e ) {
2323                             exception = true;
2324                             exceptionOccuredDuringOpenFile( e );
2325                         }
2326                     }
2327                     else if ( _open_filechooser.getFileFilter() == MainFrameApplication.xmlfilter ) {
2328                         warnIfNotPhyloXmlValidation( getConfiguration() );
2329                         try {
2330                             final PhyloXmlParser xml_parser = createPhyloXmlParser();
2331                             phys = PhylogenyMethods.readPhylogenies( xml_parser, file );
2332                         }
2333                         catch ( final Exception e ) {
2334                             exception = true;
2335                             exceptionOccuredDuringOpenFile( e );
2336                         }
2337                     }
2338                     else if ( _open_filechooser.getFileFilter() == MainFrameApplication.tolfilter ) {
2339                         try {
2340                             phys = PhylogenyMethods.readPhylogenies( new TolParser(), file );
2341                         }
2342                         catch ( final Exception e ) {
2343                             exception = true;
2344                             exceptionOccuredDuringOpenFile( e );
2345                         }
2346                     }
2347                     else if ( _open_filechooser.getFileFilter() == MainFrameApplication.nexusfilter ) {
2348                         try {
2349                             final NexusPhylogeniesParser nex = new NexusPhylogeniesParser();
2350                             setSpecialOptionsForNexParser( nex );
2351                             phys = PhylogenyMethods.readPhylogenies( nex, file );
2352                             nhx_or_nexus = true;
2353                         }
2354                         catch ( final Exception e ) {
2355                             exception = true;
2356                             exceptionOccuredDuringOpenFile( e );
2357                         }
2358                     }
2359                     // "*.*":
2360                     else {
2361                         try {
2362                             final PhylogenyParser parser = ParserUtils
2363                                     .createParserDependingOnFileType( file, getConfiguration()
2364                                             .isValidatePhyloXmlAgainstSchema() );
2365                             if ( parser instanceof NexusPhylogeniesParser ) {
2366                                 final NexusPhylogeniesParser nex = ( NexusPhylogeniesParser ) parser;
2367                                 setSpecialOptionsForNexParser( nex );
2368                                 nhx_or_nexus = true;
2369                             }
2370                             else if ( parser instanceof NHXParser ) {
2371                                 final NHXParser nhx = ( NHXParser ) parser;
2372                                 setSpecialOptionsForNhxParser( nhx );
2373                                 nhx_or_nexus = true;
2374                             }
2375                             else if ( parser instanceof PhyloXmlParser ) {
2376                                 warnIfNotPhyloXmlValidation( getConfiguration() );
2377                             }
2378                             phys = PhylogenyMethods.readPhylogenies( parser, file );
2379                         }
2380                         catch ( final Exception e ) {
2381                             exception = true;
2382                             exceptionOccuredDuringOpenFile( e );
2383                         }
2384                     }
2385                     if ( _mainpanel.getCurrentTreePanel() != null ) {
2386                         _mainpanel.getCurrentTreePanel().setArrowCursor();
2387                     }
2388                     else {
2389                         _mainpanel.setArrowCursor();
2390                     }
2391                     if ( !exception && ( phys != null ) && ( phys.length > 0 ) ) {
2392                         boolean one_desc = false;
2393                         if ( nhx_or_nexus ) {
2394                             for( final Phylogeny phy : phys ) {
2395                                 if ( getOptions().isInternalNumberAreConfidenceForNhParsing() ) {
2396                                     PhylogenyMethods.transferInternalNodeNamesToConfidence( phy );
2397                                 }
2398                                 if ( PhylogenyMethods.getMinimumDescendentsPerInternalNodes( phy ) == 1 ) {
2399                                     one_desc = true;
2400                                     break;
2401                                 }
2402                             }
2403                         }
2404                         AptxUtil.addPhylogeniesToTabs( phys,
2405                                                        file.getName(),
2406                                                        file.getAbsolutePath(),
2407                                                        getConfiguration(),
2408                                                        getMainPanel() );
2409                         _mainpanel.getControlPanel().showWhole();
2410                         if ( nhx_or_nexus && one_desc ) {
2411                             JOptionPane
2412                                     .showMessageDialog( this,
2413                                                         "One or more trees contain (a) node(s) with one descendant, "
2414                                                                 + ForesterUtil.LINE_SEPARATOR
2415                                                                 + "possibly indicating illegal parentheses within node names.",
2416                                                         "Warning: Possible Error in New Hampshire Formatted Data",
2417                                                         JOptionPane.WARNING_MESSAGE );
2418                         }
2419                     }
2420                 }
2421             }
2422         }
2423         activateSaveAllIfNeeded();
2424         System.gc();
2425     }
2426
2427     private void readSpeciesTreeFromFile() {
2428         Phylogeny t = null;
2429         boolean exception = false;
2430         final File my_dir = getCurrentDir();
2431         _open_filechooser_for_species_tree.setSelectedFile( new File( "" ) );
2432         if ( my_dir != null ) {
2433             _open_filechooser_for_species_tree.setCurrentDirectory( my_dir );
2434         }
2435         final int result = _open_filechooser_for_species_tree.showOpenDialog( _contentpane );
2436         final File file = _open_filechooser_for_species_tree.getSelectedFile();
2437         if ( ( file != null ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
2438             if ( _open_filechooser_for_species_tree.getFileFilter() == MainFrameApplication.xmlfilter ) {
2439                 try {
2440                     final Phylogeny[] trees = PhylogenyMethods.readPhylogenies( new PhyloXmlParser(), file );
2441                     t = trees[ 0 ];
2442                 }
2443                 catch ( final Exception e ) {
2444                     exception = true;
2445                     exceptionOccuredDuringOpenFile( e );
2446                 }
2447             }
2448             else if ( _open_filechooser_for_species_tree.getFileFilter() == MainFrameApplication.tolfilter ) {
2449                 try {
2450                     final Phylogeny[] trees = PhylogenyMethods.readPhylogenies( new TolParser(), file );
2451                     t = trees[ 0 ];
2452                 }
2453                 catch ( final Exception e ) {
2454                     exception = true;
2455                     exceptionOccuredDuringOpenFile( e );
2456                 }
2457             }
2458             // "*.*":
2459             else {
2460                 try {
2461                     final Phylogeny[] trees = PhylogenyMethods.readPhylogenies( new PhyloXmlParser(), file );
2462                     t = trees[ 0 ];
2463                 }
2464                 catch ( final Exception e ) {
2465                     exception = true;
2466                     exceptionOccuredDuringOpenFile( e );
2467                 }
2468             }
2469             if ( !exception && ( t != null ) && !t.isRooted() ) {
2470                 exception = true;
2471                 t = null;
2472                 JOptionPane.showMessageDialog( this,
2473                                                "Species tree is not rooted",
2474                                                "Species tree not loaded",
2475                                                JOptionPane.ERROR_MESSAGE );
2476             }
2477             if ( !exception && ( t != null ) ) {
2478                 final Set<Taxonomy> tax_set = new HashSet<Taxonomy>();
2479                 for( final PhylogenyNodeIterator it = t.iteratorExternalForward(); it.hasNext(); ) {
2480                     final PhylogenyNode node = it.next();
2481                     if ( !node.getNodeData().isHasTaxonomy() ) {
2482                         exception = true;
2483                         t = null;
2484                         JOptionPane
2485                                 .showMessageDialog( this,
2486                                                     "Species tree contains external node(s) without taxonomy information",
2487                                                     "Species tree not loaded",
2488                                                     JOptionPane.ERROR_MESSAGE );
2489                         break;
2490                     }
2491                     else {
2492                         if ( tax_set.contains( node.getNodeData().getTaxonomy() ) ) {
2493                             exception = true;
2494                             t = null;
2495                             JOptionPane.showMessageDialog( this,
2496                                                            "Taxonomy ["
2497                                                                    + node.getNodeData().getTaxonomy().asSimpleText()
2498                                                                    + "] is not unique in species tree",
2499                                                            "Species tree not loaded",
2500                                                            JOptionPane.ERROR_MESSAGE );
2501                             break;
2502                         }
2503                         else {
2504                             tax_set.add( node.getNodeData().getTaxonomy() );
2505                         }
2506                     }
2507                 }
2508             }
2509             if ( !exception && ( t != null ) ) {
2510                 _species_tree = t;
2511                 JOptionPane.showMessageDialog( this,
2512                                                "Species tree successfully loaded",
2513                                                "Species tree loaded",
2514                                                JOptionPane.INFORMATION_MESSAGE );
2515             }
2516             _contentpane.repaint();
2517             System.gc();
2518         }
2519     }
2520
2521     private void setCurrentDir( final File current_dir ) {
2522         _current_dir = current_dir;
2523     }
2524
2525     private void setMinNotCollapseConfidenceValue( final double min_not_collapse ) {
2526         _min_not_collapse = min_not_collapse;
2527     }
2528
2529     private void setPhylogeneticInferenceOptions( final PhylogeneticInferenceOptions phylogenetic_inference_options ) {
2530         _phylogenetic_inference_options = phylogenetic_inference_options;
2531     }
2532
2533     private void setSpecialOptionsForNexParser( final NexusPhylogeniesParser nex ) {
2534         nex.setReplaceUnderscores( getOptions().isReplaceUnderscoresInNhParsing() );
2535         nex.setTaxonomyExtraction( getOptions().getTaxonomyExtraction() );
2536     }
2537
2538     private void setSpecialOptionsForNhxParser( final NHXParser nhx ) {
2539         nhx.setReplaceUnderscores( getOptions().isReplaceUnderscoresInNhParsing() );
2540         nhx.setTaxonomyExtraction( getOptions().getTaxonomyExtraction() );
2541     }
2542
2543     private void writeAllToFile() {
2544         if ( ( getMainPanel().getTabbedPane() == null ) || ( getMainPanel().getTabbedPane().getTabCount() < 1 ) ) {
2545             return;
2546         }
2547         final File my_dir = getCurrentDir();
2548         if ( my_dir != null ) {
2549             _save_filechooser.setCurrentDirectory( my_dir );
2550         }
2551         _save_filechooser.setSelectedFile( new File( "" ) );
2552         final int result = _save_filechooser.showSaveDialog( _contentpane );
2553         final File file = _save_filechooser.getSelectedFile();
2554         setCurrentDir( _save_filechooser.getCurrentDirectory() );
2555         if ( ( file != null ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
2556             if ( file.exists() ) {
2557                 final int i = JOptionPane.showConfirmDialog( this,
2558                                                              file + " already exists. Overwrite?",
2559                                                              "Warning",
2560                                                              JOptionPane.OK_CANCEL_OPTION,
2561                                                              JOptionPane.WARNING_MESSAGE );
2562                 if ( i != JOptionPane.OK_OPTION ) {
2563                     return;
2564                 }
2565                 else {
2566                     try {
2567                         file.delete();
2568                     }
2569                     catch ( final Exception e ) {
2570                         JOptionPane.showMessageDialog( this,
2571                                                        "Failed to delete: " + file,
2572                                                        "Error",
2573                                                        JOptionPane.WARNING_MESSAGE );
2574                     }
2575                 }
2576             }
2577             final int count = getMainPanel().getTabbedPane().getTabCount();
2578             final List<Phylogeny> trees = new ArrayList<Phylogeny>();
2579             for( int i = 0; i < count; ++i ) {
2580                 final Phylogeny phy = getMainPanel().getPhylogeny( i );
2581                 if ( ForesterUtil.isEmpty( phy.getName() )
2582                         && !ForesterUtil.isEmpty( getMainPanel().getTabbedPane().getTitleAt( i ) ) ) {
2583                     phy.setName( getMainPanel().getTabbedPane().getTitleAt( i ) );
2584                 }
2585                 trees.add( phy );
2586                 getMainPanel().getTreePanels().get( i ).setEdited( false );
2587             }
2588             final PhylogenyWriter writer = new PhylogenyWriter();
2589             try {
2590                 writer.toPhyloXML( file, trees, 0, ForesterUtil.LINE_SEPARATOR );
2591             }
2592             catch ( final IOException e ) {
2593                 JOptionPane.showMessageDialog( this,
2594                                                "Failed to write to: " + file,
2595                                                "Error",
2596                                                JOptionPane.WARNING_MESSAGE );
2597             }
2598         }
2599     }
2600
2601     private boolean writeAsNewHampshire( final Phylogeny t, boolean exception, final File file ) {
2602         try {
2603             final PhylogenyWriter writer = new PhylogenyWriter();
2604             writer.toNewHampshire( t, false, true, getOptions().getNhConversionSupportValueStyle(), file );
2605         }
2606         catch ( final Exception e ) {
2607             exception = true;
2608             exceptionOccuredDuringSaveAs( e );
2609         }
2610         return exception;
2611     }
2612
2613     private boolean writeAsNexus( final Phylogeny t, boolean exception, final File file ) {
2614         try {
2615             final PhylogenyWriter writer = new PhylogenyWriter();
2616             writer.toNexus( file, t, getOptions().getNhConversionSupportValueStyle() );
2617         }
2618         catch ( final Exception e ) {
2619             exception = true;
2620             exceptionOccuredDuringSaveAs( e );
2621         }
2622         return exception;
2623     }
2624
2625     private boolean writeAsPhyloXml( final Phylogeny t, boolean exception, final File file ) {
2626         try {
2627             final PhylogenyWriter writer = new PhylogenyWriter();
2628             writer.toPhyloXML( file, t, 0 );
2629         }
2630         catch ( final Exception e ) {
2631             exception = true;
2632             exceptionOccuredDuringSaveAs( e );
2633         }
2634         return exception;
2635     }
2636
2637     private void writeToFile( final Phylogeny t ) {
2638         if ( t == null ) {
2639             return;
2640         }
2641         String initial_filename = null;
2642         if ( getMainPanel().getCurrentTreePanel().getTreeFile() != null ) {
2643             try {
2644                 initial_filename = getMainPanel().getCurrentTreePanel().getTreeFile().getCanonicalPath();
2645             }
2646             catch ( final IOException e ) {
2647                 initial_filename = null;
2648             }
2649         }
2650         if ( !ForesterUtil.isEmpty( initial_filename ) ) {
2651             _save_filechooser.setSelectedFile( new File( initial_filename ) );
2652         }
2653         else {
2654             _save_filechooser.setSelectedFile( new File( "" ) );
2655         }
2656         final File my_dir = getCurrentDir();
2657         if ( my_dir != null ) {
2658             _save_filechooser.setCurrentDirectory( my_dir );
2659         }
2660         final int result = _save_filechooser.showSaveDialog( _contentpane );
2661         final File file = _save_filechooser.getSelectedFile();
2662         setCurrentDir( _save_filechooser.getCurrentDirectory() );
2663         boolean exception = false;
2664         if ( ( file != null ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
2665             if ( file.exists() ) {
2666                 final int i = JOptionPane.showConfirmDialog( this,
2667                                                              file + " already exists.\nOverwrite?",
2668                                                              "Overwrite?",
2669                                                              JOptionPane.OK_CANCEL_OPTION,
2670                                                              JOptionPane.QUESTION_MESSAGE );
2671                 if ( i != JOptionPane.OK_OPTION ) {
2672                     return;
2673                 }
2674                 else {
2675                     final File to = new File( file.getAbsoluteFile().toString() + Constants.BACKUP_FILE_SUFFIX );
2676                     try {
2677                         ForesterUtil.copyFile( file, to );
2678                     }
2679                     catch ( final Exception e ) {
2680                         JOptionPane.showMessageDialog( this,
2681                                                        "Failed to create backup copy " + to,
2682                                                        "Failed to Create Backup Copy",
2683                                                        JOptionPane.WARNING_MESSAGE );
2684                     }
2685                     try {
2686                         file.delete();
2687                     }
2688                     catch ( final Exception e ) {
2689                         JOptionPane.showMessageDialog( this,
2690                                                        "Failed to delete: " + file,
2691                                                        "Failed to Delete",
2692                                                        JOptionPane.WARNING_MESSAGE );
2693                     }
2694                 }
2695             }
2696             if ( _save_filechooser.getFileFilter() == MainFrameApplication.nhfilter ) {
2697                 exception = writeAsNewHampshire( t, exception, file );
2698             }
2699             else if ( _save_filechooser.getFileFilter() == MainFrameApplication.xmlfilter ) {
2700                 exception = writeAsPhyloXml( t, exception, file );
2701             }
2702             else if ( _save_filechooser.getFileFilter() == MainFrameApplication.nexusfilter ) {
2703                 exception = writeAsNexus( t, exception, file );
2704             }
2705             // "*.*":
2706             else {
2707                 final String file_name = file.getName().trim().toLowerCase();
2708                 if ( file_name.endsWith( ".nh" ) || file_name.endsWith( ".newick" ) || file_name.endsWith( ".phy" )
2709                         || file_name.endsWith( ".tree" ) ) {
2710                     exception = writeAsNewHampshire( t, exception, file );
2711                 }
2712                 else if ( file_name.endsWith( ".nex" ) || file_name.endsWith( ".nexus" ) ) {
2713                     exception = writeAsNexus( t, exception, file );
2714                 }
2715                 // XML is default:
2716                 else {
2717                     exception = writeAsPhyloXml( t, exception, file );
2718                 }
2719             }
2720             if ( !exception ) {
2721                 getMainPanel().setTitleOfSelectedTab( file.getName() );
2722                 getMainPanel().getCurrentTreePanel().setTreeFile( file );
2723                 getMainPanel().getCurrentTreePanel().setEdited( false );
2724             }
2725         }
2726     }
2727
2728     private void writeToGraphicsFile( final Phylogeny t, final GraphicsExportType type ) {
2729         if ( ( t == null ) || t.isEmpty() ) {
2730             return;
2731         }
2732         String initial_filename = "";
2733         if ( getMainPanel().getCurrentTreePanel().getTreeFile() != null ) {
2734             initial_filename = getMainPanel().getCurrentTreePanel().getTreeFile().toString();
2735         }
2736         if ( initial_filename.indexOf( '.' ) > 0 ) {
2737             initial_filename = initial_filename.substring( 0, initial_filename.lastIndexOf( '.' ) );
2738         }
2739         initial_filename = initial_filename + "." + type;
2740         _writetographics_filechooser.setSelectedFile( new File( initial_filename ) );
2741         final File my_dir = getCurrentDir();
2742         if ( my_dir != null ) {
2743             _writetographics_filechooser.setCurrentDirectory( my_dir );
2744         }
2745         final int result = _writetographics_filechooser.showSaveDialog( _contentpane );
2746         File file = _writetographics_filechooser.getSelectedFile();
2747         setCurrentDir( _writetographics_filechooser.getCurrentDirectory() );
2748         if ( ( file != null ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
2749             if ( !file.toString().toLowerCase().endsWith( type.toString() ) ) {
2750                 file = new File( file.toString() + "." + type );
2751             }
2752             if ( file.exists() ) {
2753                 final int i = JOptionPane.showConfirmDialog( this,
2754                                                              file + " already exists. Overwrite?",
2755                                                              "Warning",
2756                                                              JOptionPane.OK_CANCEL_OPTION,
2757                                                              JOptionPane.WARNING_MESSAGE );
2758                 if ( i != JOptionPane.OK_OPTION ) {
2759                     return;
2760                 }
2761                 else {
2762                     try {
2763                         file.delete();
2764                     }
2765                     catch ( final Exception e ) {
2766                         JOptionPane.showMessageDialog( this,
2767                                                        "Failed to delete: " + file,
2768                                                        "Error",
2769                                                        JOptionPane.WARNING_MESSAGE );
2770                     }
2771                 }
2772             }
2773             writePhylogenyToGraphicsFile( file.toString(), type );
2774         }
2775     }
2776
2777     private void writeToPdf( final Phylogeny t ) {
2778         if ( ( t == null ) || t.isEmpty() ) {
2779             return;
2780         }
2781         String initial_filename = "";
2782         if ( getMainPanel().getCurrentTreePanel().getTreeFile() != null ) {
2783             initial_filename = getMainPanel().getCurrentTreePanel().getTreeFile().toString();
2784         }
2785         if ( initial_filename.indexOf( '.' ) > 0 ) {
2786             initial_filename = initial_filename.substring( 0, initial_filename.lastIndexOf( '.' ) );
2787         }
2788         initial_filename = initial_filename + ".pdf";
2789         _writetopdf_filechooser.setSelectedFile( new File( initial_filename ) );
2790         final File my_dir = getCurrentDir();
2791         if ( my_dir != null ) {
2792             _writetopdf_filechooser.setCurrentDirectory( my_dir );
2793         }
2794         final int result = _writetopdf_filechooser.showSaveDialog( _contentpane );
2795         File file = _writetopdf_filechooser.getSelectedFile();
2796         setCurrentDir( _writetopdf_filechooser.getCurrentDirectory() );
2797         if ( ( file != null ) && ( result == JFileChooser.APPROVE_OPTION ) ) {
2798             if ( !file.toString().toLowerCase().endsWith( ".pdf" ) ) {
2799                 file = new File( file.toString() + ".pdf" );
2800             }
2801             if ( file.exists() ) {
2802                 final int i = JOptionPane.showConfirmDialog( this,
2803                                                              file + " already exists. Overwrite?",
2804                                                              "WARNING",
2805                                                              JOptionPane.OK_CANCEL_OPTION,
2806                                                              JOptionPane.WARNING_MESSAGE );
2807                 if ( i != JOptionPane.OK_OPTION ) {
2808                     return;
2809                 }
2810             }
2811             printPhylogenyToPdf( file.toString() );
2812         }
2813     }
2814
2815     public static MainFrameApplication createInstance( final Phylogeny[] phys, final Configuration config ) {
2816         return new MainFrameApplication( phys, config );
2817     }
2818
2819     public static MainFrame createInstance( final Phylogeny[] phys,
2820                                             final Configuration config,
2821                                             final String title,
2822                                             final File current_dir ) {
2823         return new MainFrameApplication( phys, config, title, current_dir );
2824     }
2825
2826     static MainFrame createInstance( final Phylogeny[] phys, final Configuration config, final String title ) {
2827         return new MainFrameApplication( phys, config, title );
2828     }
2829
2830     static MainFrame createInstance( final Phylogeny[] phys, final String config_file_name, final String title ) {
2831         return new MainFrameApplication( phys, config_file_name, title );
2832     }
2833
2834     static void setTextForGraphicsSizeChooserMenuItem( final JMenuItem mi, final Options o ) {
2835         mi.setText( "Enter Default Size for Graphics Export... (current: " + o.getPrintSizeX() + ", "
2836                 + o.getPrintSizeY() + ")" );
2837     }
2838
2839     static void setTextForPdfLineWidthChooserMenuItem( final JMenuItem mi, final Options o ) {
2840         mi.setText( "Enter Default Line Width for PDF Export... (current: " + o.getPrintLineWidth() + ")" );
2841     }
2842
2843     static void warnIfNotPhyloXmlValidation( final Configuration c ) {
2844         if ( !c.isValidatePhyloXmlAgainstSchema() ) {
2845             JOptionPane
2846                     .showMessageDialog( null,
2847                                         ForesterUtil
2848                                                 .wordWrap( "phyloXML XSD-based validation is turned off [enable with line 'validate_against_phyloxml_xsd_schem: true' in configuration file]",
2849                                                            80 ),
2850                                         "Warning",
2851                                         JOptionPane.WARNING_MESSAGE );
2852         }
2853     }
2854 } // MainFrameApplication.
2855
2856 class DefaultFilter extends FileFilter {
2857
2858     @Override
2859     public boolean accept( final File f ) {
2860         final String file_name = f.getName().trim().toLowerCase();
2861         return file_name.endsWith( ".nh" ) || file_name.endsWith( ".newick" ) || file_name.endsWith( ".phy" )
2862                 || file_name.endsWith( ".nwk" ) || file_name.endsWith( ".phb" ) || file_name.endsWith( ".ph" )
2863                 || file_name.endsWith( ".tr" ) || file_name.endsWith( ".dnd" ) || file_name.endsWith( ".tree" )
2864                 || file_name.endsWith( ".nhx" ) || file_name.endsWith( ".xml" ) || file_name.endsWith( ".phyloxml" )
2865                 || file_name.endsWith( "phylo.xml" ) || file_name.endsWith( ".pxml" ) || file_name.endsWith( ".nexus" )
2866                 || file_name.endsWith( ".nx" ) || file_name.endsWith( ".nex" ) || file_name.endsWith( ".tre" )
2867                 || file_name.endsWith( ".zip" ) || file_name.endsWith( ".tol" ) || file_name.endsWith( ".tolxml" )
2868                 || file_name.endsWith( ".con" ) || f.isDirectory();
2869     }
2870
2871     @Override
2872     public String getDescription() {
2873         return "All supported files (*.xml, *.phyloxml, *phylo.xml, *.nhx, *.nh, *.newick, *.nex, *.nexus, *.phy, *.tre, *.tree, *.tol, ...)";
2874     }
2875 }
2876
2877 class GraphicsFileFilter extends FileFilter {
2878
2879     @Override
2880     public boolean accept( final File f ) {
2881         final String file_name = f.getName().trim().toLowerCase();
2882         return file_name.endsWith( ".jpg" ) || file_name.endsWith( ".jpeg" ) || file_name.endsWith( ".png" )
2883                 || file_name.endsWith( ".gif" ) || file_name.endsWith( ".bmp" ) || f.isDirectory();
2884     }
2885
2886     @Override
2887     public String getDescription() {
2888         return "Image files (*.jpg, *.jpeg, *.png, *.gif, *.bmp)";
2889     }
2890 }
2891
2892 class MsaFileFilter extends FileFilter {
2893
2894     @Override
2895     public boolean accept( final File f ) {
2896         final String file_name = f.getName().trim().toLowerCase();
2897         return file_name.endsWith( ".msa" ) || file_name.endsWith( ".aln" ) || file_name.endsWith( ".fasta" )
2898                 || file_name.endsWith( ".fas" ) || file_name.endsWith( ".fa" ) || f.isDirectory();
2899     }
2900
2901     @Override
2902     public String getDescription() {
2903         return "Multiple sequence alignment files (*.msa, *.aln, *.fasta, *.fa, *.fas)";
2904     }
2905 }
2906
2907 class NexusFilter extends FileFilter {
2908
2909     @Override
2910     public boolean accept( final File f ) {
2911         final String file_name = f.getName().trim().toLowerCase();
2912         return file_name.endsWith( ".nex" ) || file_name.endsWith( ".nexus" ) || file_name.endsWith( ".nx" )
2913                 || file_name.endsWith( ".tre" ) || f.isDirectory();
2914     }
2915
2916     @Override
2917     public String getDescription() {
2918         return "Nexus files (*.nex, *.nexus, *.nx, *.tre)";
2919     }
2920 } // NexusFilter
2921
2922 class NHFilter extends FileFilter {
2923
2924     @Override
2925     public boolean accept( final File f ) {
2926         final String file_name = f.getName().trim().toLowerCase();
2927         return file_name.endsWith( ".nh" ) || file_name.endsWith( ".newick" ) || file_name.endsWith( ".phy" )
2928                 || file_name.endsWith( ".tr" ) || file_name.endsWith( ".tree" ) || file_name.endsWith( ".dnd" )
2929                 || file_name.endsWith( ".ph" ) || file_name.endsWith( ".phb" ) || file_name.endsWith( ".nwk" )
2930                 || f.isDirectory();
2931     }
2932
2933     @Override
2934     public String getDescription() {
2935         return "New Hampshire - Newick files (*.nh, *.newick, *.phy, *.tree, *.dnd, *.tr, *.ph, *.phb, *.nwk)";
2936     }
2937 } // NHFilter
2938
2939 class NHXFilter extends FileFilter {
2940
2941     @Override
2942     public boolean accept( final File f ) {
2943         final String file_name = f.getName().trim().toLowerCase();
2944         return file_name.endsWith( ".nhx" ) || f.isDirectory();
2945     }
2946
2947     @Override
2948     public String getDescription() {
2949         return "NHX files (*.nhx) [deprecated]";
2950     }
2951 }
2952
2953 class PdfFilter extends FileFilter {
2954
2955     @Override
2956     public boolean accept( final File f ) {
2957         return f.getName().trim().toLowerCase().endsWith( ".pdf" ) || f.isDirectory();
2958     }
2959
2960     @Override
2961     public String getDescription() {
2962         return "PDF files (*.pdf)";
2963     }
2964 } // PdfFilter
2965
2966 class SequencesFileFilter extends FileFilter {
2967
2968     @Override
2969     public boolean accept( final File f ) {
2970         final String file_name = f.getName().trim().toLowerCase();
2971         return file_name.endsWith( ".fasta" ) || file_name.endsWith( ".fa" ) || file_name.endsWith( ".fas" )
2972                 || file_name.endsWith( ".seqs" ) || f.isDirectory();
2973     }
2974
2975     @Override
2976     public String getDescription() {
2977         return "Sequences files (*.fasta, *.fa, *.fas, *.seqs )";
2978     }
2979 }
2980
2981 class TolFilter extends FileFilter {
2982
2983     @Override
2984     public boolean accept( final File f ) {
2985         final String file_name = f.getName().trim().toLowerCase();
2986         return ( file_name.endsWith( ".tol" ) || file_name.endsWith( ".tolxml" ) || file_name.endsWith( ".zip" ) || f
2987                 .isDirectory() ) && ( !file_name.endsWith( ".xml.zip" ) );
2988     }
2989
2990     @Override
2991     public String getDescription() {
2992         return "Tree of Life files (*.tol, *.tolxml)";
2993     }
2994 } // TolFilter
2995
2996 class XMLFilter extends FileFilter {
2997
2998     @Override
2999     public boolean accept( final File f ) {
3000         final String file_name = f.getName().trim().toLowerCase();
3001         return file_name.endsWith( ".xml" ) || file_name.endsWith( ".phyloxml" ) || file_name.endsWith( "phylo.xml" )
3002                 || file_name.endsWith( ".pxml" ) || file_name.endsWith( ".zip" ) || f.isDirectory();
3003     }
3004
3005     @Override
3006     public String getDescription() {
3007         return "phyloXML files (*.xml, *.phyloxml, *phylo.xml, *.pxml, *.zip)";
3008     }
3009 } // XMLFilter