JAL-2795 calculated trees are now passed along as Newick strings
[jalview.git] / src / jalview / ext / archaeopteryx / AptxInit.java
1 package jalview.ext.archaeopteryx;
2
3 import jalview.ext.forester.io.UtilityMethods;
4 import jalview.ext.treeviewer.LoadedTreeAssociationI;
5 import jalview.ext.treeviewer.LoadedTreeSequenceAssociation;
6 import jalview.ext.treeviewer.TreeFrameI;
7 import jalview.ext.treeviewer.TreeI;
8 import jalview.ext.treeviewer.TreeViewerUtils;
9 import jalview.gui.Desktop;
10 import jalview.gui.JvOptionPane;
11 import jalview.io.NewickFile;
12 import jalview.util.MessageManager;
13 import jalview.viewmodel.AlignmentViewport;
14
15 import java.io.File;
16 import java.io.FileNotFoundException;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.net.MalformedURLException;
20 import java.net.URL;
21
22 import org.forester.archaeopteryx.AptxUtil;
23 import org.forester.archaeopteryx.Configuration;
24 import org.forester.archaeopteryx.webservices.PhylogeniesWebserviceClient;
25 import org.forester.archaeopteryx.webservices.WebserviceUtil;
26 import org.forester.io.parsers.PhylogenyParser;
27 import org.forester.io.parsers.nexus.NexusPhylogeniesParser;
28 import org.forester.io.parsers.nhx.NHXParser;
29 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
30 import org.forester.io.parsers.phyloxml.PhyloXmlParser;
31 import org.forester.io.parsers.tol.TolParser;
32 import org.forester.io.parsers.util.ParserUtils;
33 import org.forester.phylogeny.Phylogeny;
34 import org.forester.phylogeny.PhylogenyMethods;
35 import org.forester.phylogeny.data.Identifier;
36 import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
37 import org.forester.phylogeny.factories.PhylogenyFactory;
38 import org.forester.util.ForesterUtil;
39
40 /**
41  * Static class for creating Archaeopteryx tree viewer instances from calculated
42  * trees and letting them be bound to Jalview.
43  * 
44  * @author kjvanderheide
45  *
46  */
47 public final class AptxInit
48 {
49   public final static InputStream CONFIG_LOC = AptxInit.class
50
51           .getResourceAsStream("/_aptx_jalview_configuration_file.txt");
52
53   public final static Configuration APTX_CONFIG = new Configuration(
54           CONFIG_LOC,
55           false, false);
56   // static
57   // {
58   // APTX_CONFIG.setBaseFontFamilyName(
59   // Desktop.instance.getFont().getFamily().replaceAll(" ", "_"));
60   // APTX_CONFIG.setBaseFontSize(Desktop.instance.getFont().getSize());
61   // }
62
63   private final static boolean VALIDATE_PHYLOXML_XSD = APTX_CONFIG
64           .isValidatePhyloXmlAgainstSchema();
65
66   private final static boolean REPLACE_NHX_UNDERSCORES = APTX_CONFIG
67           .isReplaceUnderscoresInNhParsing();
68
69   private final static boolean INTERNAL_NUMBERS_AS_CONFIDENCE = APTX_CONFIG
70           .isInternalNumberAreConfidenceForNhParsing();
71
72   private final static boolean MIDPOINT_REROOT = APTX_CONFIG
73           .isMidpointReroot();
74
75   private final static NHXParser.TAXONOMY_EXTRACTION TAXONOMY_EXTRACTION = APTX_CONFIG
76           .getTaxonomyExtraction();
77
78   // public static TreeFrameI createInstanceFromCalculation(
79   // final TreeBuilder calculatedTree)
80   // {
81   // TreeBuilderI aptxTreeBuilder = new AptxTreeBuilder(
82   // calculatedTree);
83   //
84   // TreeI aptxTree = aptxTreeBuilder.buildTree();
85   //
86   // TreeFrameI aptxApp = createAptxFrame(aptxTree,
87   // calculatedTree.getAvport(), null);
88   //
89   // return aptxApp;
90   // }
91
92   public static TreeFrameI[] createInstances(String treeTitle,
93           Object source, PhylogenyParser parser, AlignmentViewport viewport)
94           throws IOException
95   {
96     TreeFrameI[] aptxFrames = null;
97     PhylogenyFactory parserFact = ParserBasedPhylogenyFactory.getInstance();
98     Phylogeny[] trees = parserFact.create(source, parser);
99     aptxFrames = new TreeFrameI[trees.length];
100
101     for (int i = 0; i < trees.length; i++)
102     {
103       Phylogeny aptxPhylogeny = trees[i];
104
105       // if (nhx_or_nexus && INTERNAL_NUMBERS_AS_CONFIDENCE)
106       // {
107       // PhylogenyMethods
108       // .transferInternalNodeNamesToConfidence(aptxPhylogeny, "");
109       // }
110       aptxPhylogeny.setName(treeTitle);
111       aptxFrames[i] = createAptxFrame(aptxPhylogeny, viewport, treeTitle);
112
113     }
114     if (Desktop.instance != null)
115     {
116       Desktop.instance.stopLoading();
117     }
118
119     return aptxFrames;
120
121   }
122
123   /**
124    * Refactored from Archaeopteryx.main
125    * 
126    * @param filePath
127    * @param viewport
128    * @return
129    * @throws IOException
130    * @throws FileNotFoundException
131    */
132   public static TreeFrameI[] createInstancesFromFile(File treeFile,
133           AlignmentViewport viewport)
134           throws FileNotFoundException, IOException
135   {
136     TreeFrameI[] aptxFrames = null;
137     if (UtilityMethods.canForesterReadFile(treeFile))
138     {
139
140       if (Desktop.instance != null)
141       {
142         Desktop.instance.startLoading(treeFile.getCanonicalPath());
143       }
144       boolean nhx_or_nexus = false;
145       final PhylogenyParser parser = ParserUtils
146               .createParserDependingOnFileType(treeFile,
147                       VALIDATE_PHYLOXML_XSD);
148       if (parser instanceof NHXParser)
149       {
150         nhx_or_nexus = true;
151         final NHXParser nhx = (NHXParser) parser;
152         nhx.setReplaceUnderscores(REPLACE_NHX_UNDERSCORES);
153         nhx.setIgnoreQuotes(false);
154         nhx.setTaxonomyExtraction(TAXONOMY_EXTRACTION);
155       }
156       else if (parser instanceof NexusPhylogeniesParser)
157       {
158         nhx_or_nexus = true;
159         final NexusPhylogeniesParser nex = (NexusPhylogeniesParser) parser;
160         nex.setReplaceUnderscores(REPLACE_NHX_UNDERSCORES);
161         nex.setIgnoreQuotes(false);
162       }
163       else if (parser instanceof PhyloXmlParser)
164       {
165         if (VALIDATE_PHYLOXML_XSD == false)
166         {
167           JvOptionPane.showInternalMessageDialog(Desktop.desktop,
168                   MessageManager.getString("error.phyloxml_validation"),
169                   MessageManager.getString("label.file_open_error"),
170                   JvOptionPane.WARNING_MESSAGE);
171         }
172       }
173       Phylogeny[] trees = PhylogenyMethods.readPhylogenies(parser,
174               treeFile);
175       aptxFrames = new TreeFrameI[trees.length];
176
177       for (int i = 0; i < trees.length; i++)
178       {
179         Phylogeny aptxPhylogeny = trees[i];
180
181         if (nhx_or_nexus && INTERNAL_NUMBERS_AS_CONFIDENCE)
182         {
183           PhylogenyMethods
184                   .transferInternalNodeNamesToConfidence(aptxPhylogeny, "");
185         }
186         String treeTitle = treeFile.getName() + "[" + i + "]";
187         aptxPhylogeny.setName(treeTitle);
188         aptxFrames[i] = createAptxFrame(aptxPhylogeny, viewport, treeTitle);
189
190       }
191       if (Desktop.instance != null)
192       {
193         Desktop.instance.stopLoading();
194       }
195     }
196     return aptxFrames;
197   }
198
199
200   public static TreeFrameI[] createInstancesFromFile(
201           String filePath,
202           AlignmentViewport viewport)
203           throws FileNotFoundException, IOException
204   {
205     File treeFile = new File(filePath);
206     return createInstancesFromFile(treeFile, viewport);
207
208     }
209
210   public static TreeFrameI[] createInstancesFromFile(NewickFile newickFile,
211           AlignmentViewport viewport)
212   {
213     return null;
214   }
215
216
217   public static TreeFrameI[] createInstancesFromUrl(URL treeUrl,
218           AlignmentViewport viewport)
219           throws FileNotFoundException, IOException, RuntimeException
220   {
221     
222     String treeTitle = treeUrl.getFile();
223     if (Desktop.instance != null)
224     {
225       Desktop.instance.startLoading(treeTitle);
226     }
227     Phylogeny[] trees = AptxUtil.readPhylogeniesFromUrl(treeUrl,
228             VALIDATE_PHYLOXML_XSD,
229              REPLACE_NHX_UNDERSCORES, INTERNAL_NUMBERS_AS_CONFIDENCE,
230             TAXONOMY_EXTRACTION, MIDPOINT_REROOT);
231
232     TreeFrameI[] aptxFrames = new TreeFrameI[trees.length];
233     for (int i = 0; i < trees.length; i++)
234     {
235       Phylogeny aptxTree = trees[i];
236       aptxFrames[i] = createAptxFrame(aptxTree, viewport, treeTitle);
237     }
238
239     if (Desktop.instance != null)
240     {
241       Desktop.instance.stopLoading();
242     }
243
244     return aptxFrames;
245
246   }
247
248   /**
249    * Refactored from Forester's UrlTreeReader, this can be more efficient
250    * 
251    * @param databaseIndex
252    * @param viewport
253    * @return
254    */
255   public static TreeFrameI[] createInstancesFromDb(
256           PhylogeniesWebserviceClient treeDbClient, String identifier,
257           AlignmentViewport viewport)
258   {
259
260     URL url = null;
261     Phylogeny[] trees = null;
262     TreeFrameI[] aptxFrames = null;
263
264     if ((identifier != null) && (identifier.trim().length() > 0))
265     {
266       if (Desktop.instance != null)
267       {
268         Desktop.instance.startLoading(identifier);
269       }
270
271       identifier = identifier.trim();
272       if (treeDbClient.isQueryInteger())
273       {
274         identifier = identifier.replaceAll("^\\D+", "");
275
276         int id;
277         try
278         {
279           id = Integer.parseInt(identifier);
280         } catch (final NumberFormatException e)
281         {
282           JvOptionPane.showInternalMessageDialog(Desktop.desktop,
283                   MessageManager.formatMessage(
284                           "error.database_id_has_letters", new String[]
285                           { identifier }),
286                   MessageManager.getString("label.invalid_url"),
287                   JvOptionPane.ERROR_MESSAGE);
288           return new TreeFrameI[0];
289         }
290         identifier = id + "";
291       }
292       boolean exception = false;
293       try
294       {
295         String url_str = treeDbClient.getUrl();
296         url_str = url_str.replaceFirst(
297                 PhylogeniesWebserviceClient.QUERY_PLACEHOLDER, identifier);
298         url = new URL(url_str);
299         PhylogenyParser parser = null;
300         switch (treeDbClient.getReturnFormat())
301         {
302         case TOL_XML_RESPONSE:
303           parser = new TolParser();
304           break;
305         case NEXUS:
306           parser = new NexusPhylogeniesParser();
307           ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true);
308           break;
309         case TREEBASE_TREE:
310           parser = new NexusPhylogeniesParser();
311           ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true);
312           ((NexusPhylogeniesParser) parser)
313                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
314           break;
315         case TREEBASE_STUDY:
316           parser = new NexusPhylogeniesParser();
317           ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true);
318           ((NexusPhylogeniesParser) parser)
319                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
320           break;
321         case NH:
322           parser = new NHXParser();
323           ((NHXParser) parser)
324                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
325           ((NHXParser) parser).setReplaceUnderscores(true);
326           ((NHXParser) parser).setGuessRootedness(true);
327           break;
328         case NH_EXTRACT_TAXONOMY:
329           parser = new NHXParser();
330           ((NHXParser) parser).setTaxonomyExtraction(
331                   NHXParser.TAXONOMY_EXTRACTION.AGGRESSIVE);
332           ((NHXParser) parser).setReplaceUnderscores(false);
333           ((NHXParser) parser).setGuessRootedness(true);
334           break;
335         case PFAM:
336           parser = new NHXParser();
337           ((NHXParser) parser).setTaxonomyExtraction(
338                   NHXParser.TAXONOMY_EXTRACTION.PFAM_STYLE_STRICT);
339           ((NHXParser) parser).setReplaceUnderscores(false);
340           ((NHXParser) parser).setGuessRootedness(true);
341           break;
342         case NHX:
343           parser = new NHXParser();
344           ((NHXParser) parser)
345                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
346           ((NHXParser) parser).setReplaceUnderscores(false);
347           ((NHXParser) parser).setGuessRootedness(true);
348           break;
349         case PHYLOXML:
350           parser = PhyloXmlParser.createPhyloXmlParserXsdValidating();
351           break;
352         default:
353           throw new IllegalArgumentException(
354                   "unknown format: " + treeDbClient.getReturnFormat());
355         }
356         //
357         // if (_main_frame.getMainPanel().getCurrentTreePanel() != null)
358         // {
359         // _main_frame.getMainPanel().getCurrentTreePanel().setWaitCursor();
360         // }
361         // else
362         // {
363         // _main_frame.getMainPanel().setWaitCursor();
364         // }
365         trees = ForesterUtil.readPhylogeniesFromUrl(url, parser);
366         aptxFrames = new TreeFrameI[trees.length];
367       } catch (final MalformedURLException e)
368       {
369         exception = true;
370         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
371                 MessageManager.formatMessage(
372                         "exception.unable_to_launch_url", new String[]
373                         { url.toString() }),
374                 MessageManager.getString("label.invalid_url"),
375                 JvOptionPane.ERROR_MESSAGE);
376         System.err.println(e.getLocalizedMessage());
377       } catch (final IOException e)
378       {
379         exception = true;
380         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
381                 "Could not read from " + url + "\n"
382                         + e.getLocalizedMessage(),
383                 "Failed to read tree from " + treeDbClient.getName() + " for "
384                         + identifier,
385                 JvOptionPane.ERROR_MESSAGE);
386         System.err.println(e.getLocalizedMessage());
387       } catch (final NumberFormatException e)
388       {
389         exception = true;
390         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
391                 "Could not read from " + url + "\n"
392                         + e.getLocalizedMessage(),
393                 "Failed to read tree from " + treeDbClient.getName() + " for "
394                         + identifier,
395                 JvOptionPane.ERROR_MESSAGE);
396         System.err.println(e.getLocalizedMessage());
397       } catch (final Exception e)
398       {
399         exception = true;
400         e.printStackTrace();
401         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
402                 e.getLocalizedMessage(), "Unexpected Exception",
403                 JvOptionPane.ERROR_MESSAGE);
404         System.err.println(e.getLocalizedMessage());
405       }
406       if ((trees != null) && (trees.length > 0))
407       {
408         int i = 0;
409         for (final Phylogeny aptxTree : trees)
410         {
411           if (!aptxTree.isEmpty())
412           {
413             if (treeDbClient.getName().equals(WebserviceUtil.TREE_FAM_NAME))
414             {
415               aptxTree.setRerootable(false);
416               aptxTree.setRooted(true);
417             }
418             if (treeDbClient.getProcessingInstructions() != null)
419             {
420               try
421               {
422                 WebserviceUtil.processInstructions(treeDbClient,
423                         aptxTree);
424               } catch (final PhyloXmlDataFormatException e)
425               {
426                 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
427                         "Error:\n" + e.getLocalizedMessage(), "Error",
428                         JvOptionPane.ERROR_MESSAGE);
429               }
430             }
431             if (treeDbClient.getNodeField() != null)
432             {
433               try
434               {
435                 PhylogenyMethods.transferNodeNameToField(aptxTree,
436                         treeDbClient.getNodeField(), false);
437               } catch (final PhyloXmlDataFormatException e)
438               {
439                 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
440                         "Error:\n" + e.getLocalizedMessage(), "Error",
441                         JvOptionPane.ERROR_MESSAGE);
442               }
443             }
444             aptxTree.setIdentifier(
445                     new Identifier(identifier, treeDbClient.getName()));
446             // _main_frame.getJMenuBar().remove(_main_frame.getHelpMenu());
447             // _main_frame.getMenuBarOfExternalTreeFrameI()
448             // .add(_main_frame.getHelpMenu());
449             // _main_frame.getMainPanel().addExternalTreeIInNewTab(ExternalTreeI,
450             // _main_frame.getConfiguration(),
451             // new File(url.getFile()).getName(), url.toString());
452
453
454             TreeFrameI aptxApp = createAptxFrame(aptxTree,
455                     viewport,
456                     url.getFile());
457             String my_name_for_file = "";
458             if (!ForesterUtil.isEmpty(aptxTree.getName()))
459             {
460               my_name_for_file = new String(aptxTree.getName())
461                       .replaceAll(" ", "_");
462             }
463             else if (aptxTree.getIdentifier() != null)
464             {
465               final StringBuffer sb = new StringBuffer();
466               if (!ForesterUtil
467                       .isEmpty(aptxTree.getIdentifier().getProvider()))
468               {
469                 sb.append(aptxTree.getIdentifier().getProvider());
470                 sb.append("_");
471               }
472               sb.append(aptxTree.getIdentifier().getValue());
473               my_name_for_file = new String(
474                       sb.toString().replaceAll(" ", "_"));
475             }
476             aptxApp.getTreePanel()
477                     .setTreeFile(new File(my_name_for_file));
478             // AptxUtil.lookAtSomeTreePropertiesForAptxControlSettings(
479             // aptxTree, aptxApp.getMainPanel().getControlPanel(),
480             // APTX_CONFIG);
481             aptxApp.getTreeControls().displayEntireTree();
482
483             aptxApp.checkMultipleTrees();
484             aptxFrames[i++] = aptxApp;
485           }
486         }
487       }
488       else if (!exception) // ..what?
489       {
490         JvOptionPane.showMessageDialog(null,
491                 ForesterUtil.wordWrap(
492                         "Failed to read in tree(s) from [" + url + "]", 80),
493                 "Error", JvOptionPane.ERROR_MESSAGE);
494       }
495       if ((trees != null) && (trees.length > 0))
496       {
497         try
498         {
499           JvOptionPane.showMessageDialog(null,
500                   ForesterUtil.wordWrap("Successfully read in "
501                           + trees.length + " tree(s) from [" + url + "]",
502                           80),
503                   "Success", JvOptionPane.INFORMATION_MESSAGE);
504         } catch (final Exception e)
505         {
506           // Not important if this fails, do nothing.
507         }
508         // _main_frame.getContentPane().repaint();
509       }
510     }
511
512     System.gc();
513
514
515     if (Desktop.instance != null)
516     {
517       Desktop.instance.stopLoading();
518     }
519     return aptxFrames;
520
521
522   }
523
524
525
526   public static TreeFrameI createAptxFrame(TreeI aptxTree,
527           AlignmentViewport jalviewAlignport, String treeTitle)
528   {
529     validateConfig(APTX_CONFIG);
530     TreeFrameI aptxApp = aptxTree
531             .createTreeViewerFromTree(treeTitle);
532     TreeI jalviewTree = aptxApp.getTree();
533     LoadedTreeAssociationI bindAptxNodes = new LoadedTreeSequenceAssociation(
534             jalviewAlignport.getAlignment().getSequencesArray(),
535             jalviewTree);
536     bindAptxNodes.associateLeavesToSequences();
537
538     TreeViewerUtils.associateNodesWithJalviewSequences(aptxApp, jalviewAlignport,
539             bindAptxNodes.getAlignmentWithNodes(),
540             bindAptxNodes.getNodesWithAlignment());
541     TreeViewerUtils.addTreeViewFrameToJalview(aptxApp);
542
543     // adaptAptxGui(aptxApp); //moved to AptxFrame
544     return aptxApp;
545   }
546
547
548   protected static TreeFrameI createAptxFrame(
549           final Phylogeny aptxTree,
550           final AlignmentViewport jalviewAlignport, String treeTitle)
551   {
552     validateConfig(APTX_CONFIG);
553     TreeFrameI aptxApp = new AptxFrame(aptxTree, APTX_CONFIG,
554             treeTitle);
555     TreeI jalviewTree = aptxApp.getTree();
556     LoadedTreeAssociationI bindAptxNodes = new LoadedTreeSequenceAssociation(
557             jalviewAlignport.getAlignment().getSequencesArray(),
558             jalviewTree);
559     bindAptxNodes.associateLeavesToSequences();
560
561     TreeViewerUtils.associateNodesWithJalviewSequences(aptxApp, jalviewAlignport,
562             bindAptxNodes.getAlignmentWithNodes(),
563             bindAptxNodes.getNodesWithAlignment());
564     TreeViewerUtils.addTreeViewFrameToJalview(aptxApp);
565
566     // adaptAptxGui(aptxApp); //moved to AptxFrame
567     return aptxApp;
568   }
569
570
571   private static boolean validateConfig(Configuration aptxConfig)
572   {
573     if (aptxConfig == null || aptxConfig.isCouldReadConfigFile() == false)
574     {
575       int keepGoing = JvOptionPane.showConfirmDialog(Desktop.desktop,
576               MessageManager.getString("label.aptx_config_not_found"),
577               MessageManager.formatMessage("label.couldnt_locate",
578                       new String[]
579                       { "_aptx_jalview_configuration_file" }),
580               JvOptionPane.YES_NO_CANCEL_OPTION);
581
582       if (keepGoing == JvOptionPane.CANCEL_OPTION
583               || keepGoing == JvOptionPane.CLOSED_OPTION
584               || keepGoing == JvOptionPane.NO_OPTION)
585       {
586         return false;
587       }
588
589     }
590     return true;
591   }
592
593
594 }