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