package beast.app.beauti; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.JComponent; import javax.swing.JOptionPane; import beast.core.BEASTInterface; import beast.core.BEASTObject; import beast.core.Description; import beast.core.Input; import beast.core.Input.Validate; import beast.evolution.alignment.Alignment; import beast.math.distributions.MRCAPrior; import beast.util.XMLParser; @Description("Beauti configuration object, used to find Beauti configuration " + "information from Beauti template files.") public class BeautiConfig extends BEASTObject { final public Input<String> inlineInput = new Input<>("inlinePlugins", "comma separated list of inputs that should " + "go inline, e.g. beast.evolution.sitemodel.SiteModel.substModel"); final public Input<String> collapsedInput = new Input<>("collapsedPlugins", "comma separated list of inputs that should " + "go inline, but are initially collapsed, e.g. beast.core.MCMC.logger"); final public Input<String> suppressInputs = new Input<>("suppressPlugins", "comma separated list of inputs that should " + "be suppressed. e.g. beast.core.MCMC.operator"); final public Input<String> inputLabelMapInput = new Input<>("inputLabelMap", "comma separated list of inputs and their " + "display labels separated by a '=', e.g. beast.core.MCMC.logger=Loggers "); // public Input<String> m_hidePanels = new Input<>("hidePanels","comma separated list of panes that should not" + // "be displayed when starting beauti, e.g. TAXON_SETS_PANEL,TIP_DATES_PANEL"); final public Input<String> buttonLabelMapInput = new Input<>("buttonLabelMap", "comma separated list of buttons in dialogs and their " + "display labels separated by a '=', e.g. beast.app.beauti.BeautiInitDlg.>> details=Edit parameters"); final public Input<String> disableMenus = new Input<>("disableMenus", "comma separated list of menus that should " + "not be visible, e.g., View.Show Data Panel,Mode"); final public Input<String> disableButtons = new Input<>("disableButtons", "comma separated list of buttons that should " + "not be visible, e.g., beast.app.beauti.BeautiInitDlg.Analysis template:"); // public Input<String> m_editButtonStatus = new Input<>("editButtonStatus","comma separated list of list-inputs with custom " + // "button status. One of 'none', 'addonly' 'delonly' +, e.g., beast.core.MCMC.operator=addonly"); final public Input<List<BeautiPanelConfig>> panelsInput = new Input<>("panel", "define custom panels and their properties", new ArrayList<>()); final public Input<Boolean> isExpertInput = new Input<>("isExpert", "flag to indicate Beauti should start in expert mode", false); final public Input<BeautiSubTemplate> partitionTemplate = new Input<>("partitiontemplate", "defines template used when creating a partition", Validate.REQUIRED); final public Input<List<BeautiSubTemplate>> subTemplatesInput = new Input<>("subtemplate", "defines subtemplates for creating selected classes", new ArrayList<>()); final public Input<List<BeautiAlignmentProvider>> alignmentProviderInput = new Input<>("alignmentProvider", "defines providers for adding new alignments", new ArrayList<>()); /** * list of inputs for which the input editor should be expanded inline in a dialog * in the format <className>.<inputName>, e.g. beast.evolution.sitemodel.SiteModel.substModel */ public Set<String> inlineBEASTObject = new HashSet<>(); /** * list of inputs for which the input editor should be expanded inline in a dialog but initially collapsed. * e.g. beast.evolution.sitemodel.SiteModel.substModel */ public Set<String> collapsedBEASTObjects = new HashSet<>(); /** * list of inputs that should not be shown in a dialog. Same format as for inlineBEASTObjects* */ public Set<String> suppressBEASTObjects = new HashSet<>(); /** * map that identifies the label to be used for a particular input * */ public HashMap<String, String> inputLabelMap = new HashMap<>(); public HashMap<String, String> buttonLabelMap = new HashMap<>(); // public static HashMap<String, String> g_sEditButtonStatus = new HashMap<>(); // public static Set<String> g_sHidePanels = new HashSet<>(); public Set<String> disabledMenus = new HashSet<>(); public Set<String> disabledButtons = new HashSet<>(); public List<BeautiPanelConfig> panels = new ArrayList<>(); public List<BeautiSubTemplate> subTemplates; public List<BeautiAlignmentProvider> alignmentProvider; public BeautiSubTemplate hyperPriorTemplate = null; @Override public void initAndValidate() { parseSet(inlineInput.get(), null, inlineBEASTObject); parseSet(collapsedInput.get(), null, collapsedBEASTObjects); inlineBEASTObject.addAll(collapsedBEASTObjects); // parseSet(m_hidePanels.get(), "TAXON_SETS_PANEL,TIP_DATES_PANEL,PRIORS_PANEL,OPERATORS_PANEL", g_sHidePanels); parseSet(suppressInputs.get(), null, suppressBEASTObjects); parseSet(disableMenus.get(), null, disabledMenus); parseSet(disableButtons.get(), null, disabledButtons); parseMap(inputLabelMapInput.get(), inputLabelMap); parseMap(buttonLabelMapInput.get(), buttonLabelMap); // parseMap(m_editButtonStatus.get(), g_sEditButtonStatus); for (BeautiPanelConfig panel : panelsInput.get()) { panels.add(panel); // check for duplicates for (BeautiPanelConfig panel2 : panels) { if (panel2.nameInput.get().equals(panel.nameInput.get()) && panel2 != panel) { panels.remove(panels.size() - 1); break; } } } //InputEditor.setExpertMode(isExpertInput.get()); subTemplates = subTemplatesInput.get(); alignmentProvider = alignmentProviderInput.get(); try { XMLParser parser = new XMLParser(); hyperPriorTemplate = (BeautiSubTemplate) parser.parseBareFragment(HYPER_PRIOR_XML, true); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } final static String HYPER_PRIOR_XML = " <beast version='2.0'\n" + " namespace='beast.app.beauti:beast.core:beast.evolution.branchratemodel:beast.evolution.speciation:beast.evolution.tree.coalescent:beast.core.util:beast.evolution.nuc:beast.evolution.operators:beast.evolution.sitemodel:beast.evolution.substitutionmodel:beast.evolution.likelihood:beast.evolution:beast.math.distributions'>\n" + " <!-- Parameter Hyper Prior -->\n" + " <subtemplate spec='beast.app.beauti.BeautiSubTemplate' id='HyperPrior' class='beast.math.distributions.Prior' mainid='HyperPrior.$(n)'>\n" + " <![CDATA[\n" + " <beastObject id='HyperPrior.$(n)' spec='Prior' x='@parameter.$(n)'>\n" + " <distr spec='OneOnX'/>\n" + " </beastObject>\n" + "\n" + " <beastObject id='hyperScaler.$(n)' spec='ScaleOperator' scaleFactor='0.5' weight='0.1' parameter='@parameter.$(n)'/>\n" + " ]]>\n" + " <connect spec='beast.app.beauti.BeautiConnector' srcID='parameter.$(n)' targetID='state' inputName='stateNode' if='inposterior(parameter.$(n)) and parameter.$(n)/estimate=true'/>\n" + "\n" + " <connect spec='beast.app.beauti.BeautiConnector' srcID='hyperScaler.$(n)' targetID='mcmc' inputName='operator' if='inposterior(parameter.$(n)) and parameter.$(n)/estimate=true'>Scale hyper parameter $(n)</connect>\n" + "\n" + " <connect spec='beast.app.beauti.BeautiConnector' srcID='parameter.$(n)' targetID='tracelog' inputName='log' if='inposterior(parameter.$(n)) and parameter.$(n)/estimate=true'/>\n" + " <connect spec='beast.app.beauti.BeautiConnector' srcID='HyperPrior.$(n)' targetID='tracelog' inputName='log' if='inposterior(parameter.$(n)) and parameter.$(n)/estimate=true'/>\n" + "\n" + " <connect spec='beast.app.beauti.BeautiConnector' srcID='HyperPrior.$(n)' targetID='prior' inputName='distribution' if='inposterior(parameter.$(n)) and parameter.$(n)/estimate=true'>Hyper prior for parameter $(n)</connect>\n" + " </subtemplate>\n" + " </beast>\n"; public void setDoc(BeautiDoc doc) { partitionTemplate.get().setDoc(doc); for (BeautiSubTemplate sub : subTemplates) { sub.setDoc(doc); } doc.setExpertMode(isExpertInput.get()); hyperPriorTemplate.doc = doc; } public void clear() { inlineBEASTObject = new HashSet<>(); collapsedBEASTObjects = new HashSet<>(); suppressBEASTObjects = new HashSet<>(); inputLabelMap = new HashMap<>(); buttonLabelMap = new HashMap<>(); disabledMenus = new HashSet<>(); disabledButtons = new HashSet<>(); panels = new ArrayList<>(); } /** * if fileArray == null, then use getAlignments(doc) * @param doc * @param parent * @param fileArray * @return a list of alignments based on the user selected alignment provider */ public List<BEASTInterface> selectAlignments(BeautiDoc doc, JComponent parent, File[] fileArray) { List<BeautiAlignmentProvider> providers = alignmentProvider; BeautiAlignmentProvider selectedProvider = null; if (providers.size() == 1) { selectedProvider = providers.get(0); } else { selectedProvider = (BeautiAlignmentProvider) JOptionPane.showInputDialog(parent, "Select what to add", "Add partition", JOptionPane.QUESTION_MESSAGE, null, providers.toArray(), providers.get(0)); if (selectedProvider == null) { return null; } } List<BEASTInterface> beastObjects = selectedProvider.getAlignments(doc, fileArray); // create taxon sets, if any if (beastObjects != null) { for (BEASTInterface o : beastObjects) { if (o instanceof Alignment) { try { BeautiDoc.createTaxonSet((Alignment) o, doc); } catch(Exception e) { e.printStackTrace(); } } } } doc.connectModel(); if (beastObjects != null) { for (BEASTInterface o : beastObjects) { if (o instanceof MRCAPrior) { doc.addMRCAPrior((MRCAPrior) o); } } } return beastObjects; } // selectAlignments public List<BeautiSubTemplate> getInputCandidates(BEASTInterface beastObject, Input<?> input, Class<?> type) { List<BeautiSubTemplate> candidates = new ArrayList<>(); for (BeautiSubTemplate template : subTemplates) { if (type.isAssignableFrom(template._class)) { try { if (input.canSetValue(template.instance, beastObject)) { candidates.add(template); } } catch (Exception e) { // ignore: cannot set value } } } return candidates; } private void parseMap(String str, HashMap<String, String> stringMap) { if (str != null) { for (String str2 : str.split(",")) { String[] strs = str2.split("="); stringMap.put(normalize(strs[0]), normalize(strs.length == 1 ? "" : strs[1])); } } } private void parseSet(String str, String defaultValue, Set<String> stringSet) { if (str == null) { str = defaultValue; } if (str != null) { for (String str2 : str.split(",")) { stringSet.add(normalize(str2)); } } } // remove leading and tailing spaces String normalize(String str) { int i = 0; int n = str.length(); while (i < n && Character.isWhitespace(str.charAt(i))) { i++; } while (n > 0 && Character.isWhitespace(str.charAt(n - 1))) { n--; } return str.substring(i, n); } public String getButtonLabel(String className, String str) { if (buttonLabelMap.containsKey(className + "." + str)) { return buttonLabelMap.get(className + "." + str); } return str; } public String getButtonLabel(Object o, String str) { if (buttonLabelMap.containsKey(o.getClass().getName() + "." + str)) { return buttonLabelMap.get(o.getClass().getName() + "." + str); } return str; } public String getInputLabel(BEASTInterface beastObject, String name) { if (inputLabelMap.containsKey(beastObject.getClass().getName() + "." + name)) { name = inputLabelMap.get(beastObject.getClass().getName() + "." + name); } return name; } public boolean menuIsInvisible(String menuName) { return disabledMenus.contains(menuName); } static BeautiSubTemplate NULL_TEMPLATE = new BeautiSubTemplate(); public static BeautiSubTemplate getNullTemplate(BeautiDoc doc) { NULL_TEMPLATE.setID("[none]"); NULL_TEMPLATE._class = Object.class; NULL_TEMPLATE.doc = doc; return NULL_TEMPLATE; } // public static boolean hasDeleteButton(String fullInputName) { // if (!g_sEditButtonStatus.containsKey(fullInputName)) { // return true; // } // String status = g_sEditButtonStatus.get(fullInputName); // if (status.equals("none") || status.equals("onlyadd")) { // return false; // } // return true; // } // public static boolean hasAddButton(String fullInputName) { // if (!g_sEditButtonStatus.containsKey(fullInputName)) { // return true; // } // String status = g_sEditButtonStatus.get(fullInputName); // if (status.equals("none") || status.equals("onlydel")) { // return false; // } // return true; // } } // class BeautiConfig