package figtree.webui; import java.awt.BasicStroke; import java.awt.Font; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.List; import jebl.evolution.io.ImportException; import jebl.evolution.io.NewickImporter; import jebl.evolution.trees.RootedTree; import jebl.evolution.trees.SortedRootedTree; import jebl.evolution.trees.TransformedRootedTree; import jebl.evolution.trees.Tree; import eu.webtoolkit.jwt.AlignmentFlag; import eu.webtoolkit.jwt.Signal; import eu.webtoolkit.jwt.Signal1.Listener; import eu.webtoolkit.jwt.WApplication; import eu.webtoolkit.jwt.WBoxLayout; import eu.webtoolkit.jwt.WCheckBox; import eu.webtoolkit.jwt.WComboBox; import eu.webtoolkit.jwt.WContainerWidget; import eu.webtoolkit.jwt.WEnvironment; import eu.webtoolkit.jwt.WFormWidget; import eu.webtoolkit.jwt.WHBoxLayout; import eu.webtoolkit.jwt.WIntValidator; import eu.webtoolkit.jwt.WLabel; import eu.webtoolkit.jwt.WLength; import eu.webtoolkit.jwt.WSpinBox; import eu.webtoolkit.jwt.WVBoxLayout; import figtree.application.FigTreeNexusImporter; import figtree.panel.SimpleLabelPainter; import figtree.treeviewer.TreePane; import figtree.treeviewer.treelayouts.PolarTreeLayout; import figtree.treeviewer.treelayouts.RadialTreeLayout; import figtree.treeviewer.treelayouts.RectilinearTreeLayout; public class FigTreeWebApplication extends WApplication { private TreeWidget treeWidget; private SimpleLabelPainter tipPainter; private SimpleLabelPainter nodePainter; private SimpleLabelPainter branchPainter; public FigTreeWebApplication(WEnvironment env) { super(env); setTitle("FigTree"); useStyleSheet("figtree.css"); WVBoxLayout layout = new WVBoxLayout(getRoot()); FileUploadWidget uploadWidget = new FileUploadWidget(); uploadWidget.fileUploaded().addListener(this, new Listener<String>() { @Override public void trigger(String path) { readFile(path); } }); layout.addWidget(uploadWidget); layout.addWidget(treeWidget = new TreeWidget(), 1); treeWidget.setStyleClass("tree"); readFile("/etc/figtree/example.tree"); treeWidget.getTreePane().setTipLabelPainter (tipPainter = new SimpleLabelPainter(SimpleLabelPainter.PainterIntent.TIP)); treeWidget.getTreePane().setNodeLabelPainter (nodePainter = new SimpleLabelPainter(SimpleLabelPainter.PainterIntent.NODE)); treeWidget.getTreePane().setBranchLabelPainter (branchPainter = new SimpleLabelPainter(SimpleLabelPainter.PainterIntent.BRANCH)); createControls(layout); } private void readFile(String path) { try { FileReader reader = new FileReader(path); readData(reader, true); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void createControls(WVBoxLayout layout) { WHBoxLayout controlsLayout = new WHBoxLayout(); layout.addLayout(controlsLayout, 0, AlignmentFlag.AlignJustify, AlignmentFlag.AlignTop); WVBoxLayout column = new WVBoxLayout(); controlsLayout.addLayout(column, 0, AlignmentFlag.AlignJustify, AlignmentFlag.AlignMiddle); WComboBox box = new WComboBox(); addField(column, "Layout: ", box, AlignmentFlag.AlignLeft); box.addItem("Rectilinear"); box.addItem("Radial"); box.addItem("Polar"); box.activated().addListener(this, new Listener<Integer>() { @Override public void trigger(Integer choice) { switch (choice) { case 0: treeWidget.getTreePane().setTreeLayout(new RectilinearTreeLayout()); break; case 1: treeWidget.getTreePane().setTreeLayout(new RadialTreeLayout()); break; case 2: treeWidget.getTreePane().setTreeLayout(new PolarTreeLayout()); } } }); column = new WVBoxLayout(); controlsLayout.addLayout(column, 0, AlignmentFlag.AlignJustify, AlignmentFlag.AlignMiddle); WSpinBox spinBox = new WSpinBox(); spinBox.setValue(2); spinBox.setRange(0, 48); spinBox.setMaxLength(3); addField(column, "Line Weight: ", spinBox, AlignmentFlag.AlignRight); spinBox.valueChanged().addListener(this, new Listener<Double>() { @Override public void trigger(Double value) { treeWidget.getTreePane().setBranchStroke(new BasicStroke(value.floatValue())); } }); spinBox.valueChanged().trigger(spinBox.getValue()); spinBox = new WSpinBox(); spinBox.setValue(6); spinBox.setRange(0, 48); spinBox.setValidator(new WIntValidator(0, 48)); spinBox.setMaxLength(3); addField(column, "Font Size: ", spinBox, AlignmentFlag.AlignRight); spinBox.valueChanged().addListener(this, new Listener<Double>() { @Override public void trigger(Double value) { tipPainter.setFont(new Font("sansserif", Font.PLAIN, value.intValue())); } }); spinBox.valueChanged().trigger(spinBox.getValue()); column = new WVBoxLayout(); controlsLayout.addLayout(column, 0, AlignmentFlag.AlignJustify, AlignmentFlag.AlignMiddle); final WCheckBox midPointCheck = new WCheckBox("Midpoint root"); midPointCheck.setChecked(false); addField(column, null, midPointCheck, AlignmentFlag.AlignRight); midPointCheck.changed().addListener(this, new Signal.Listener() { @Override public void trigger() { if (midPointCheck.isChecked()) { treeWidget.getTreePane().setRootingOn(true); treeWidget.getTreePane().setRootingType(TreePane.RootingType.MID_POINT); } else { treeWidget.getTreePane().setRootingOn(false); treeWidget.getTreePane().setRootingType(TreePane.RootingType.USER_ROOTING); } } }); final WComboBox orderCombo = new WComboBox(); orderCombo.addItem("Off"); orderCombo.addItem("Increasing"); orderCombo.addItem("Decreasing"); orderCombo.resize(new WLength(120), WLength.Auto); addField(column, "Order: ", orderCombo, AlignmentFlag.AlignRight); orderCombo.changed().addListener(this, new Signal.Listener() { @Override public void trigger() { if (orderCombo.getCurrentIndex() == 0) { treeWidget.getTreePane().setOrderBranchesOn(false); } else { treeWidget.getTreePane().setOrderBranchesOn(true); treeWidget.getTreePane().setBranchOrdering(SortedRootedTree.BranchOrdering.values()[orderCombo.getCurrentIndex() - 1]); } } }); final WComboBox transformCombo = new WComboBox(); transformCombo.addItem("Off"); transformCombo.addItem(TransformedRootedTree.Transform.CLADOGRAM.toString()); transformCombo.addItem(TransformedRootedTree.Transform.PROPORTIONAL.toString()); transformCombo.addItem(TransformedRootedTree.Transform.EQUAL_LENGTHS.toString()); transformCombo.resize(new WLength(120), WLength.Auto); addField(column, "Transform: ", transformCombo, AlignmentFlag.AlignRight); transformCombo.changed().addListener(this, new Signal.Listener() { @Override public void trigger() { if (transformCombo.getCurrentIndex() == 0) { treeWidget.getTreePane().setTransformBranchesOn(false); } else { treeWidget.getTreePane().setTransformBranchesOn(true); treeWidget.getTreePane().setBranchTransform(TransformedRootedTree.Transform.values()[transformCombo.getCurrentIndex() - 1]); } } }); column = new WVBoxLayout(); controlsLayout.addLayout(column, 0, AlignmentFlag.AlignJustify, AlignmentFlag.AlignMiddle); WComboBox combo = addLabelCombo(column, tipPainter, "Tips: "); combo.setCurrentIndex(1); combo.changed().trigger(); addLabelCombo(column, nodePainter, "Nodes: "); addLabelCombo(column, branchPainter, "Branches: "); } private WComboBox addLabelCombo(WVBoxLayout column, final SimpleLabelPainter labelPainter, String title) { labelPainter.setNumberFormat(new DecimalFormat("#.####")); labelPainter.setFont(new Font("sansserif", Font.PLAIN, 8)); String[] attributes = labelPainter.getAttributes(); final WComboBox displayAttributeCombo = new WComboBox(); displayAttributeCombo.addItem("None"); for (String attr : attributes) { displayAttributeCombo.addItem(attr); } addField(column, title, displayAttributeCombo, AlignmentFlag.AlignRight); displayAttributeCombo.changed().addListener(this, new Signal.Listener() { @Override public void trigger() { String attribute = (String)displayAttributeCombo.getCurrentText().toString(); if (attribute.equals("none")) { labelPainter.setVisible(false); } else { labelPainter.setDisplayAttribute(attribute); labelPainter.setVisible(true); } } }); displayAttributeCombo.changed().trigger(); return displayAttributeCombo; } private void addField(WBoxLayout controlsLayout, String label, WFormWidget widget, AlignmentFlag alignment) { WContainerWidget w = new WContainerWidget(); if (label != null) { WLabel l; w.addWidget(l = new WLabel(label)); l.setBuddy(widget); } w.addWidget(widget); controlsLayout.addWidget(w, 0, alignment, AlignmentFlag.AlignTop); } protected boolean readData(Reader reader, boolean isNexus) throws IOException { List<Tree> trees = new ArrayList<Tree>(); try { if (isNexus) { FigTreeNexusImporter importer = new FigTreeNexusImporter(reader); while (importer.hasTree()) { Tree tree = importer.importNextTree(); trees.add(tree); } } else { NewickImporter importer = new NewickImporter(reader, true); while (importer.hasTree()) { Tree tree = importer.importNextTree(); trees.add(tree); } } if (trees.size() == 0) { throw new ImportException("This file contained no trees."); } treeWidget.getTreePane().setTree((RootedTree) trees.get(0)); } catch (ImportException ie) { // FIXME return false; } return true; } }