JAL-2871 JAL-2877 hideous attempt at seeing if non-static configuration
[jalview.git] / src / jalview / ext / archaeopteryx / AptxInit.java
1 package jalview.ext.archaeopteryx;
2
3 import jalview.analysis.TreeBuilder;
4 import jalview.bin.Cache;
5 import jalview.datamodel.SequenceI;
6 import jalview.ext.treeviewer.ExternalTreeBuilderI;
7 import jalview.ext.treeviewer.ExternalTreeViewerBindingI;
8 import jalview.gui.Desktop;
9 import jalview.gui.JvOptionPane;
10 import jalview.util.MessageManager;
11 import jalview.viewmodel.AlignmentViewport;
12
13 import java.awt.Component;
14 import java.awt.Dimension;
15 import java.io.File;
16 import java.io.FileNotFoundException;
17 import java.io.IOException;
18 import java.net.MalformedURLException;
19 import java.net.URL;
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import javax.swing.JMenu;
24 import javax.swing.JMenuBar;
25 import javax.swing.JMenuItem;
26 import javax.swing.JSeparator;
27
28 import org.forester.archaeopteryx.AptxUtil;
29 import org.forester.archaeopteryx.Archaeopteryx;
30 import org.forester.archaeopteryx.Configuration;
31 import org.forester.archaeopteryx.MainFrame;
32 import org.forester.archaeopteryx.webservices.PhylogeniesWebserviceClient;
33 import org.forester.archaeopteryx.webservices.WebserviceUtil;
34 import org.forester.io.parsers.PhylogenyParser;
35 import org.forester.io.parsers.nexus.NexusPhylogeniesParser;
36 import org.forester.io.parsers.nhx.NHXParser;
37 import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException;
38 import org.forester.io.parsers.phyloxml.PhyloXmlParser;
39 import org.forester.io.parsers.tol.TolParser;
40 import org.forester.io.parsers.util.ParserUtils;
41 import org.forester.phylogeny.Phylogeny;
42 import org.forester.phylogeny.PhylogenyMethods;
43 import org.forester.phylogeny.PhylogenyNode;
44 import org.forester.phylogeny.data.Identifier;
45 import org.forester.util.ForesterUtil;
46
47 /**
48  * Static class for creating Archaeopteryx tree viewer instances from calculated
49  * trees and letting them be bound to Jalview.
50  * 
51  * @author kjvanderheide
52  *
53  */
54 public final class AptxInit
55 {
56
57   private static Map<MainFrame, JalviewBinding> activeAptx = new HashMap<>();
58
59
60
61   public static MainFrame createInstanceFromCalculation(
62           final TreeBuilder calculatedTree)
63   {
64     ExternalTreeBuilderI<Phylogeny, PhylogenyNode> aptxTreeBuilder = new AptxTreeBuilder(
65             calculatedTree);
66
67     Phylogeny aptxTree = aptxTreeBuilder.buildTree();
68
69     MainFrame aptxApp = createAptxFrame(aptxTree,
70             calculatedTree.getAvport(), null);
71             
72     return aptxApp;
73   }
74
75   /**
76    * Refactored from Archaeopteryx.main
77    * 
78    * @param filePath
79    * @param viewport
80    * @return
81    * @throws IOException
82    * @throws FileNotFoundException
83    */
84   public static MainFrame[] createInstancesFromFile(String filePath,
85           AlignmentViewport viewport)
86           throws FileNotFoundException, IOException
87   {
88     Configuration APTX_CONFIG = new Configuration(Cache.getDefault(
89             "APTXCONFIG",
90             Desktop.instance.getClass()
91                     .getResource("/_aptx_jalview_configuration_file.txt")
92                     .toString()),
93             false, false, false);
94     File treeFile = new File(filePath);
95     final String err = ForesterUtil.isReadableFile(treeFile);
96     if (!ForesterUtil.isEmpty(err))
97     {
98       JvOptionPane.showMessageDialog(Desktop.desktop, err,
99               MessageManager.getString("label.problem_reading_tree_file"),
100               JvOptionPane.WARNING_MESSAGE);
101     }
102
103     if (Desktop.instance != null)
104     {
105       Desktop.instance.startLoading(filePath);
106     }
107     boolean nhx_or_nexus = false;
108     final PhylogenyParser parser = ParserUtils.createParserDependingOnFileType(
109                     treeFile,
110                     APTX_CONFIG.isValidatePhyloXmlAgainstSchema());
111     if (parser instanceof NHXParser)
112     {
113       nhx_or_nexus = true;
114       final NHXParser nhx = (NHXParser) parser;
115       nhx.setReplaceUnderscores(
116               APTX_CONFIG.isReplaceUnderscoresInNhParsing());
117       nhx.setIgnoreQuotes(false);
118       nhx.setTaxonomyExtraction(APTX_CONFIG.getTaxonomyExtraction());
119     }
120     else if (parser instanceof NexusPhylogeniesParser)
121     {
122       nhx_or_nexus = true;
123       final NexusPhylogeniesParser nex = (NexusPhylogeniesParser) parser;
124       nex.setReplaceUnderscores(
125               APTX_CONFIG.isReplaceUnderscoresInNhParsing());
126       nex.setIgnoreQuotes(false);
127     }
128     else if (parser instanceof PhyloXmlParser)
129     {
130       if (APTX_CONFIG.isValidatePhyloXmlAgainstSchema() == false)
131       {
132         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
133                 MessageManager.getString("error.phyloxml_validation"),
134                 MessageManager.getString("label.file_open_error"),
135                                        JvOptionPane.WARNING_MESSAGE );
136       }
137     }
138     Phylogeny[] trees = PhylogenyMethods.readPhylogenies(parser, treeFile);
139     MainFrame[] aptxFrames = new MainFrame[trees.length];
140
141
142     for (int i = 0; i < trees.length; i++)
143       {
144       Phylogeny tree = trees[i];
145
146       if (nhx_or_nexus
147               && APTX_CONFIG.isInternalNumberAreConfidenceForNhParsing())
148       {
149         PhylogenyMethods.transferInternalNodeNamesToConfidence(tree, "");
150       }
151       String treeTitle = treeFile.getName() + "[" + i + "]";
152       tree.setName(treeTitle);
153       aptxFrames[i] = createAptxFrame(tree, viewport, treeTitle);
154
155     }
156     if (Desktop.instance != null)
157     {
158       Desktop.instance.stopLoading();
159     }
160     return aptxFrames;
161     }
162
163
164   public static MainFrame[] createInstancesFromUrl(URL treeUrl,
165           AlignmentViewport viewport)
166           throws FileNotFoundException, IOException, RuntimeException
167   {
168     Configuration APTX_CONFIG = new Configuration(Cache.getDefault(
169             "APTXCONFIG",
170             Desktop.instance.getClass()
171                     .getResource("/_aptx_jalview_configuration_file.txt")
172                     .toString()),
173             false, false, false);
174     String treeTitle = treeUrl.getFile();
175     if (Desktop.instance != null)
176     {
177       Desktop.instance.startLoading(treeTitle);
178     }
179     Phylogeny[] trees = AptxUtil.readPhylogeniesFromUrl(treeUrl,
180             APTX_CONFIG.isValidatePhyloXmlAgainstSchema(),
181             APTX_CONFIG.isReplaceUnderscoresInNhParsing(),
182             APTX_CONFIG.isInternalNumberAreConfidenceForNhParsing(),
183             APTX_CONFIG.getTaxonomyExtraction(),
184             APTX_CONFIG.isMidpointReroot());
185
186     MainFrame[] aptxFrames = new MainFrame[trees.length];
187     for (int i = 0; i < trees.length; i++)
188     {
189       Phylogeny tree = trees[i];
190       aptxFrames[i] = createAptxFrame(tree, 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 MainFrame[] createInstancesFromDb(
210           PhylogeniesWebserviceClient treeDbClient, String identifier,
211           AlignmentViewport viewport)
212   {
213     Configuration APTX_CONFIG = new Configuration(Cache.getDefault(
214             "APTXCONFIG",
215             Desktop.instance.getClass()
216                     .getResource("/_aptx_jalview_configuration_file.txt")
217                     .toString()),
218             false, false, false);
219     URL url = null;
220     Phylogeny[] trees = null;
221
222     if ((identifier != null) && (identifier.trim().length() > 0))
223     {
224       if (Desktop.instance != null)
225       {
226         Desktop.instance.startLoading(identifier);
227       }
228
229       identifier = identifier.trim();
230       if (treeDbClient.isQueryInteger())
231       {
232         identifier = identifier.replaceAll("^\\D+", "");
233
234         int id;
235         try
236         {
237           id = Integer.parseInt(identifier);
238         } catch (final NumberFormatException e)
239         {
240           JvOptionPane.showInternalMessageDialog(Desktop.desktop,
241                   MessageManager.formatMessage(
242                           "error.database_id_has_letters", new String[]
243                           { identifier }),
244                   MessageManager.getString("label.invalid_url"),
245                   JvOptionPane.ERROR_MESSAGE);
246           return new MainFrame[0];
247         }
248         identifier = id + "";
249       }
250       boolean exception = false;
251       try
252       {
253         String url_str = treeDbClient.getUrl();
254         url_str = url_str.replaceFirst(
255                 PhylogeniesWebserviceClient.QUERY_PLACEHOLDER, identifier);
256         url = new URL(url_str);
257         PhylogenyParser parser = null;
258         switch (treeDbClient.getReturnFormat())
259         {
260         case TOL_XML_RESPONSE:
261           parser = new TolParser();
262           break;
263         case NEXUS:
264           parser = new NexusPhylogeniesParser();
265           ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true);
266           break;
267         case TREEBASE_TREE:
268           parser = new NexusPhylogeniesParser();
269           ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true);
270           ((NexusPhylogeniesParser) parser)
271                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
272           break;
273         case TREEBASE_STUDY:
274           parser = new NexusPhylogeniesParser();
275           ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true);
276           ((NexusPhylogeniesParser) parser)
277                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
278           break;
279         case NH:
280           parser = new NHXParser();
281           ((NHXParser) parser)
282                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
283           ((NHXParser) parser).setReplaceUnderscores(true);
284           ((NHXParser) parser).setGuessRootedness(true);
285           break;
286         case NH_EXTRACT_TAXONOMY:
287           parser = new NHXParser();
288           ((NHXParser) parser).setTaxonomyExtraction(
289                   NHXParser.TAXONOMY_EXTRACTION.AGGRESSIVE);
290           ((NHXParser) parser).setReplaceUnderscores(false);
291           ((NHXParser) parser).setGuessRootedness(true);
292           break;
293         case PFAM:
294           parser = new NHXParser();
295           ((NHXParser) parser).setTaxonomyExtraction(
296                   NHXParser.TAXONOMY_EXTRACTION.PFAM_STYLE_STRICT);
297           ((NHXParser) parser).setReplaceUnderscores(false);
298           ((NHXParser) parser).setGuessRootedness(true);
299           break;
300         case NHX:
301           parser = new NHXParser();
302           ((NHXParser) parser)
303                   .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO);
304           ((NHXParser) parser).setReplaceUnderscores(false);
305           ((NHXParser) parser).setGuessRootedness(true);
306           break;
307         case PHYLOXML:
308           parser = PhyloXmlParser.createPhyloXmlParserXsdValidating();
309           break;
310         default:
311           throw new IllegalArgumentException(
312                   "unknown format: " + treeDbClient.getReturnFormat());
313         }
314         //
315         // if (_main_frame.getMainPanel().getCurrentTreePanel() != null)
316         // {
317         // _main_frame.getMainPanel().getCurrentTreePanel().setWaitCursor();
318         // }
319         // else
320         // {
321         // _main_frame.getMainPanel().setWaitCursor();
322         // }
323         trees = ForesterUtil.readPhylogeniesFromUrl(url, parser);
324       } catch (final MalformedURLException e)
325       {
326         exception = true;
327         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
328                 MessageManager.formatMessage(
329                         "exception.unable_to_launch_url", new String[]
330                         { url.toString() }),
331                 MessageManager.getString("label.invalid_url"),
332                 JvOptionPane.ERROR_MESSAGE);
333         System.err.println(e.getLocalizedMessage());
334       } catch (final IOException e)
335       {
336         exception = true;
337         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
338                 "Could not read from " + url + "\n"
339                         + e.getLocalizedMessage(),
340                 "Failed to read tree from " + treeDbClient.getName() + " for "
341                         + identifier,
342                 JvOptionPane.ERROR_MESSAGE);
343         System.err.println(e.getLocalizedMessage());
344       } catch (final NumberFormatException e)
345       {
346         exception = true;
347         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
348                 "Could not read from " + url + "\n"
349                         + e.getLocalizedMessage(),
350                 "Failed to read tree from " + treeDbClient.getName() + " for "
351                         + identifier,
352                 JvOptionPane.ERROR_MESSAGE);
353         System.err.println(e.getLocalizedMessage());
354       } catch (final Exception e)
355       {
356         exception = true;
357         e.printStackTrace();
358         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
359                 e.getLocalizedMessage(), "Unexpected Exception",
360                 JvOptionPane.ERROR_MESSAGE);
361         System.err.println(e.getLocalizedMessage());
362       }
363       if ((trees != null) && (trees.length > 0))
364       {
365         for (final Phylogeny phylogeny : trees)
366         {
367           if (!phylogeny.isEmpty())
368           {
369             if (treeDbClient.getName().equals(WebserviceUtil.TREE_FAM_NAME))
370             {
371               phylogeny.setRerootable(false);
372               phylogeny.setRooted(true);
373             }
374             if (treeDbClient.getProcessingInstructions() != null)
375             {
376               try
377               {
378                 WebserviceUtil.processInstructions(treeDbClient, phylogeny);
379               } catch (final PhyloXmlDataFormatException e)
380               {
381                 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
382                         "Error:\n" + e.getLocalizedMessage(), "Error",
383                         JvOptionPane.ERROR_MESSAGE);
384               }
385             }
386             if (treeDbClient.getNodeField() != null)
387             {
388               try
389               {
390                 PhylogenyMethods.transferNodeNameToField(phylogeny,
391                         treeDbClient.getNodeField(), false);
392               } catch (final PhyloXmlDataFormatException e)
393               {
394                 JvOptionPane.showInternalMessageDialog(Desktop.desktop,
395                         "Error:\n" + e.getLocalizedMessage(), "Error",
396                         JvOptionPane.ERROR_MESSAGE);
397               }
398             }
399             phylogeny.setIdentifier(
400                     new Identifier(identifier, treeDbClient.getName()));
401             // _main_frame.getJMenuBar().remove(_main_frame.getHelpMenu());
402             // _main_frame.getMenuBarOfMainFrame()
403             // .add(_main_frame.getHelpMenu());
404             // _main_frame.getMainPanel().addPhylogenyInNewTab(phylogeny,
405             // _main_frame.getConfiguration(),
406             // new File(url.getFile()).getName(), url.toString());
407
408             MainFrame aptxApp = createAptxFrame(phylogeny, viewport,
409                     url.getFile());
410             String my_name_for_file = "";
411             if (!ForesterUtil.isEmpty(phylogeny.getName()))
412             {
413               my_name_for_file = new String(phylogeny.getName())
414                       .replaceAll(" ", "_");
415             }
416             else if (phylogeny.getIdentifier() != null)
417             {
418               final StringBuffer sb = new StringBuffer();
419               if (!ForesterUtil
420                       .isEmpty(phylogeny.getIdentifier().getProvider()))
421               {
422                 sb.append(phylogeny.getIdentifier().getProvider());
423                 sb.append("_");
424               }
425               sb.append(phylogeny.getIdentifier().getValue());
426               my_name_for_file = new String(
427                       sb.toString().replaceAll(" ", "_"));
428             }
429             aptxApp.getMainPanel().getCurrentTreePanel()
430                     .setTreeFile(new File(my_name_for_file));
431             AptxUtil.lookAtSomeTreePropertiesForAptxControlSettings(
432                     phylogeny, aptxApp.getMainPanel().getControlPanel(),
433                     APTX_CONFIG);
434             // _main_frame.getMainPanel().getControlPanel().showWhole();
435
436             aptxApp.activateSaveAllIfNeeded();
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 MainFrame createAptxFrame(
481           final Phylogeny aptxTree,
482           final AlignmentViewport jalviewAlignport, String treeTitle)
483   {
484     Configuration APTX_CONFIG = new Configuration(Cache.getDefault(
485             "APTXCONFIG",
486             Desktop.instance.getClass()
487                     .getResource("/_aptx_jalview_configuration_file.txt")
488                     .toString()),
489             false, false, false);
490     if (APTX_CONFIG == null || APTX_CONFIG.isCouldReadConfigFile() == false)
491     {
492       int keepGoing = JvOptionPane.showConfirmDialog(Desktop.desktop,
493               MessageManager.getString("label.aptx_config_not_found"),
494               MessageManager.formatMessage("label.couldnt_locate",
495                       new String[]
496                       { "_aptx_jalview_configuration_file" }),
497               JvOptionPane.YES_NO_CANCEL_OPTION);
498
499       if (keepGoing == JvOptionPane.CANCEL_OPTION
500               || keepGoing == JvOptionPane.CLOSED_OPTION
501               || keepGoing == JvOptionPane.NO_OPTION)
502       {
503         return null;
504       }
505
506     }
507     MainFrame aptxApp = Archaeopteryx.createApplication(aptxTree,
508             APTX_CONFIG, treeTitle);
509
510
511     LoadedTreeSequenceAssociation bindAptxNodes = new LoadedTreeSequenceAssociation(
512             jalviewAlignport.getAlignment().getSequencesArray(), aptxTree);
513     bindAptxNodes.associateLeavesToSequences();
514
515     bindNodesToJalviewSequences(aptxApp, jalviewAlignport,
516             bindAptxNodes.getAlignmentWithNodes(),
517             bindAptxNodes.getNodesWithAlignment());
518     bindTreeViewFrameToJalview(aptxApp);
519
520     adaptAptxGui(aptxApp);
521     return aptxApp;
522   }
523
524
525   public static ExternalTreeViewerBindingI<?> bindNodesToJalviewSequences(
526           final MainFrame aptxApp,
527           final AlignmentViewport jalviewAlignViewport,
528           final Map<SequenceI, PhylogenyNode> alignMappedToNodes,
529           final Map<PhylogenyNode, SequenceI> nodesMappedToAlign)
530   {
531     JalviewBinding treeBinding = new JalviewBinding(aptxApp,
532             jalviewAlignViewport,
533             alignMappedToNodes, nodesMappedToAlign);
534     activeAptx.put(aptxApp, treeBinding);
535     return treeBinding;
536   }
537
538
539   public static MainFrame bindTreeViewFrameToJalview(
540           final MainFrame 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.getMainPanel().getCurrentTreePanel()
549             .getTreeFile();
550     if (treeFile != null)
551     {
552       frameTitle += MessageManager.formatMessage("label.aptx_title_append",
553               new String[]
554               { treeFile.getAbsolutePath() });
555     }
556     Desktop.addInternalFrame(aptxApp, frameTitle, true, width, height, true,
557             true);
558     return aptxApp;
559
560   }
561
562   /**
563    * Hides certain redundant Archaeopteryx GUI elements such as the menu items
564    * for reading in trees and adds extra items related to Jalview such as the
565    * tree sorting item.
566    * 
567    * 
568    * @param aptxFrame
569    */
570   private static void adaptAptxGui(MainFrame aptxFrame)
571   {
572     JMenuBar frameBar = aptxFrame.getJMenuBar();
573
574     for (int i = 0; i < frameBar.getMenuCount();i++) {
575       JMenu menu = frameBar.getMenu(i);
576
577       if (menu.getText().contains("File"))
578       {
579         // hide all "Read from ..." and "New" menu items and any Separators that
580         // come directly after them
581         Component previousMenuItem = null;
582         for (Component menuItem : menu.getMenuComponents()) {
583           if (previousMenuItem instanceof JMenuItem)
584           {
585             if (((JMenuItem) previousMenuItem).getText().startsWith("Read")
586                     || ((JMenuItem) previousMenuItem).getText()
587                             .startsWith("New"))
588             {
589               previousMenuItem.setVisible(false);
590
591               if (menuItem instanceof JSeparator)
592               {
593                 menuItem.setVisible(false);
594               }
595             }
596           }
597           previousMenuItem = menuItem;
598         }
599       }
600       else if (menu.getText().contains("Inference"))
601       {
602         menu.setVisible(false);
603       }
604       else if (menu.getText().contains("View"))
605       {
606         menu.addSeparator();
607         JMenuItem sortByTree = new JMenuItem("Sort alignment by tree");
608         JMenuItem refreshJalview = new JMenuItem(
609                 "Filter alignment to show only currently visible sequences");
610
611         refreshJalview.setFont(menu.getFont());
612
613         menu.add(sortByTree);
614         menu.add(refreshJalview);
615
616         sortByTree.setFont(menu.getFont());
617         sortByTree.setVisible(false); // don't show unless it's actually
618         // possible
619
620         refreshJalview.addActionListener(activeAptx.get(aptxFrame));
621
622
623       }
624
625     }
626     aptxFrame.validate();
627   }
628
629   public static Map<MainFrame, JalviewBinding> getAllAptxFrames()
630   {
631     return activeAptx;
632   }
633
634
635 }