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