JAL-1953 redundant tree interface instantiation removed
[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.forester.UtilityMethods;
6 import jalview.ext.treeviewer.ExternalLoadedTreeAssociationI;
7 import jalview.ext.treeviewer.ExternalTreeBuilderI;
8 import jalview.ext.treeviewer.ExternalTreeFrame;
9 import jalview.ext.treeviewer.ExternalTreeI;
10 import jalview.ext.treeviewer.ExternalTreeNodeI;
11 import jalview.ext.treeviewer.ExternalTreeViewerBindingI;
12 import jalview.ext.treeviewer.LoadedTreeSequenceAssociation;
13 import jalview.gui.Desktop;
14 import jalview.gui.JvOptionPane;
15 import jalview.util.MessageManager;
16 import jalview.viewmodel.AlignmentViewport;
17
18 import java.awt.Dimension;
19 import java.io.File;
20 import java.io.FileNotFoundException;
21 import java.io.IOException;
22 import java.net.MalformedURLException;
23 import java.net.URL;
24 import java.util.HashMap;
25 import java.util.Map;
26
27 import org.forester.archaeopteryx.AptxUtil;
28 import org.forester.archaeopteryx.Configuration;
29 import org.forester.archaeopteryx.webservices.PhylogeniesWebserviceClient;
30 import org.forester.archaeopteryx.webservices.WebserviceUtil;
31 import org.forester.io.parsers.PhylogenyParser;
32 import org.forester.io.parsers.nexus.NexusPhylogeniesParser;
33 import org.forester.io.parsers.nhx.NHXParser;
34 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
35 import org.forester.io.parsers.phyloxml.PhyloXmlParser;
36 import org.forester.io.parsers.tol.TolParser;
37 import org.forester.io.parsers.util.ParserUtils;
38 import org.forester.phylogeny.Phylogeny;
39 import org.forester.phylogeny.PhylogenyMethods;
40 import org.forester.phylogeny.data.Identifier;
41 import org.forester.util.ForesterUtil;
42
43 /**
44  * Static class for creating Archaeopteryx tree viewer instances from calculated
45  * trees and letting them be bound to Jalview.
46  * 
47  * @author kjvanderheide
48  *
49  */
50 public final class AptxInit
51 {
52   public final static Configuration APTX_CONFIG = new Configuration(
53           "_aptx_jalview_configuration_file",
54             false, false, false);
55
56   private final static boolean VALIDATE_PHYLOXML_XSD = APTX_CONFIG
57           .isValidatePhyloXmlAgainstSchema();
58
59   private final static boolean REPLACE_NHX_UNDERSCORES = APTX_CONFIG
60           .isReplaceUnderscoresInNhParsing();
61
62   private final static boolean INTERNAL_NUMBERS_AS_CONFIDENCE = APTX_CONFIG
63           .isInternalNumberAreConfidenceForNhParsing();
64
65   private final static boolean MIDPOINT_REROOT = APTX_CONFIG
66           .isMidpointReroot();
67
68   private final static NHXParser.TAXONOMY_EXTRACTION TAXONOMY_EXTRACTION = APTX_CONFIG
69           .getTaxonomyExtraction();
70
71   private static Map<ExternalTreeFrame, ExternalTreeViewerBindingI> activeAptx = new HashMap<>();
72
73
74
75
76   public static ExternalTreeFrame createInstanceFromCalculation(
77           final TreeBuilder calculatedTree)
78   {
79     ExternalTreeBuilderI aptxTreeBuilder = new AptxTreeBuilder(
80             calculatedTree);
81
82     ExternalTreeI aptxTree = aptxTreeBuilder.buildTree();
83
84     ExternalTreeFrame aptxApp = createAptxFrame(aptxTree,
85             calculatedTree.getAvport(), null);
86             
87     return aptxApp;
88   }
89
90
91   /**
92    * Refactored from Archaeopteryx.main
93    * 
94    * @param filePath
95    * @param viewport
96    * @return
97    * @throws IOException
98    * @throws FileNotFoundException
99    */
100   public static ExternalTreeFrame[] createInstancesFromFile(
101           String filePath,
102           AlignmentViewport viewport)
103           throws FileNotFoundException, IOException
104   {
105     File treeFile = new File(filePath);
106     ExternalTreeFrame[] aptxFrames = null;
107     if (UtilityMethods.canForesterReadFile(treeFile))
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       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         aptxFrames[i] = createAptxFrame(aptxPhylogeny, viewport, treeTitle);
160
161     }
162     if (Desktop.instance != null)
163     {
164       Desktop.instance.stopLoading();
165       }
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       aptxFrames[i] = createAptxFrame(aptxTree, viewport, treeTitle);
191     }
192
193     if (Desktop.instance != null)
194     {
195       Desktop.instance.stopLoading();
196     }
197
198     return aptxFrames;
199
200   }
201
202   /**
203    * Refactored from Forester's UrlTreeReader, this can be more efficient
204    * 
205    * @param databaseIndex
206    * @param viewport
207    * @return
208    */
209   public static ExternalTreeFrame[] createInstancesFromDb(
210           PhylogeniesWebserviceClient treeDbClient, String identifier,
211           AlignmentViewport viewport)
212   {
213
214     URL url = null;
215     Phylogeny[] trees = null;
216     ExternalTreeFrame[] aptxFrames = 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         aptxFrames = new ExternalTreeFrame[trees.length];
321       } catch (final MalformedURLException e)
322       {
323         exception = true;
324         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
325                 MessageManager.formatMessage(
326                         "exception.unable_to_launch_url", new String[]
327                         { url.toString() }),
328                 MessageManager.getString("label.invalid_url"),
329                 JvOptionPane.ERROR_MESSAGE);
330         System.err.println(e.getLocalizedMessage());
331       } catch (final IOException e)
332       {
333         exception = true;
334         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
335                 "Could not read from " + url + "\n"
336                         + e.getLocalizedMessage(),
337                 "Failed to read tree from " + treeDbClient.getName() + " for "
338                         + identifier,
339                 JvOptionPane.ERROR_MESSAGE);
340         System.err.println(e.getLocalizedMessage());
341       } catch (final NumberFormatException e)
342       {
343         exception = true;
344         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
345                 "Could not read from " + url + "\n"
346                         + e.getLocalizedMessage(),
347                 "Failed to read tree from " + treeDbClient.getName() + " for "
348                         + identifier,
349                 JvOptionPane.ERROR_MESSAGE);
350         System.err.println(e.getLocalizedMessage());
351       } catch (final Exception e)
352       {
353         exception = true;
354         e.printStackTrace();
355         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
356                 e.getLocalizedMessage(), "Unexpected Exception",
357                 JvOptionPane.ERROR_MESSAGE);
358         System.err.println(e.getLocalizedMessage());
359       }
360       if ((trees != null) && (trees.length > 0))
361       {
362         int i = 0;
363         for (final Phylogeny aptxTree : trees)
364         {
365           if (!aptxTree.isEmpty())
366           {
367             if (treeDbClient.getName().equals(WebserviceUtil.TREE_FAM_NAME))
368             {
369               aptxTree.setRerootable(false);
370               aptxTree.setRooted(true);
371             }
372             if (treeDbClient.getProcessingInstructions() != null)
373             {
374               try
375               {
376                 WebserviceUtil.processInstructions(treeDbClient,
377                         aptxTree);
378               } catch (final PhyloXmlDataFormatException e)
379               {
380                 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
381                         "Error:\n" + e.getLocalizedMessage(), "Error",
382                         JvOptionPane.ERROR_MESSAGE);
383               }
384             }
385             if (treeDbClient.getNodeField() != null)
386             {
387               try
388               {
389                 PhylogenyMethods.transferNodeNameToField(aptxTree,
390                         treeDbClient.getNodeField(), false);
391               } catch (final PhyloXmlDataFormatException e)
392               {
393                 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
394                         "Error:\n" + e.getLocalizedMessage(), "Error",
395                         JvOptionPane.ERROR_MESSAGE);
396               }
397             }
398             aptxTree.setIdentifier(
399                     new Identifier(identifier, treeDbClient.getName()));
400             // _main_frame.getJMenuBar().remove(_main_frame.getHelpMenu());
401             // _main_frame.getMenuBarOfExternalTreeFrameI()
402             // .add(_main_frame.getHelpMenu());
403             // _main_frame.getMainPanel().addExternalTreeIInNewTab(ExternalTreeI,
404             // _main_frame.getConfiguration(),
405             // new File(url.getFile()).getName(), url.toString());
406
407
408             ExternalTreeFrame aptxApp = createAptxFrame(aptxTree,
409                     viewport,
410                     url.getFile());
411             String my_name_for_file = "";
412             if (!ForesterUtil.isEmpty(aptxTree.getName()))
413             {
414               my_name_for_file = new String(aptxTree.getName())
415                       .replaceAll(" ", "_");
416             }
417             else if (aptxTree.getIdentifier() != null)
418             {
419               final StringBuffer sb = new StringBuffer();
420               if (!ForesterUtil
421                       .isEmpty(aptxTree.getIdentifier().getProvider()))
422               {
423                 sb.append(aptxTree.getIdentifier().getProvider());
424                 sb.append("_");
425               }
426               sb.append(aptxTree.getIdentifier().getValue());
427               my_name_for_file = new String(
428                       sb.toString().replaceAll(" ", "_"));
429             }
430             aptxApp.getTreePanel()
431                     .setTreeFile(new File(my_name_for_file));
432             // AptxUtil.lookAtSomeTreePropertiesForAptxControlSettings(
433             // aptxTree, aptxApp.getMainPanel().getControlPanel(),
434             // APTX_CONFIG);
435             aptxApp.getTreeControls().displayEntireTree();
436
437             aptxApp.checkMultipleTrees();
438             aptxFrames[i++] = aptxApp;
439           }
440         }
441       }
442       else if (!exception) // ..what?
443       {
444         JvOptionPane.showMessageDialog(null,
445                 ForesterUtil.wordWrap(
446                         "Failed to read in tree(s) from [" + url + "]", 80),
447                 "Error", JvOptionPane.ERROR_MESSAGE);
448       }
449       if ((trees != null) && (trees.length > 0))
450       {
451         try
452         {
453           JvOptionPane.showMessageDialog(null,
454                   ForesterUtil.wordWrap("Successfully read in "
455                           + trees.length + " tree(s) from [" + url + "]",
456                           80),
457                   "Success", JvOptionPane.INFORMATION_MESSAGE);
458         } catch (final Exception e)
459         {
460           // Not important if this fails, do nothing.
461         }
462         // _main_frame.getContentPane().repaint();
463       }
464     }
465
466     System.gc();
467
468
469     if (Desktop.instance != null)
470     {
471       Desktop.instance.stopLoading();
472     }
473     return aptxFrames;
474
475
476   }
477
478
479
480   public static ExternalTreeFrame createAptxFrame(ExternalTreeI aptxTree,
481           AlignmentViewport jalviewAlignport, String treeTitle)
482   {
483     validateConfig(APTX_CONFIG);
484     ExternalTreeFrame aptxApp = aptxTree
485             .createTreeViewerFromTree(treeTitle);
486     ExternalTreeI jalviewTree = aptxApp.getTree();
487     ExternalLoadedTreeAssociationI bindAptxNodes = new LoadedTreeSequenceAssociation(
488             jalviewAlignport.getAlignment().getSequencesArray(),
489             jalviewTree);
490     bindAptxNodes.associateLeavesToSequences();
491
492     bindNodesToJalviewSequences(aptxApp, jalviewAlignport,
493             bindAptxNodes.getAlignmentWithNodes(),
494             bindAptxNodes.getNodesWithAlignment());
495     bindTreeViewFrameToJalview(aptxApp);
496
497     // adaptAptxGui(aptxApp); //moved to AptxFrame
498     return aptxApp;
499   }
500
501
502   protected static ExternalTreeFrame createAptxFrame(
503           final Phylogeny aptxTree,
504           final AlignmentViewport jalviewAlignport, String treeTitle)
505   {
506     validateConfig(APTX_CONFIG);
507     ExternalTreeFrame aptxApp = new AptxFrame(aptxTree, APTX_CONFIG,
508             treeTitle);
509     ExternalTreeI jalviewTree = aptxApp.getTree();
510     ExternalLoadedTreeAssociationI bindAptxNodes = new LoadedTreeSequenceAssociation(
511             jalviewAlignport.getAlignment().getSequencesArray(),
512             jalviewTree);
513     bindAptxNodes.associateLeavesToSequences();
514
515     bindNodesToJalviewSequences(aptxApp, jalviewAlignport,
516             bindAptxNodes.getAlignmentWithNodes(),
517             bindAptxNodes.getNodesWithAlignment());
518     bindTreeViewFrameToJalview(aptxApp);
519
520     // adaptAptxGui(aptxApp); //moved to AptxFrame
521     return aptxApp;
522   }
523
524
525   protected static ExternalTreeViewerBindingI bindNodesToJalviewSequences(
526           final ExternalTreeFrame aptxApp,
527           final AlignmentViewport jalviewAlignViewport,
528           final Map<SequenceI, ExternalTreeNodeI> alignMappedToNodes,
529           final Map<ExternalTreeNodeI, SequenceI> nodesMappedToAlign)
530   {
531     ExternalTreeViewerBindingI treeBinding = new JalviewBinding(aptxApp,
532             jalviewAlignViewport,
533             alignMappedToNodes, nodesMappedToAlign);
534     activeAptx.put(aptxApp, treeBinding);
535     return treeBinding;
536   }
537
538
539   protected static ExternalTreeFrame bindTreeViewFrameToJalview(
540           final ExternalTreeFrame aptxApp)
541   {
542     int width = 400;
543     int height = 550;
544     aptxApp.setMinimumSize(new Dimension(width, height));
545     // aptxApp.setFont(Desktop.instance.getFont());
546     // aptxApp.getMainPanel().setFont(Desktop.instance.getFont());
547     String frameTitle = MessageManager.getString("label.aptx_title");
548     File treeFile = aptxApp.getTreePanel().getTreeFile();
549     if (treeFile != null)
550     {
551       frameTitle += MessageManager.formatMessage("label.aptx_title_append",
552               new String[]
553               { treeFile.getAbsolutePath() });
554     }
555     aptxApp.addFrameToJalview(frameTitle, true, width, height, true,
556             true);
557     return aptxApp;
558
559   }
560
561   private static boolean validateConfig(Configuration aptxConfig)
562   {
563     if (aptxConfig == null || aptxConfig.isCouldReadConfigFile() == false)
564     {
565       int keepGoing = JvOptionPane.showConfirmDialog(Desktop.desktop,
566               MessageManager.getString("label.aptx_config_not_found"),
567               MessageManager.formatMessage("label.couldnt_locate",
568                       new String[]
569                       { "_aptx_jalview_configuration_file" }),
570               JvOptionPane.YES_NO_CANCEL_OPTION);
571
572       if (keepGoing == JvOptionPane.CANCEL_OPTION
573               || keepGoing == JvOptionPane.CLOSED_OPTION
574               || keepGoing == JvOptionPane.NO_OPTION)
575       {
576         return false;
577       }
578
579     }
580     return true;
581   }
582
583
584
585   public static Map<ExternalTreeFrame, ExternalTreeViewerBindingI> getAllAptxFrames()
586   {
587     return activeAptx;
588   }
589
590
591 }