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