package jalview.ext.archaeopteryx; import jalview.analysis.TreeBuilder; import jalview.datamodel.SequenceI; import jalview.ext.treeviewer.ExternalTreeBuilderI; import jalview.ext.treeviewer.ExternalTreeViewerBindingI; import jalview.gui.Desktop; import jalview.gui.JvOptionPane; import jalview.util.MessageManager; import jalview.viewmodel.AlignmentViewport; import java.awt.Component; import java.awt.Dimension; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JSeparator; import org.forester.archaeopteryx.AptxUtil; import org.forester.archaeopteryx.Archaeopteryx; import org.forester.archaeopteryx.Configuration; import org.forester.archaeopteryx.MainFrame; import org.forester.archaeopteryx.webservices.PhylogeniesWebserviceClient; import org.forester.archaeopteryx.webservices.WebserviceUtil; import org.forester.io.parsers.PhylogenyParser; import org.forester.io.parsers.nexus.NexusPhylogeniesParser; import org.forester.io.parsers.nhx.NHXParser; import org.forester.io.parsers.phyloxml.PhyloXmlDataFormatException; import org.forester.io.parsers.phyloxml.PhyloXmlParser; import org.forester.io.parsers.tol.TolParser; import org.forester.io.parsers.util.ParserUtils; import org.forester.phylogeny.Phylogeny; import org.forester.phylogeny.PhylogenyMethods; import org.forester.phylogeny.PhylogenyNode; import org.forester.phylogeny.data.Identifier; import org.forester.util.ForesterUtil; /** * Static class for creating Archaeopteryx tree viewer instances from calculated * trees and letting them be bound to Jalview. * * @author kjvanderheide * */ public final class AptxInit { private final static Configuration APTX_CONFIG = new Configuration( "_aptx_jalview_configuration_file", false, false, false); private final static boolean VALIDATE_PHYLOXML_XSD = APTX_CONFIG .isValidatePhyloXmlAgainstSchema(); private final static boolean REPLACE_NHX_UNDERSCORES = APTX_CONFIG .isReplaceUnderscoresInNhParsing(); private final static boolean INTERNAL_NUMBERS_AS_CONFIDENCE = APTX_CONFIG .isInternalNumberAreConfidenceForNhParsing(); private final static boolean MIDPOINT_REROOT = APTX_CONFIG .isMidpointReroot(); private final static NHXParser.TAXONOMY_EXTRACTION TAXONOMY_EXTRACTION = APTX_CONFIG .getTaxonomyExtraction(); private static Map activeAptx = new HashMap<>(); public static MainFrame createInstanceFromCalculation( final TreeBuilder calculatedTree) { ExternalTreeBuilderI aptxTreeBuilder = new AptxTreeBuilder( calculatedTree); Phylogeny aptxTree = aptxTreeBuilder.buildTree(); MainFrame aptxApp = createAptxFrame(aptxTree, calculatedTree.getAvport(), null); return aptxApp; } /** * Refactored from Archaeopteryx.main * * @param filePath * @param viewport * @return * @throws IOException * @throws FileNotFoundException */ public static MainFrame[] createInstancesFromFile(String filePath, AlignmentViewport viewport) throws FileNotFoundException, IOException { File treeFile = new File(filePath); final String err = ForesterUtil.isReadableFile(treeFile); if (!ForesterUtil.isEmpty(err)) { JvOptionPane.showMessageDialog(Desktop.desktop, err, MessageManager.getString("label.problem_reading_tree_file"), JvOptionPane.WARNING_MESSAGE); } if (Desktop.instance != null) { Desktop.instance.startLoading(filePath); } boolean nhx_or_nexus = false; final PhylogenyParser parser = ParserUtils.createParserDependingOnFileType( treeFile, VALIDATE_PHYLOXML_XSD); if (parser instanceof NHXParser) { nhx_or_nexus = true; final NHXParser nhx = (NHXParser) parser; nhx.setReplaceUnderscores(REPLACE_NHX_UNDERSCORES); nhx.setIgnoreQuotes(false); nhx.setTaxonomyExtraction(TAXONOMY_EXTRACTION); } else if (parser instanceof NexusPhylogeniesParser) { nhx_or_nexus = true; final NexusPhylogeniesParser nex = (NexusPhylogeniesParser) parser; nex.setReplaceUnderscores(REPLACE_NHX_UNDERSCORES); nex.setIgnoreQuotes(false); } else if (parser instanceof PhyloXmlParser) { if (VALIDATE_PHYLOXML_XSD == false) { JvOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager.getString("error.phyloxml_validation"), MessageManager.getString("label.file_open_error"), JvOptionPane.WARNING_MESSAGE ); } } Phylogeny[] trees = PhylogenyMethods.readPhylogenies(parser, treeFile); MainFrame[] aptxFrames = new MainFrame[trees.length]; for (int i = 0; i < trees.length; i++) { Phylogeny tree = trees[i]; if (nhx_or_nexus && INTERNAL_NUMBERS_AS_CONFIDENCE) { PhylogenyMethods.transferInternalNodeNamesToConfidence(tree, ""); } String treeTitle = treeFile.getName() + "[" + i + "]"; tree.setName(treeTitle); aptxFrames[i] = createAptxFrame(tree, viewport, treeTitle); } if (Desktop.instance != null) { Desktop.instance.stopLoading(); } return aptxFrames; } public static MainFrame[] createInstancesFromUrl(URL treeUrl, AlignmentViewport viewport) throws FileNotFoundException, IOException, RuntimeException { String treeTitle = treeUrl.getFile(); if (Desktop.instance != null) { Desktop.instance.startLoading(treeTitle); } Phylogeny[] trees = AptxUtil.readPhylogeniesFromUrl(treeUrl, VALIDATE_PHYLOXML_XSD, REPLACE_NHX_UNDERSCORES, INTERNAL_NUMBERS_AS_CONFIDENCE, TAXONOMY_EXTRACTION, MIDPOINT_REROOT); MainFrame[] aptxFrames = new MainFrame[trees.length]; for (int i = 0; i < trees.length; i++) { Phylogeny tree = trees[i]; aptxFrames[i] = createAptxFrame(tree, viewport, treeTitle); } if (Desktop.instance != null) { Desktop.instance.stopLoading(); } return aptxFrames; } /** * Refactored from Forester's UrlTreeReader, this can be more efficient * * @param databaseIndex * @param viewport * @return */ public static MainFrame[] createInstancesFromDb( PhylogeniesWebserviceClient treeDbClient, String identifier, AlignmentViewport viewport) { URL url = null; Phylogeny[] trees = null; if ((identifier != null) && (identifier.trim().length() > 0)) { if (Desktop.instance != null) { Desktop.instance.startLoading(identifier); } identifier = identifier.trim(); if (treeDbClient.isQueryInteger()) { identifier = identifier.replaceAll("^\\D+", ""); int id; try { id = Integer.parseInt(identifier); } catch (final NumberFormatException e) { JvOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager.formatMessage( "error.database_id_has_letters", new String[] { identifier }), MessageManager.getString("label.invalid_url"), JvOptionPane.ERROR_MESSAGE); return new MainFrame[0]; } identifier = id + ""; } boolean exception = false; try { String url_str = treeDbClient.getUrl(); url_str = url_str.replaceFirst( PhylogeniesWebserviceClient.QUERY_PLACEHOLDER, identifier); url = new URL(url_str); PhylogenyParser parser = null; switch (treeDbClient.getReturnFormat()) { case TOL_XML_RESPONSE: parser = new TolParser(); break; case NEXUS: parser = new NexusPhylogeniesParser(); ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true); break; case TREEBASE_TREE: parser = new NexusPhylogeniesParser(); ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true); ((NexusPhylogeniesParser) parser) .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO); break; case TREEBASE_STUDY: parser = new NexusPhylogeniesParser(); ((NexusPhylogeniesParser) parser).setReplaceUnderscores(true); ((NexusPhylogeniesParser) parser) .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO); break; case NH: parser = new NHXParser(); ((NHXParser) parser) .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO); ((NHXParser) parser).setReplaceUnderscores(true); ((NHXParser) parser).setGuessRootedness(true); break; case NH_EXTRACT_TAXONOMY: parser = new NHXParser(); ((NHXParser) parser).setTaxonomyExtraction( NHXParser.TAXONOMY_EXTRACTION.AGGRESSIVE); ((NHXParser) parser).setReplaceUnderscores(false); ((NHXParser) parser).setGuessRootedness(true); break; case PFAM: parser = new NHXParser(); ((NHXParser) parser).setTaxonomyExtraction( NHXParser.TAXONOMY_EXTRACTION.PFAM_STYLE_STRICT); ((NHXParser) parser).setReplaceUnderscores(false); ((NHXParser) parser).setGuessRootedness(true); break; case NHX: parser = new NHXParser(); ((NHXParser) parser) .setTaxonomyExtraction(NHXParser.TAXONOMY_EXTRACTION.NO); ((NHXParser) parser).setReplaceUnderscores(false); ((NHXParser) parser).setGuessRootedness(true); break; case PHYLOXML: parser = PhyloXmlParser.createPhyloXmlParserXsdValidating(); break; default: throw new IllegalArgumentException( "unknown format: " + treeDbClient.getReturnFormat()); } // // if (_main_frame.getMainPanel().getCurrentTreePanel() != null) // { // _main_frame.getMainPanel().getCurrentTreePanel().setWaitCursor(); // } // else // { // _main_frame.getMainPanel().setWaitCursor(); // } trees = ForesterUtil.readPhylogeniesFromUrl(url, parser); } catch (final MalformedURLException e) { exception = true; JvOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager.formatMessage( "exception.unable_to_launch_url", new String[] { url.toString() }), MessageManager.getString("label.invalid_url"), JvOptionPane.ERROR_MESSAGE); System.err.println(e.getLocalizedMessage()); } catch (final IOException e) { exception = true; JvOptionPane.showInternalMessageDialog(Desktop.desktop, "Could not read from " + url + "\n" + e.getLocalizedMessage(), "Failed to read tree from " + treeDbClient.getName() + " for " + identifier, JvOptionPane.ERROR_MESSAGE); System.err.println(e.getLocalizedMessage()); } catch (final NumberFormatException e) { exception = true; JvOptionPane.showInternalMessageDialog(Desktop.desktop, "Could not read from " + url + "\n" + e.getLocalizedMessage(), "Failed to read tree from " + treeDbClient.getName() + " for " + identifier, JvOptionPane.ERROR_MESSAGE); System.err.println(e.getLocalizedMessage()); } catch (final Exception e) { exception = true; e.printStackTrace(); JvOptionPane.showInternalMessageDialog(Desktop.desktop, e.getLocalizedMessage(), "Unexpected Exception", JvOptionPane.ERROR_MESSAGE); System.err.println(e.getLocalizedMessage()); } if ((trees != null) && (trees.length > 0)) { for (final Phylogeny phylogeny : trees) { if (!phylogeny.isEmpty()) { if (treeDbClient.getName().equals(WebserviceUtil.TREE_FAM_NAME)) { phylogeny.setRerootable(false); phylogeny.setRooted(true); } if (treeDbClient.getProcessingInstructions() != null) { try { WebserviceUtil.processInstructions(treeDbClient, phylogeny); } catch (final PhyloXmlDataFormatException e) { JvOptionPane.showInternalMessageDialog(Desktop.desktop, "Error:\n" + e.getLocalizedMessage(), "Error", JvOptionPane.ERROR_MESSAGE); } } if (treeDbClient.getNodeField() != null) { try { PhylogenyMethods.transferNodeNameToField(phylogeny, treeDbClient.getNodeField(), false); } catch (final PhyloXmlDataFormatException e) { JvOptionPane.showInternalMessageDialog(Desktop.desktop, "Error:\n" + e.getLocalizedMessage(), "Error", JvOptionPane.ERROR_MESSAGE); } } phylogeny.setIdentifier( new Identifier(identifier, treeDbClient.getName())); // _main_frame.getJMenuBar().remove(_main_frame.getHelpMenu()); // _main_frame.getMenuBarOfMainFrame() // .add(_main_frame.getHelpMenu()); // _main_frame.getMainPanel().addPhylogenyInNewTab(phylogeny, // _main_frame.getConfiguration(), // new File(url.getFile()).getName(), url.toString()); MainFrame aptxApp = createAptxFrame(phylogeny, viewport, url.getFile()); String my_name_for_file = ""; if (!ForesterUtil.isEmpty(phylogeny.getName())) { my_name_for_file = new String(phylogeny.getName()) .replaceAll(" ", "_"); } else if (phylogeny.getIdentifier() != null) { final StringBuffer sb = new StringBuffer(); if (!ForesterUtil .isEmpty(phylogeny.getIdentifier().getProvider())) { sb.append(phylogeny.getIdentifier().getProvider()); sb.append("_"); } sb.append(phylogeny.getIdentifier().getValue()); my_name_for_file = new String( sb.toString().replaceAll(" ", "_")); } aptxApp.getMainPanel().getCurrentTreePanel() .setTreeFile(new File(my_name_for_file)); AptxUtil.lookAtSomeTreePropertiesForAptxControlSettings( phylogeny, aptxApp.getMainPanel().getControlPanel(), APTX_CONFIG); // _main_frame.getMainPanel().getControlPanel().showWhole(); aptxApp.activateSaveAllIfNeeded(); } } } else if (!exception) // ..what? { JvOptionPane.showMessageDialog(null, ForesterUtil.wordWrap( "Failed to read in tree(s) from [" + url + "]", 80), "Error", JvOptionPane.ERROR_MESSAGE); } if ((trees != null) && (trees.length > 0)) { try { JvOptionPane.showMessageDialog(null, ForesterUtil.wordWrap("Successfully read in " + trees.length + " tree(s) from [" + url + "]", 80), "Success", JvOptionPane.INFORMATION_MESSAGE); } catch (final Exception e) { // Not important if this fails, do nothing. } // _main_frame.getContentPane().repaint(); } } System.gc(); if (Desktop.instance != null) { Desktop.instance.stopLoading(); } return null; } public static MainFrame createAptxFrame( final Phylogeny aptxTree, final AlignmentViewport jalviewAlignport, String treeTitle) { if (APTX_CONFIG == null || APTX_CONFIG.isCouldReadConfigFile() == false) { int keepGoing = JvOptionPane.showConfirmDialog(Desktop.desktop, MessageManager.getString("label.aptx_config_not_found"), MessageManager.formatMessage("label.couldnt_locate", new String[] { "_aptx_jalview_configuration_file" }), JvOptionPane.YES_NO_CANCEL_OPTION); if (keepGoing == JvOptionPane.CANCEL_OPTION || keepGoing == JvOptionPane.CLOSED_OPTION || keepGoing == JvOptionPane.NO_OPTION) { return null; } } MainFrame aptxApp = Archaeopteryx.createApplication(aptxTree, APTX_CONFIG, treeTitle); LoadedTreeSequenceAssociation bindAptxNodes = new LoadedTreeSequenceAssociation( jalviewAlignport.getAlignment().getSequencesArray(), aptxTree); bindAptxNodes.associateLeavesToSequences(); bindNodesToJalviewSequences(aptxApp, jalviewAlignport, bindAptxNodes.getAlignmentWithNodes(), bindAptxNodes.getNodesWithAlignment()); bindTreeViewFrameToJalview(aptxApp); adaptAptxGui(aptxApp); return aptxApp; } public static ExternalTreeViewerBindingI bindNodesToJalviewSequences( final MainFrame aptxApp, final AlignmentViewport jalviewAlignViewport, final Map alignMappedToNodes, final Map nodesMappedToAlign) { JalviewBinding treeBinding = new JalviewBinding(aptxApp, jalviewAlignViewport, alignMappedToNodes, nodesMappedToAlign); activeAptx.put(aptxApp, treeBinding); return treeBinding; } public static MainFrame bindTreeViewFrameToJalview( final MainFrame aptxApp) { int width = 400; int height = 550; aptxApp.setMinimumSize(new Dimension(width, height)); // aptxApp.setFont(Desktop.instance.getFont()); // aptxApp.getMainPanel().setFont(Desktop.instance.getFont()); String frameTitle = MessageManager.getString("label.aptx_title"); File treeFile = aptxApp.getMainPanel().getCurrentTreePanel() .getTreeFile(); if (treeFile != null) { frameTitle += MessageManager.formatMessage("label.aptx_title_append", new String[] { treeFile.getAbsolutePath() }); } Desktop.addInternalFrame(aptxApp, frameTitle, true, width, height, true, true); return aptxApp; } /** * Hides certain redundant Archaeopteryx GUI elements such as the menu items * for reading in trees and adds extra items related to Jalview such as the * tree sorting item. * * * @param aptxFrame */ private static void adaptAptxGui(MainFrame aptxFrame) { JMenuBar frameBar = aptxFrame.getJMenuBar(); for (int i = 0; i < frameBar.getMenuCount();i++) { JMenu menu = frameBar.getMenu(i); if (menu.getText().contains("File")) { // hide all "Read from ..." and "New" menu items and any Separators that // come directly after them Component previousMenuItem = null; for (Component menuItem : menu.getMenuComponents()) { if (previousMenuItem instanceof JMenuItem) { if (((JMenuItem) previousMenuItem).getText().startsWith("Read") || ((JMenuItem) previousMenuItem).getText() .startsWith("New")) { previousMenuItem.setVisible(false); if (menuItem instanceof JSeparator) { menuItem.setVisible(false); } } } previousMenuItem = menuItem; } } else if (menu.getText().contains("Inference")) { menu.setVisible(false); } else if (menu.getText().contains("View")) { menu.addSeparator(); JMenuItem sortByTree = new JMenuItem("Sort alignment by tree"); JMenuItem refreshJalview = new JMenuItem( "Filter alignment to show only currently visible sequences"); refreshJalview.setFont(menu.getFont()); menu.add(sortByTree); menu.add(refreshJalview); sortByTree.setFont(menu.getFont()); sortByTree.setVisible(false); // don't show unless it's actually // possible refreshJalview.addActionListener(activeAptx.get(aptxFrame)); } } aptxFrame.validate(); } public static Map getAllAptxFrames() { return activeAptx; } }