package beast.app.beauti; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JOptionPane; import beast.app.draw.BEASTObjectPanel; import beast.app.draw.InputEditor; import beast.app.draw.ListInputEditor; import beast.app.draw.SmallButton; import beast.core.BEASTInterface; import beast.core.Distribution; import beast.core.Input; import beast.core.Logger; import beast.core.State; import beast.core.StateNode; import beast.core.parameter.RealParameter; import beast.core.util.Log; import beast.evolution.alignment.Taxon; import beast.evolution.alignment.TaxonSet; import beast.evolution.tree.Tree; import beast.evolution.tree.TreeDistribution; import beast.evolution.tree.TreeInterface; import beast.math.distributions.MRCAPrior; import beast.math.distributions.OneOnX; import beast.math.distributions.Prior; import beast.util.AddOnManager; public class PriorListInputEditor extends ListInputEditor { private static final long serialVersionUID = 1L; List<JButton> rangeButtons; List<JButton> taxonButtons; public PriorListInputEditor(BeautiDoc doc) { super(doc); } @Override public Class<?> type() { return List.class; } @Override public Class<?> baseType() { return Distribution.class; } @Override public void init(Input<?> input, BEASTInterface beastObject, int itemNr, ExpandOption isExpandOption, boolean addButtons) { List<?> list = (List<?>) input.get(); Collections.sort(list, (Object o1, Object o2) -> { if (o1 instanceof BEASTInterface && o2 instanceof BEASTInterface) { String d1 = ((BEASTInterface)o1).getID(); String id2 = ((BEASTInterface)o2).getID(); // first the tree priors if (o1 instanceof TreeDistribution) { if (o2 instanceof TreeDistribution) { TreeInterface tree1 = ((TreeDistribution)o1).treeInput.get(); if (tree1 == null) { tree1 = ((TreeDistribution)o1).treeIntervalsInput.get().treeInput.get(); } TreeInterface tree2 = ((TreeDistribution)o2).treeInput.get(); if (tree2 == null) { tree2 = ((TreeDistribution)o2).treeIntervalsInput.get().treeInput.get(); } return d1.compareTo(id2); } else { return -1; } } else if (o1 instanceof MRCAPrior) { // last MRCA priors if (o2 instanceof MRCAPrior) { return d1.compareTo(id2); } else { return 1; } } else { if (o2 instanceof TreeDistribution) { return 1; } if (o2 instanceof MRCAPrior) { return -1; } if (o1 instanceof Prior) { d1 = ((Prior) o1).getParameterName(); } if (o2 instanceof Prior) { id2 = ((Prior) o2).getParameterName(); } return d1.compareTo(id2); } } return 0; } ); rangeButtons = new ArrayList<>(); taxonButtons = new ArrayList<>(); //m_buttonStatus = ButtonStatus.NONE; super.init(input, beastObject, itemNr, isExpandOption, addButtons); if (beastObject instanceof BeautiPanelConfig) { BeautiPanelConfig config = (BeautiPanelConfig) beastObject; if (config.parentBEASTObjects != null && config.parentBEASTObjects.size() > 0 && config.parentBEASTObjects.get(0).getID().equals("speciescoalescent")) { m_buttonStatus = ButtonStatus.NONE; } } if (m_buttonStatus == ButtonStatus.ALL || m_buttonStatus == ButtonStatus.ADD_ONLY) { addButton = new SmallButton("+ Add Prior", true); addButton.setName("addItem"); addButton.setToolTipText("Add new prior (like an MRCA-prior) to the list of priors"); addButton.addActionListener(e -> { addItem(); }); buttonBox.add(addButton); buttonBox.add(Box.createHorizontalGlue()); } } /** * add components to box that are specific for the beastObject. * By default, this just inserts a label with the beastObject ID * * @param itemBox box to add components to * @param beastObject beastObject to add */ @Override protected InputEditor addPluginItem(Box itemBox, BEASTInterface beastObject) { try { int listItemNr = ((List<?>) m_input.get()).indexOf(beastObject); InputEditor editor = doc.getInputEditorFactory().createInputEditor(m_input, listItemNr, beastObject, false, ExpandOption.FALSE, ButtonStatus.NONE, null, doc); itemBox.add((Component) editor); return editor; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return this; } String paramToString(RealParameter p) { Double lower = p.lowerValueInput.get(); Double upper = p.upperValueInput.get(); return "initial = " + p.valuesInput.get() + " [" + (lower == null ? "-\u221E" : lower + "") + "," + (upper == null ? "\u221E" : upper + "") + "]"; } Set<Taxon> getTaxonCandidates(MRCAPrior prior) { Set<Taxon> candidates = new HashSet<>(); Tree tree = prior.treeInput.get(); String [] taxa = null; if (tree.m_taxonset.get() != null) { try { TaxonSet set = tree.m_taxonset.get(); set.initAndValidate(); taxa = set.asStringList().toArray(new String[0]); } catch (Exception e) { taxa = prior.treeInput.get().getTaxaNames(); } } else { taxa = prior.treeInput.get().getTaxaNames(); } for (String taxon : taxa) { candidates.add(doc.getTaxon(taxon)); } return candidates; } /** * class to deal with toggling monophyletic flag on an MRCAPrior * */ class MRCAPriorActionListener implements ActionListener { MRCAPrior m_prior; MRCAPriorActionListener(MRCAPrior prior) { m_prior = prior; } @Override public void actionPerformed(ActionEvent e) { try { m_prior.isMonophyleticInput.setValue(((JCheckBox) e.getSource()).isSelected(), m_prior); refreshPanel(); } catch (Exception ex) { Log.err.println("PriorListInputEditor " + ex.getMessage()); } } } @Override protected void addItem() { super.addItem(); sync(); refreshPanel(); } // addItem List<PriorProvider> priorProviders; private void initProviders() { priorProviders = new ArrayList<>(); priorProviders.add(new MRCAPriorProvider()); // build up list of data types List<String> importerClasses = AddOnManager.find(PriorProvider.class, new String[]{"beast.app"}); for (String _class: importerClasses) { try { if (!_class.startsWith(this.getClass().getName())) { PriorProvider priorProvider = (PriorProvider) Class.forName(_class).newInstance(); priorProviders.add(priorProvider); } } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } @Override protected List<BEASTInterface> pluginSelector(Input<?> input, BEASTInterface parent, List<String> tabooList) { if (priorProviders == null) { initProviders(); } PriorProvider priorProvider = priorProviders.get(0); if (priorProviders.size() > 1) { // let user choose a PriorProvider List<String> descriptions = new ArrayList<>(); List<PriorProvider> availableProviders = new ArrayList<>(); for (PriorProvider i : priorProviders) { if (i.canProvidePrior(doc)) { descriptions.add(i.getDescription()); availableProviders.add(i); } } String option = (String)JOptionPane.showInputDialog(null, "Which prior do you want to add", "Option", JOptionPane.WARNING_MESSAGE, null, descriptions.toArray(), descriptions.get(0)); if (option == null) { return null; } int i = descriptions.indexOf(option); priorProvider = availableProviders.get(i); } List<BEASTInterface> selectedPlugins = new ArrayList<>(); List<Distribution> distrs = priorProvider.createDistribution(doc); if (distrs == null) { return null; } for (Distribution distr : distrs) { selectedPlugins.add(distr); } return selectedPlugins; } class MRCAPriorProvider implements PriorProvider { @Override public List<Distribution> createDistribution(BeautiDoc doc) { MRCAPrior prior = new MRCAPrior(); try { List<Tree> trees = new ArrayList<>(); getDoc().scrubAll(true, false); State state = (State) doc.pluginmap.get("state"); for (StateNode node : state.stateNodeInput.get()) { if (node instanceof Tree) { // && ((Tree) node).m_initial.get() != null) { trees.add((Tree) node); } } int treeIndex = 0; if (trees.size() > 1) { String[] treeIDs = new String[trees.size()]; for (int j = 0; j < treeIDs.length; j++) { treeIDs[j] = trees.get(j).getID(); } treeIndex = JOptionPane.showOptionDialog(null, "Select a tree", "MRCA selector", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, treeIDs, trees.get(0)); } if (treeIndex < 0) { return null; } prior.treeInput.setValue(trees.get(treeIndex), prior); TaxonSet taxonSet = new TaxonSet(); TaxonSetDialog dlg = new TaxonSetDialog(taxonSet, getTaxonCandidates(prior), doc); if (!dlg.showDialog() || dlg.taxonSet.getID() == null || dlg.taxonSet.getID().trim().equals("")) { return null; } taxonSet = dlg.taxonSet; if (taxonSet.taxonsetInput.get().size() == 0) { JOptionPane.showMessageDialog(doc.beauti, "At least one taxon should be included in the taxon set", "Error specifying taxon set", JOptionPane.ERROR_MESSAGE); return null; } int i = 1; String id = taxonSet.getID(); while (doc.pluginmap.containsKey(taxonSet.getID()) && doc.pluginmap.get(taxonSet.getID()) != taxonSet) { taxonSet.setID(id + i); i++; } BEASTObjectPanel.addPluginToMap(taxonSet, doc); prior.taxonsetInput.setValue(taxonSet, prior); prior.setID(taxonSet.getID() + ".prior"); // this sets up the type prior.distInput.setValue(new OneOnX(), prior); // this removes the parametric distribution prior.distInput.setValue(null, prior); Logger logger = (Logger) doc.pluginmap.get("tracelog"); logger.loggersInput.setValue(prior, logger); } catch (Exception e) { // TODO: handle exception } List<Distribution> selectedPlugins = new ArrayList<>(); selectedPlugins.add(prior); g_collapsedIDs.add(prior.getID()); return selectedPlugins; } @Override public String getDescription() { return "MRCA prior"; } } }