JAL-2838 Aptx frames now appear in the alignment sorting menu
[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.ExternalTreeBuilderI;
6 import jalview.ext.treeviewer.ExternalTreeViewerBindingI;
7 import jalview.gui.Desktop;
8 import jalview.gui.JvOptionPane;
9 import jalview.util.MessageManager;
10 import jalview.viewmodel.AlignmentViewport;
11
12 import java.awt.Dimension;
13 import java.io.File;
14 import java.io.FileNotFoundException;
15 import java.io.IOException;
16 import java.net.MalformedURLException;
17 import java.net.URL;
18 import java.util.HashMap;
19 import java.util.Map;
20
21 import org.forester.archaeopteryx.AptxUtil;
22 import org.forester.archaeopteryx.Archaeopteryx;
23 import org.forester.archaeopteryx.Configuration;
24 import org.forester.archaeopteryx.MainFrame;
25 import org.forester.archaeopteryx.webservices.PhylogeniesWebserviceClient;
26 import org.forester.archaeopteryx.webservices.WebserviceUtil;
27 import org.forester.archaeopteryx.webservices.WebservicesManager;
28 import org.forester.io.parsers.PhylogenyParser;
29 import org.forester.io.parsers.nexus.NexusPhylogeniesParser;
30 import org.forester.io.parsers.nhx.NHXParser;
31 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
32 import org.forester.io.parsers.phyloxml.PhyloXmlParser;
33 import org.forester.io.parsers.tol.TolParser;
34 import org.forester.io.parsers.util.ParserUtils;
35 import org.forester.phylogeny.Phylogeny;
36 import org.forester.phylogeny.PhylogenyMethods;
37 import org.forester.phylogeny.PhylogenyNode;
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
51   private final static Configuration APTX_CONFIG = new Configuration(
52           "_aptx_jalview_configuration_file", 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<MainFrame, JalviewBinding> activeAptx = new HashMap<>();
70
71
72
73   public static MainFrame createInstanceFromCalculation(
74           final TreeBuilder calculatedTree)
75   {
76     ExternalTreeBuilderI<Phylogeny, PhylogenyNode> aptxTreeBuilder = new AptxTreeBuilder(
77             calculatedTree);
78
79     Phylogeny aptxTree = aptxTreeBuilder.buildTree();
80
81     MainFrame 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 MainFrame[] createInstancesFromFile(String filePath,
97           AlignmentViewport viewport)
98           throws FileNotFoundException, IOException
99   {
100     File treeFile = new File(filePath);
101     final String err = ForesterUtil.isReadableFile(treeFile);
102     if (!ForesterUtil.isEmpty(err))
103     {
104       JvOptionPane.showMessageDialog(Desktop.desktop, err,
105               MessageManager.getString("label.problem_reading_tree_file"),
106               JvOptionPane.WARNING_MESSAGE);
107     }
108
109     if (Desktop.instance != null)
110     {
111       Desktop.instance.startLoading(filePath);
112     }
113     boolean nhx_or_nexus = false;
114     final PhylogenyParser parser = ParserUtils.createParserDependingOnFileType(
115             treeFile, VALIDATE_PHYLOXML_XSD);
116     if (parser instanceof NHXParser)
117     {
118       nhx_or_nexus = true;
119       final NHXParser nhx = (NHXParser) parser;
120       nhx.setReplaceUnderscores(REPLACE_NHX_UNDERSCORES);
121       nhx.setIgnoreQuotes(false);
122       nhx.setTaxonomyExtraction(TAXONOMY_EXTRACTION);
123     }
124     else if (parser instanceof NexusPhylogeniesParser)
125     {
126       nhx_or_nexus = true;
127       final NexusPhylogeniesParser nex = (NexusPhylogeniesParser) parser;
128       nex.setReplaceUnderscores(REPLACE_NHX_UNDERSCORES);
129       nex.setIgnoreQuotes(false);
130     }
131 //    else if (p instanceof PhyloXmlParser)
132 //    {
133 //      MainFrameApplication.warnIfNotPhyloXmlValidation(APTX_CONFIG);
134 //    }
135     Phylogeny[] trees = PhylogenyMethods.readPhylogenies(parser, treeFile);
136     MainFrame[] aptxFrames = new MainFrame[trees.length];
137
138
139     for (int i = 0; i < trees.length; i++)
140       {
141       Phylogeny tree = trees[i];
142
143       if (nhx_or_nexus && INTERNAL_NUMBERS_AS_CONFIDENCE)
144       {
145         PhylogenyMethods.transferInternalNodeNamesToConfidence(tree, "");
146       }
147       String treeTitle = treeFile.getName() + "[" + i + "]";
148       tree.setName(treeTitle);
149       aptxFrames[i] = createAptxFrame(tree, viewport, treeTitle);
150
151     }
152     if (Desktop.instance != null)
153     {
154       Desktop.instance.stopLoading();
155     }
156     return aptxFrames;
157     }
158
159
160   public static MainFrame[] createInstancesFromUrl(URL treeUrl,
161           AlignmentViewport viewport)
162           throws FileNotFoundException, IOException, RuntimeException
163   {
164     
165     String treeTitle = treeUrl.getFile();
166     if (Desktop.instance != null)
167     {
168       Desktop.instance.startLoading(treeTitle);
169     }
170     Phylogeny[] trees = AptxUtil.readPhylogeniesFromUrl(treeUrl,
171             VALIDATE_PHYLOXML_XSD,
172              REPLACE_NHX_UNDERSCORES, INTERNAL_NUMBERS_AS_CONFIDENCE,
173             TAXONOMY_EXTRACTION, MIDPOINT_REROOT);
174
175     MainFrame[] aptxFrames = new MainFrame[trees.length];
176     for (int i = 0; i < trees.length; i++)
177     {
178       Phylogeny tree = trees[i];
179       aptxFrames[i] = createAptxFrame(tree, viewport, treeTitle);
180     }
181
182     if (Desktop.instance != null)
183     {
184       Desktop.instance.stopLoading();
185     }
186
187     return aptxFrames;
188
189   }
190
191   /**
192    * Refactored from Forester's UrlTreeReader, this can be more efficient
193    * 
194    * @param databaseIndex
195    * @param viewport
196    * @return
197    */
198   public static MainFrame[] createInstancesFromDb(int databaseIndex,
199           AlignmentViewport viewport)
200   {
201
202     URL url = null;
203     Phylogeny[] trees = null;
204     final WebservicesManager webservices_manager = WebservicesManager
205             .getInstance();
206     final PhylogeniesWebserviceClient client = webservices_manager
207             .getAvailablePhylogeniesWebserviceClient(databaseIndex);
208     String identifier = JvOptionPane.showInternalInputDialog(
209             Desktop.desktop,
210             client.getInstructions() + "\n(Reference: "
211                     + client.getReference() + ")",
212             client.getDescription(), JvOptionPane.QUESTION_MESSAGE);
213
214     if ((identifier != null) && (identifier.trim().length() > 0))
215     {
216       if (Desktop.instance != null)
217       {
218         Desktop.instance.startLoading(identifier);
219       }
220
221       identifier = identifier.trim();
222       if (client.isQueryInteger())
223       {
224         identifier = identifier.replaceAll("^\\D+", "");
225
226         int id;
227         try
228         {
229           id = Integer.parseInt(identifier);
230         } catch (final NumberFormatException e)
231         {
232           JvOptionPane.showInternalMessageDialog(Desktop.desktop,
233                   "Identifier is expected to be a number",
234                   "Can not open URL", JvOptionPane.ERROR_MESSAGE);
235           return new MainFrame[0];
236         }
237         identifier = id + "";
238       }
239       boolean exception = false;
240       try
241       {
242         String url_str = client.getUrl();
243         url_str = url_str.replaceFirst(
244                 PhylogeniesWebserviceClient.QUERY_PLACEHOLDER, identifier);
245         url = new URL(url_str);
246         PhylogenyParser parser = null;
247         switch (client.getReturnFormat())
248         {
249         case TOL_XML_RESPONSE:
250           parser = new TolParser();
251           break;
252         case NEXUS:
253           parser = new NexusPhylogeniesParser();
254           ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true);
255           break;
256         case TREEBASE_TREE:
257           parser = new NexusPhylogeniesParser();
258           ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true);
259           ((NexusPhylogeniesParser) parser)
260                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
261           break;
262         case TREEBASE_STUDY:
263           parser = new NexusPhylogeniesParser();
264           ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true);
265           ((NexusPhylogeniesParser) parser)
266                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
267           break;
268         case NH:
269           parser = new NHXParser();
270           ((NHXParser) parser)
271                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
272           ((NHXParser) parser).setReplaceUnderscores(true);
273           ((NHXParser) parser).setGuessRootedness(true);
274           break;
275         case NH_EXTRACT_TAXONOMY:
276           parser = new NHXParser();
277           ((NHXParser) parser).setTaxonomyExtraction(
278                   NHXParser.TAXONOMY_EXTRACTION.AGGRESSIVE);
279           ((NHXParser) parser).setReplaceUnderscores(false);
280           ((NHXParser) parser).setGuessRootedness(true);
281           break;
282         case PFAM:
283           parser = new NHXParser();
284           ((NHXParser) parser).setTaxonomyExtraction(
285                   NHXParser.TAXONOMY_EXTRACTION.PFAM_STYLE_STRICT);
286           ((NHXParser) parser).setReplaceUnderscores(false);
287           ((NHXParser) parser).setGuessRootedness(true);
288           break;
289         case NHX:
290           parser = new NHXParser();
291           ((NHXParser) parser)
292                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
293           ((NHXParser) parser).setReplaceUnderscores(false);
294           ((NHXParser) parser).setGuessRootedness(true);
295           break;
296         case PHYLOXML:
297           parser = PhyloXmlParser.createPhyloXmlParserXsdValidating();
298           break;
299         default:
300           throw new IllegalArgumentException(
301                   "unknown format: " + client.getReturnFormat());
302         }
303         //
304         // if (_main_frame.getMainPanel().getCurrentTreePanel() != null)
305         // {
306         // _main_frame.getMainPanel().getCurrentTreePanel().setWaitCursor();
307         // }
308         // else
309         // {
310         // _main_frame.getMainPanel().setWaitCursor();
311         // }
312         trees = ForesterUtil.readPhylogeniesFromUrl(url, parser);
313       } catch (final MalformedURLException e)
314       {
315         exception = true;
316         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
317                 "Malformed URL: " + url + "\n" + e.getLocalizedMessage(),
318                 "Malformed URL", JvOptionPane.ERROR_MESSAGE);
319       } catch (final IOException e)
320       {
321         exception = true;
322         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
323                 "Could not read from " + url + "\n"
324                         + e.getLocalizedMessage(),
325                 "Failed to read tree from " + client.getName() + " for "
326                         + identifier,
327                 JvOptionPane.ERROR_MESSAGE);
328       } catch (final NumberFormatException e)
329       {
330         exception = true;
331         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
332                 "Could not read from " + url + "\n"
333                         + e.getLocalizedMessage(),
334                 "Failed to read tree from " + client.getName() + " for "
335                         + identifier,
336                 JvOptionPane.ERROR_MESSAGE);
337       } catch (final Exception e)
338       {
339         exception = true;
340         e.printStackTrace();
341         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
342                 e.getLocalizedMessage(), "Unexpected Exception",
343                 JvOptionPane.ERROR_MESSAGE);
344       } finally
345       {
346         // if (_main_frame.getCurrentTreePanel() != null)
347         // {
348         // _main_frame.getCurrentTreePanel().setArrowCursor();
349         // }
350         // else
351         // {
352         // _main_frame.getMainPanel().setArrowCursor();
353         // }
354       }
355       if ((trees != null) && (trees.length > 0))
356       {
357         for (final Phylogeny phylogeny : trees)
358         {
359           if (!phylogeny.isEmpty())
360           {
361             if (client.getName().equals(WebserviceUtil.TREE_FAM_NAME))
362             {
363               phylogeny.setRerootable(false);
364               phylogeny.setRooted(true);
365             }
366             if (client.getProcessingInstructions() != null)
367             {
368               try
369               {
370                 WebserviceUtil.processInstructions(client, phylogeny);
371               } catch (final PhyloXmlDataFormatException e)
372               {
373                 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
374                         "Error:\n" + e.getLocalizedMessage(), "Error",
375                         JvOptionPane.ERROR_MESSAGE);
376               }
377             }
378             if (client.getNodeField() != null)
379             {
380               try
381               {
382                 PhylogenyMethods.transferNodeNameToField(phylogeny,
383                         client.getNodeField(), false);
384               } catch (final PhyloXmlDataFormatException e)
385               {
386                 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
387                         "Error:\n" + e.getLocalizedMessage(), "Error",
388                         JvOptionPane.ERROR_MESSAGE);
389               }
390             }
391             phylogeny.setIdentifier(
392                     new Identifier(identifier, client.getName()));
393             // _main_frame.getJMenuBar().remove(_main_frame.getHelpMenu());
394             // _main_frame.getMenuBarOfMainFrame()
395             // .add(_main_frame.getHelpMenu());
396             // _main_frame.getMainPanel().addPhylogenyInNewTab(phylogeny,
397             // _main_frame.getConfiguration(),
398             // new File(url.getFile()).getName(), url.toString());
399
400             MainFrame aptxApp = createAptxFrame(phylogeny, viewport,
401                     url.getFile());
402             String my_name_for_file = "";
403             if (!ForesterUtil.isEmpty(phylogeny.getName()))
404             {
405               my_name_for_file = new String(phylogeny.getName())
406                       .replaceAll(" ", "_");
407             }
408             else if (phylogeny.getIdentifier() != null)
409             {
410               final StringBuffer sb = new StringBuffer();
411               if (!ForesterUtil
412                       .isEmpty(phylogeny.getIdentifier().getProvider()))
413               {
414                 sb.append(phylogeny.getIdentifier().getProvider());
415                 sb.append("_");
416               }
417               sb.append(phylogeny.getIdentifier().getValue());
418               my_name_for_file = new String(
419                       sb.toString().replaceAll(" ", "_"));
420             }
421             // _main_frame.getMainPanel().getCurrentTreePanel()
422             // .setTreeFile(new File(my_name_for_file));
423             AptxUtil.lookAtSomeTreePropertiesForAptxControlSettings(
424                     phylogeny, aptxApp.getMainPanel().getControlPanel(),
425                     APTX_CONFIG);
426             // _main_frame.getMainPanel().getControlPanel().showWhole();
427
428             aptxApp.activateSaveAllIfNeeded();
429           }
430         }
431       }
432       else if (!exception)
433       {
434         JvOptionPane.showMessageDialog(null,
435                 ForesterUtil.wordWrap(
436                         "Failed to read in tree(s) from [" + url + "]", 80),
437                 "Error", JvOptionPane.ERROR_MESSAGE);
438       }
439       if ((trees != null) && (trees.length > 0))
440       {
441         try
442         {
443           JvOptionPane.showMessageDialog(null,
444                   ForesterUtil.wordWrap("Successfully read in "
445                           + trees.length + " tree(s) from [" + url + "]",
446                           80),
447                   "Success", JvOptionPane.INFORMATION_MESSAGE);
448         } catch (final Exception e)
449         {
450           // Not important if this fails, do nothing.
451         }
452         // _main_frame.getContentPane().repaint();
453       }
454     }
455
456     System.gc();
457
458
459     if (Desktop.instance != null)
460     {
461       Desktop.instance.stopLoading();
462     }
463     return null;
464
465
466   }
467
468
469
470
471
472   public static MainFrame createAptxFrame(
473           final Phylogeny aptxTree,
474           final AlignmentViewport jalviewAlignport, String treeTitle)
475   {
476     MainFrame aptxApp = Archaeopteryx.createApplication(aptxTree,
477             APTX_CONFIG, treeTitle);
478
479     LoadedTreeSequenceAssociation bindAptxNodes = new LoadedTreeSequenceAssociation(
480             jalviewAlignport.getAlignment().getSequencesArray(), aptxTree);
481     bindAptxNodes.associateLeavesToSequences();
482
483     bindNodesToJalviewSequences(aptxApp, jalviewAlignport,
484             bindAptxNodes.getAlignmentWithNodes(),
485             bindAptxNodes.getNodesWithAlignment());
486     bindTreeViewFrameToJalview(aptxApp);
487
488     return aptxApp;
489   }
490
491   // private static void addPartitioningSlider(MainFrame aptxFrame)
492   // {
493   // JSlider slider = new JSlider();
494   //
495   //
496   // }
497
498   public static ExternalTreeViewerBindingI<?> bindNodesToJalviewSequences(
499           final MainFrame aptxApp,
500           final AlignmentViewport jalviewAlignViewport,
501           final Map<SequenceI, PhylogenyNode> alignMappedToNodes,
502           final Map<PhylogenyNode, SequenceI> nodesMappedToAlign)
503   {
504     JalviewBinding treeBinding = new JalviewBinding(aptxApp,
505             jalviewAlignViewport,
506             alignMappedToNodes, nodesMappedToAlign);
507     activeAptx.put(aptxApp, treeBinding);
508     return treeBinding;
509   }
510
511
512   public static MainFrame bindTreeViewFrameToJalview(
513           final MainFrame aptxApp)
514   {
515     int width = 400;
516     int height = 550;
517     aptxApp.setMinimumSize(new Dimension(width, height));
518     // aptxApp.setFont(Desktop.instance.getFont());
519     // aptxApp.getMainPanel().setFont(Desktop.instance.getFont());
520
521     Desktop.addInternalFrame(aptxApp, "Archaeopteryx Tree View", true,
522             width, height, true, true);
523
524     return aptxApp;
525
526   }
527
528   public static Map<MainFrame, JalviewBinding> getAllAptxFrames()
529   {
530     return activeAptx;
531   }
532
533
534 }