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