diff -Nru figtree-1.4.2+dfsg/build.xml figtree-1.4.3+dfsg/build.xml --- figtree-1.4.2+dfsg/build.xml 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/build.xml 2016-10-04 14:24:27.000000000 +0000 @@ -12,6 +12,7 @@ + @@ -60,17 +61,27 @@ + + + + + + + + - - - - + + - + @@ -91,7 +102,8 @@ - + + @@ -101,7 +113,6 @@ - @@ -121,9 +132,11 @@ classpath="${launch4j.dir}/launch4j.jar :${launch4j.dir}/lib/xstream.jar" /> + @@ -131,9 +144,9 @@ @@ -156,9 +169,11 @@ + @@ -170,33 +185,36 @@ - - + + - + - - - + + + - + - @@ -215,13 +233,15 @@ + + diff -Nru figtree-1.4.2+dfsg/debian/changelog figtree-1.4.3+dfsg/debian/changelog --- figtree-1.4.2+dfsg/debian/changelog 2015-12-08 10:12:33.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/changelog 2017-07-14 12:12:26.000000000 +0000 @@ -1,3 +1,19 @@ +figtree (1.4.3+dfsg-1) unstable; urgency=medium + + * Team upload. + + [ Fabian Klötzl ] + * Adapt d/watch and d/copyright for new upstream release + * Import upstream version 1.4.3. + * add patch for wrapper to support spaces in paths + * Standards Version: 4.0.0 (tiny changes needed) + * debhelper 10 + + [ Andreas Tille ] + * cme fix dpkg-control + + -- Fabian Klötzl Fri, 14 Jul 2017 14:12:26 +0200 + figtree (1.4.2+dfsg-2) unstable; urgency=medium * Adjust versioned depends from libjam-java diff -Nru figtree-1.4.2+dfsg/debian/compat figtree-1.4.3+dfsg/debian/compat --- figtree-1.4.2+dfsg/debian/compat 2015-12-08 10:12:33.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/compat 2017-07-14 12:12:26.000000000 +0000 @@ -1 +1 @@ -9 +10 diff -Nru figtree-1.4.2+dfsg/debian/control figtree-1.4.3+dfsg/debian/control --- figtree-1.4.2+dfsg/debian/control 2015-12-08 10:12:33.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/control 2017-07-14 12:12:26.000000000 +0000 @@ -4,7 +4,7 @@ Olivier Sallou Section: science Priority: optional -Build-Depends: debhelper (>= 9), +Build-Depends: debhelper (>= 10), javahelper, default-jdk, ant, @@ -20,9 +20,9 @@ libfreehep-graphicsio-svg-java, libfreehep-graphicsio-emf-java, libitext5-java -Standards-Version: 3.9.6 +Standards-Version: 4.0.0 Vcs-Browser: https://anonscm.debian.org/cgit/debian-med/figtree.git -Vcs-Git: git://anonscm.debian.org/debian-med/figtree.git +Vcs-Git: https://anonscm.debian.org/git/debian-med/figtree.git Homepage: http://tree.bio.ed.ac.uk/software/figtree/ Package: figtree diff -Nru figtree-1.4.2+dfsg/debian/copyright figtree-1.4.3+dfsg/debian/copyright --- figtree-1.4.2+dfsg/debian/copyright 2015-12-08 10:12:33.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/copyright 2017-07-14 12:12:26.000000000 +0000 @@ -1,11 +1,12 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: FigTree Upstream-Contact: Andrew Rambaut Source: https://github.com/rambaut/figtree Files-Excluded: */*.jar */*.jnilib release/Windows - release/Mac + release/Mac + packaging_tools Files: * Copyright: © 2005-2011 Andrew Rambaut diff -Nru figtree-1.4.2+dfsg/debian/patches/build_figtree_gui_only.patch figtree-1.4.3+dfsg/debian/patches/build_figtree_gui_only.patch --- figtree-1.4.2+dfsg/debian/patches/build_figtree_gui_only.patch 2015-12-08 10:12:33.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/patches/build_figtree_gui_only.patch 2017-07-14 12:12:26.000000000 +0000 @@ -1,23 +1,26 @@ Author: Andreas Tille Date: Mon, 07 Feb 2011 12:02:43 +0100 +Author: Fabian Klötzl +Last-Date: 2017-07-14 Description: Do not build targets figtree-pdf.jar and figtree.war --- a/build.xml +++ b/build.xml -@@ -60,35 +60,6 @@ +@@ -70,36 +70,6 @@ + - +- - -- -- -- -- +- +- - - -- - - - +- - - @@ -38,4 +41,4 @@ - - + diff -Nru figtree-1.4.2+dfsg/debian/patches/fix_classpath_in_build_xml.patch figtree-1.4.3+dfsg/debian/patches/fix_classpath_in_build_xml.patch --- figtree-1.4.2+dfsg/debian/patches/fix_classpath_in_build_xml.patch 2015-12-08 10:12:33.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/patches/fix_classpath_in_build_xml.patch 2017-07-14 12:12:26.000000000 +0000 @@ -11,9 +11,9 @@ + + - -@@ -35,7 +36,7 @@ +@@ -36,7 +37,7 @@ -@@ -48,11 +49,13 @@ +@@ -49,11 +50,13 @@ diff -Nru figtree-1.4.2+dfsg/debian/patches/fix_handling_of_paths_with_spaces_in_wrapper.patch figtree-1.4.3+dfsg/debian/patches/fix_handling_of_paths_with_spaces_in_wrapper.patch --- figtree-1.4.2+dfsg/debian/patches/fix_handling_of_paths_with_spaces_in_wrapper.patch 1970-01-01 00:00:00.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/patches/fix_handling_of_paths_with_spaces_in_wrapper.patch 2017-07-14 12:12:26.000000000 +0000 @@ -0,0 +1,18 @@ +From: Fabian Klötzl +Date: Fri, 14 Jul 2017 11:59:41 +0200 +Description: fix handling of paths with spaces in wrapper + +--- + release/Linux/scripts/figtree | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/release/Linux/scripts/figtree b/release/Linux/scripts/figtree +index f1ec842..6dd9b68 100755 +--- a/release/Linux/scripts/figtree ++++ b/release/Linux/scripts/figtree +@@ -1,4 +1,4 @@ + #!/bin/sh + +-java -Xms64m -Xmx512m -jar lib/figtree.jar $* ++java -Xms64m -Xmx512m -jar lib/figtree.jar "$@" + diff -Nru figtree-1.4.2+dfsg/debian/patches/fix_itext_api_change.patch figtree-1.4.3+dfsg/debian/patches/fix_itext_api_change.patch --- figtree-1.4.2+dfsg/debian/patches/fix_itext_api_change.patch 2015-12-08 10:12:33.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/patches/fix_itext_api_change.patch 2017-07-14 12:12:26.000000000 +0000 @@ -6,7 +6,7 @@ Forwarded: no --- a/src/figtree/application/FigTreeFrame.java +++ b/src/figtree/application/FigTreeFrame.java -@@ -22,7 +22,7 @@ package figtree.application; +@@ -22,7 +22,7 @@ import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; diff -Nru figtree-1.4.2+dfsg/debian/patches/fix_jebl.patch figtree-1.4.3+dfsg/debian/patches/fix_jebl.patch --- figtree-1.4.2+dfsg/debian/patches/fix_jebl.patch 2015-12-08 10:12:33.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/patches/fix_jebl.patch 2017-07-14 12:12:26.000000000 +0000 @@ -4,7 +4,7 @@ Last-Updated: 2015-08-12 --- a/src/figtree/application/FigTreeFrame.java +++ b/src/figtree/application/FigTreeFrame.java -@@ -930,7 +930,7 @@ public class FigTreeFrame extends Docume +@@ -932,7 +932,7 @@ FileWriter writer = new FileWriter(file); FigTreeNexusExporter exporter = new FigTreeNexusExporter(writer, true); diff -Nru figtree-1.4.2+dfsg/debian/patches/ignore_quaqua.patch figtree-1.4.3+dfsg/debian/patches/ignore_quaqua.patch --- figtree-1.4.2+dfsg/debian/patches/ignore_quaqua.patch 2015-12-08 10:12:33.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/patches/ignore_quaqua.patch 2017-07-14 12:12:26.000000000 +0000 @@ -8,15 +8,15 @@ --- a/src/figtree/application/FigTreeApplication.java +++ b/src/figtree/application/FigTreeApplication.java -@@ -51,7 +51,6 @@ import jebl.evolution.trees.Tree; +@@ -56,7 +56,6 @@ import javax.imageio.ImageIO; import javax.swing.*; -import ch.randelshofer.quaqua.QuaquaManager; - - /** - * Application class for FigTree including main() method for invoking it. -@@ -336,40 +335,6 @@ public class FigTreeApplication extends + import org.apache.batik.dom.GenericDOMImplementation; + import org.apache.batik.svggen.SVGGraphics2D; + import org.w3c.dom.DOMImplementation; +@@ -321,40 +320,6 @@ System.setProperty("apple.awt.showGrowBox","true"); System.setProperty("apple.awt.graphics.UseQuartz","true"); @@ -57,7 +57,7 @@ UIManager.put("SystemFont", new Font("Lucida Grande", Font.PLAIN, 13)); UIManager.put("SmallSystemFont", new Font("Lucida Grande", Font.PLAIN, 11)); -@@ -465,4 +430,4 @@ public class FigTreeApplication extends +@@ -450,4 +415,4 @@ } } @@ -66,7 +66,7 @@ +} --- a/src/figtree/treeviewer/TreeViewerController.java +++ b/src/figtree/treeviewer/TreeViewerController.java -@@ -112,13 +112,10 @@ public class TreeViewerController extend +@@ -112,13 +112,10 @@ rectangularTreeToggle.setFocusable(false); polarTreeToggle.setFocusable(false); radialTreeToggle.setFocusable(false); @@ -82,7 +82,7 @@ ButtonGroup buttonGroup = new ButtonGroup(); --- a/src/figtree/application/FigTreeFrame.java +++ b/src/figtree/application/FigTreeFrame.java -@@ -224,7 +224,6 @@ public class FigTreeFrame extends Docume +@@ -226,7 +226,6 @@ // treeViewer.showStatistics(); // } // }); @@ -90,7 +90,7 @@ // toolBar.addComponent(settingsToolButton); // settingsToolButton.setEnabled(false); -@@ -235,19 +234,16 @@ public class FigTreeFrame extends Docume +@@ -237,19 +236,16 @@ toggle1.setFocusable(false); toggle1.putClientProperty("JButton.buttonType", "segmentedTextured"); toggle1.putClientProperty("JButton.segmentPosition", "first"); @@ -110,7 +110,7 @@ ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(toggle1); -@@ -301,7 +297,6 @@ public class FigTreeFrame extends Docume +@@ -303,7 +299,6 @@ prevTreeToolButton.setFocusable(false); prevTreeToolButton.putClientProperty("JButton.buttonType", "segmentedTextured"); prevTreeToolButton.putClientProperty("JButton.segmentPosition", "first"); @@ -118,7 +118,7 @@ final ToolbarAction nextTreeToolbarAction = new ToolbarAction(null, "Next Tree...", nextIcon) { -@@ -321,7 +316,6 @@ public class FigTreeFrame extends Docume +@@ -323,7 +318,6 @@ nextTreeToolButton.setFocusable(false); nextTreeToolButton.putClientProperty("JButton.buttonType", "segmentedTextured"); nextTreeToolButton.putClientProperty("JButton.segmentPosition", "last"); @@ -126,16 +126,9 @@ nextTreeToolbarAction.setEnabled(treeViewer.getCurrentTreeIndex() < treeViewer.getTreeCount() - 1); prevTreeToolbarAction.setEnabled(treeViewer.getCurrentTreeIndex() > 0); -@@ -1852,4 +1846,4 @@ public class FigTreeFrame extends Docume - private AnnotationDialog annotationDialog = null; - private AnnotationDialog copyAnnotationDialog = null; - private SelectAnnotationDialog selectAnnotationDialog = null; --} -\ No newline at end of file -+} --- a/src/figtree/treeviewer/ControllerOptionsPanel.java +++ b/src/figtree/treeviewer/ControllerOptionsPanel.java -@@ -51,7 +51,6 @@ public class ControllerOptionsPanel exte +@@ -51,7 +51,6 @@ } public static void setComponentLook(JComponent comp) { diff -Nru figtree-1.4.2+dfsg/debian/patches/java7-compat.patch figtree-1.4.3+dfsg/debian/patches/java7-compat.patch --- figtree-1.4.2+dfsg/debian/patches/java7-compat.patch 2015-12-08 10:12:33.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/patches/java7-compat.patch 2017-07-14 12:12:26.000000000 +0000 @@ -5,7 +5,7 @@ --- a/src/figtree/treeviewer/TreePane.java +++ b/src/figtree/treeviewer/TreePane.java -@@ -28,6 +28,7 @@ import jebl.evolution.trees.*; +@@ -28,6 +28,7 @@ import figtree.treeviewer.decorators.*; import figtree.treeviewer.painters.*; import figtree.treeviewer.treelayouts.*; @@ -13,7 +13,7 @@ import javax.swing.*; import java.awt.*; -@@ -2341,4 +2342,4 @@ public class TreePane extends JComponent +@@ -2449,4 +2450,4 @@ private Map calloutPaths = new HashMap(); diff -Nru figtree-1.4.2+dfsg/debian/patches/series figtree-1.4.3+dfsg/debian/patches/series --- figtree-1.4.2+dfsg/debian/patches/series 2015-12-08 10:12:33.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/patches/series 2017-07-14 12:12:26.000000000 +0000 @@ -8,3 +8,4 @@ fix_classpath_in_build_xml.patch fix_itext_api_change.patch fix_jebl.patch +fix_handling_of_paths_with_spaces_in_wrapper.patch diff -Nru figtree-1.4.2+dfsg/debian/watch figtree-1.4.3+dfsg/debian/watch --- figtree-1.4.2+dfsg/debian/watch 2015-12-08 10:12:33.000000000 +0000 +++ figtree-1.4.3+dfsg/debian/watch 2017-07-14 12:12:26.000000000 +0000 @@ -1,3 +1,3 @@ -version=3 -opts=uversionmangle=s/_/\./g,repacksuffix=+dfsg,dversionmangle=s/\+dfsg//g \ - https://github.com/rambaut/figtree/releases .*/archive/[relas_]*(\d[\d._]+)\.(?:tar(?:\.gz|\.bz2)?|tgz) +version=4 + +opts=repacksuffix=+dfsg,dversionmangle=s/\+dfsg//g https://github.com/rambaut/figtree/tags .*/v(\d.*)\.(?:tgz|tbz2|txz|tar\.(?:gz|bz2|xz)) diff -Nru figtree-1.4.2+dfsg/.gitignore figtree-1.4.3+dfsg/.gitignore --- figtree-1.4.2+dfsg/.gitignore 1970-01-01 00:00:00.000000000 +0000 +++ figtree-1.4.3+dfsg/.gitignore 2016-10-04 14:24:27.000000000 +0000 @@ -0,0 +1,9 @@ + +*.class +build/* +classes/* +dist/* +out/* +FigTree* +tests/* +examples/* Binary files /tmp/tmpTG9zXl/gn0D6isQaU/figtree-1.4.2+dfsg/lib/libquaqua64.dylib and /tmp/tmpTG9zXl/dcMjjLp3Jw/figtree-1.4.3+dfsg/lib/libquaqua64.dylib differ diff -Nru figtree-1.4.2+dfsg/README.md figtree-1.4.3+dfsg/README.md --- figtree-1.4.2+dfsg/README.md 1970-01-01 00:00:00.000000000 +0000 +++ figtree-1.4.3+dfsg/README.md 2016-10-04 14:24:27.000000000 +0000 @@ -0,0 +1,4 @@ +_FigTree_ + +FigTree is designed as a graphical viewer of phylogenetic trees and as a program for producing publication-ready figures. As with most of my programs, it was written for my own needs so may not be as polished and feature-complete as a commercial program. In particular it is designed to display summarized and annotated trees produced by BEAST. + diff -Nru figtree-1.4.2+dfsg/release/common/README.txt figtree-1.4.3+dfsg/release/common/README.txt --- figtree-1.4.2+dfsg/release/common/README.txt 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/release/common/README.txt 2016-10-04 14:24:27.000000000 +0000 @@ -1,4 +1,4 @@ - FigTree v1.4 2006-2012 + FigTree v1.4.3 2006-2016 Andrew Rambaut Institute of Evolutionary Biology @@ -7,7 +7,7 @@ UNIX/Linux/Mac OS X (command-line) version README -Last updated: a.rambaut@ed.ac.uk - 8th October 2012 +Last updated: a.rambaut@ed.ac.uk - 4th October 2016 Contents: 1) INTRODUCTION @@ -27,6 +27,52 @@ ___________________________________________________________________________ 2) VERSION HISTORY +v1.4.3 Released 4th October 2016 + +New features: + Node shape option can now show shapes for internal or external nodes or both. + Copying selected taxon labels when these are selected, subtree when branches are selected. + Selecting 'reverse axis' should automatically reverse the Time Scale scale factor. Previously the user needed to set this to -1.0. + When searching for text, scrolls to show highlighted tip. + +Bugs fixed: + Issue 102: Large SVG files from figtree are broken + Issue 95: Changing the origin value for the Scale Axis does not work + Issue 94: The trait legend overlaps the tree. + Issue 93: Command-line PDF/SVG export options not working + Issue 92: Reading a file with a mix of integer and real node labels causes exception. + Issue 90: Export picture cuts the top of the higest tip label + Issue 79: Export of .SVG produces corrupt files + +v1.4.2 Released 9th July 2014 + +New features: + New -url command line option allows reading of trees from URLs in pipelines. + +Bugs fixed: + Issue 76: Scale axis should only show as many decimal places as necessary. + Issue 75: Export PNG & JPEG produce blank images. + Issue 64: Putting node bars on translates the tree to the right (now really fixed, I think). + +v1.4.1 Released 14th June 2014 + +New features: + Copy selected subtrees to clipboard as NEXUS format. + + New graphics export options (PDF, SVG, PNG & JPEG). + + Control panel now scrolls and can be resized. + +Bugs fixed: + Issue 23: Find bar opens slowly with big trees. + Issue 28: Filtering should work on currently display labels. + Issue 53: Option Tip Labels: "Colour By" does not render Names in colour. + Issue 57: Midpoint rooting not working correctly. + Issue 59: Clear Highlighting/Cartoon etc doesn't seem to work on individual branches. + Issue 62: When all clades are 'collapsed', the top triangle is clipped. + Issue 64: Putting node bars on translates the tree to the right. + Issue 69: Import annotation causes crash. + v1.4 Released 8th October 2012. New Features: diff -Nru figtree-1.4.2+dfsg/src/figtree/application/FigTreeApplication.java figtree-1.4.3+dfsg/src/figtree/application/FigTreeApplication.java --- figtree-1.4.2+dfsg/src/figtree/application/FigTreeApplication.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/application/FigTreeApplication.java 2016-10-04 14:24:27.000000000 +0000 @@ -30,6 +30,11 @@ package figtree.application; +import com.itextpdf.text.Document; +import com.itextpdf.text.DocumentException; +import com.itextpdf.text.pdf.PdfContentByte; +import com.itextpdf.text.pdf.PdfTemplate; +import com.itextpdf.text.pdf.PdfWriter; import figtree.application.preferences.*; import figtree.treeviewer.ExtendedTreeViewer; import jam.framework.*; @@ -52,6 +57,9 @@ import javax.swing.*; import ch.randelshofer.quaqua.QuaquaManager; +import org.apache.batik.dom.GenericDOMImplementation; +import org.apache.batik.svggen.SVGGraphics2D; +import org.w3c.dom.DOMImplementation; /** * Application class for FigTree including main() method for invoking it. @@ -68,8 +76,8 @@ */ public class FigTreeApplication extends MultiDocApplication { - public static final String VERSION = "1.4.2"; - public static final String DATES = "2006-2014"; + public static final String VERSION = "1.4.3"; + public static final String DATES = "2006-2016"; public static FigTreeApplication application; @@ -164,34 +172,10 @@ GraphicFormat format = null; if (graphicFormat.equals("PDF")) { - if (graphicFileName != null) { - System.out.println("Creating PDF graphic: " + graphicFileName); - } format = GraphicFormat.PDF; -// } else if (graphicFormat.equals("PS")) { -// if (graphicFileName != null) { -// System.out.println("Creating PS graphic: " + graphicFileName); -// } -// g = new PSGraphics2D(stream, new Dimension(width, height)); -// } else if (graphicFormat.equals("EMF")) { -// if (graphicFileName != null) { -// System.out.println("Creating EMF graphic: " + graphicFileName); -// } -// g = new EMFGraphics2D(stream, new Dimension(width, height)); -// } else if (graphicFormat.equals("SVG")) { -// if (graphicFileName != null) { -// System.out.println("Creating SVG graphic: " + graphicFileName); -// } -// g = new SVGGraphics2D(stream, new Dimension(width, height)); -// } else if (graphicFormat.equals("SWF")) { -// if (graphicFileName != null) { -// System.out.println("Creating SWF graphic: " + graphicFileName); -// } -// g = new SWFGraphics2D(stream, new Dimension(width, height)); + } else if (graphicFormat.equals("SVG")) { + format = GraphicFormat.SVG; } else if (graphicFormat.equals("GIF")) { - if (graphicFileName != null) { - System.out.println("Creating GIF graphic: " + graphicFileName); - } format = GraphicFormat.GIF; } else if (graphicFormat.equals("PNG")) { format = GraphicFormat.PNG; @@ -201,17 +185,18 @@ throw new RuntimeException("Unknown graphic format"); } - JComponent comp = treeViewer.getContentPane(); - BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - Graphics g = bi.createGraphics(); - comp.paint(g); - g.dispose(); - ImageIO.write(bi, format.getName(), stream); + if (graphicFileName != null) { + System.out.println("Creating " + graphicFormat + " graphic: " + graphicFileName); + } + + FigTreeFrame.exportGraphics(format, treeViewer.getContentPane(), stream); } catch(ImportException ie) { - throw new RuntimeException("Error writing graphic file: " + ie); + throw new RuntimeException("Error writing graphic file: " + ie.getMessage()); } catch(IOException ioe) { - throw new RuntimeException("Error writing graphic file: " + ioe); + throw new RuntimeException("Error writing graphic file: " + ioe.getMessage()); + } catch (DocumentException de) { + throw new RuntimeException("Error writing graphic file: " + de.getMessage()); } } @@ -264,10 +249,10 @@ new Arguments.Option[] { new Arguments.StringOption("graphic", new String[] { "PDF", - // "SVG", + "SVG", // "SWF", "PS", "EMF", "PNG", - "GIF", + // "GIF", "JPEG" }, false, "produce a graphic with the given format"), new Arguments.IntegerOption("width", "the width of the graphic in pixels"), @@ -405,7 +390,7 @@ icon = new ImageIcon(url); } - final String nameString = "FigTree " + VERSION; + final String nameString = "FigTree"; String titleString = "" + "
" + "

FigTree

" + diff -Nru figtree-1.4.2+dfsg/src/figtree/application/FigTreeFrame.java figtree-1.4.3+dfsg/src/figtree/application/FigTreeFrame.java --- figtree-1.4.2+dfsg/src/figtree/application/FigTreeFrame.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/application/FigTreeFrame.java 2016-10-04 14:24:27.000000000 +0000 @@ -29,6 +29,7 @@ import figtree.treeviewer.decorators.DiscreteColourDecorator; import figtree.treeviewer.decorators.HSBDiscreteColourDecorator; import figtree.treeviewer.painters.StatesPainter; +import jebl.evolution.align.Output; import jebl.evolution.alignments.Alignment; import jebl.evolution.alignments.BasicAlignment; import jebl.evolution.graphs.Node; @@ -52,6 +53,7 @@ import org.apache.batik.svggen.SVGGraphics2D; import org.apache.batik.svggen.SVGGraphics2DIOException; import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Element; import javax.imageio.ImageIO; import javax.swing.*; @@ -288,7 +290,7 @@ public void actionPerformed(ActionEvent e){ if (treeViewer.isRootingOn() && treeViewer.getRootingType() == TreePane.RootingType.USER_ROOTING) { JOptionPane.showMessageDialog(FigTreeFrame.this, "Cannot switch trees when user rooting option is on.\n" + - "Turn this option off to switch trees", + "Turn this option off to switch trees", "Unable to switch trees", JOptionPane.ERROR_MESSAGE); @@ -308,7 +310,7 @@ public void actionPerformed(ActionEvent e){ if (treeViewer.isRootingOn() && treeViewer.getRootingType() == TreePane.RootingType.USER_ROOTING) { JOptionPane.showMessageDialog(FigTreeFrame.this, "Cannot switch trees when user rooting option is on.\n" + - "Turn this option off to switch trees", + "Turn this option off to switch trees", "Unable to switch trees", JOptionPane.ERROR_MESSAGE); @@ -1216,27 +1218,16 @@ File file = new File(dialog.getDirectory(), dialog.getFile()); try { - JComponent comp = treeViewer.getContentPane(); - switch (format) { + OutputStream stream = new FileOutputStream(file); - case PNG: - case GIF: - case BMP: - case JPEG: - exportGraphicsFile(format, comp, file); - break; - case EPS: - throw new UnsupportedOperationException("EPS not handled"); - case SVG: - exportSVGFile(comp, file); - break; - case PDF: - exportPDFFile(comp, file); - break; - default: - throw new UnsupportedOperationException("Format not handled: " + format); + exportGraphics(format, treeViewer.getContentPane(), stream); - } + stream.flush(); + stream.close(); + } catch(DocumentException de) { + JOptionPane.showMessageDialog(this, "Error writing PDF file: " + de, + "Export PDF Error", + JOptionPane.ERROR_MESSAGE); } catch (IOException ioe) { JOptionPane.showMessageDialog(this, "Error writing tree file: " + ioe.getMessage(), "Export Error", @@ -1247,7 +1238,30 @@ } - private final void exportGraphicsFile(GraphicFormat format, JComponent component, File file) throws IOException { + public final static void exportGraphics(GraphicFormat format, JComponent comp, OutputStream stream) throws IOException, DocumentException { + switch (format) { + + case PNG: + case GIF: + case BMP: + case JPEG: + exportGraphicsFile(format, comp, stream); + break; + case EPS: + throw new UnsupportedOperationException("EPS not handled"); + case SVG: + exportSVGFile(comp, stream); + break; + case PDF: + exportPDFFile(comp, stream); + break; + default: + throw new UnsupportedOperationException("Format not handled: " + format); + + } + + } + private final static void exportGraphicsFile(GraphicFormat format, JComponent component, OutputStream stream) throws IOException { int imageType = BufferedImage.TYPE_INT_RGB; if (format == GraphicFormat.PNG) { @@ -1263,10 +1277,10 @@ } component.paint(g); g.dispose(); - ImageIO.write(bi, format.getName(), file); + ImageIO.write(bi, format.getName(), stream); } - private final void exportSVGFile(JComponent component, File file) throws IOException { + private final static void exportSVGFile(JComponent component, OutputStream stream) throws IOException { // Get a DOMImplementation and create an XML document DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation(); org.w3c.dom.Document document = domImpl.createDocument(null, "svg", null); @@ -1275,50 +1289,46 @@ SVGGraphics2D svgGenerator = new SVGGraphics2D(document); component.paint(svgGenerator); + Element svgRoot = svgGenerator.getRoot(); + Rectangle2D bounds = component.getBounds(); + String viewBox = "0 0 " + bounds.getWidth() + " " + bounds.getHeight(); + svgRoot.setAttributeNS(null, svgGenerator.SVG_VIEW_BOX_ATTRIBUTE, viewBox); + svgRoot.setAttributeNS(null, svgGenerator.SVG_WIDTH_ATTRIBUTE, Double.toString(bounds.getWidth())); + svgRoot.setAttributeNS(null, svgGenerator.SVG_HEIGHT_ATTRIBUTE, Double.toString(bounds.getHeight())); // Write svg file - OutputStream outputStream = new FileOutputStream(file); - Writer out = new OutputStreamWriter(outputStream, "UTF-8"); - svgGenerator.stream(out, true /* use css */); - outputStream.flush(); - outputStream.close(); + Writer out = new OutputStreamWriter(stream, "UTF-8"); + svgGenerator.stream(svgRoot, out, true /* use css */, false /* escaped */); } - public final void exportPDFFile(JComponent component, File file) { - Rectangle2D bounds = treeViewer.getContentPane().getBounds(); + public final static void exportPDFFile(JComponent component, OutputStream stream) throws DocumentException { + Rectangle2D bounds = component.getBounds(); Document document = new Document(new com.itextpdf .text.Rectangle((float)bounds.getWidth(), (float)bounds.getHeight())); - try { - // step 2 - PdfWriter writer; - writer = PdfWriter.getInstance(document, new FileOutputStream(file)); - // step 3 - document.open(); - // step 4 - PdfContentByte cb = writer.getDirectContent(); - PdfTemplate tp = cb.createTemplate((float)bounds.getWidth(), (float)bounds.getHeight()); - Graphics2D g2d = tp.createGraphics((float)bounds.getWidth(), (float)bounds.getHeight(), new DefaultFontMapper()); - component.print(g2d); - g2d.dispose(); - cb.addTemplate(tp, 0, 0); - } - catch(DocumentException de) { - JOptionPane.showMessageDialog(this, "Error writing PDF file: " + de, - "Export PDF Error", - JOptionPane.ERROR_MESSAGE); - } - catch (FileNotFoundException e) { - JOptionPane.showMessageDialog(this, "Error writing PDF file: " + e, - "Export PDF Error", - JOptionPane.ERROR_MESSAGE); - } + // step 2 + PdfWriter writer; + writer = PdfWriter.getInstance(document, stream); + // step 3 + document.open(); + // step 4 + PdfContentByte cb = writer.getDirectContent(); + PdfTemplate tp = cb.createTemplate((float)bounds.getWidth(), (float)bounds.getHeight()); + Graphics2D g2d = tp.createGraphics((float)bounds.getWidth(), (float)bounds.getHeight(), new DefaultFontMapper()); + component.print(g2d); + g2d.dispose(); + cb.addTemplate(tp, 0, 0); + document.close(); } public void doCopy() { StringWriter writer = new StringWriter(); try { - writeTreeFile(writer, ExportTreeDialog.Format.NEXUS, true, false, false, true, true); + if (treeViewer.getSelectionMode() == TreePaneSelector.SelectionMode.TAXA) { + writeTaxa(writer); + } else { + writeTreeFile(writer, ExportTreeDialog.Format.NEXUS, true, false, false, true, true); + } } catch (IOException e) { e.printStackTrace(); } @@ -1382,6 +1392,14 @@ treeViewer.selectAll(); } + protected void writeTaxa(Writer writer) throws IOException { + PrintWriter printWriter = new PrintWriter(writer); + for (Taxon taxon : treeViewer.getSelectedTaxa()) { + printWriter.println(taxon.getName()); + } + writer.close(); + } + protected void writeTreeFile(Writer writer, ExportTreeDialog.Format format, boolean writeAllTrees, boolean writeAsDisplayed, @@ -1852,4 +1870,4 @@ private AnnotationDialog annotationDialog = null; private AnnotationDialog copyAnnotationDialog = null; private SelectAnnotationDialog selectAnnotationDialog = null; -} \ No newline at end of file +} diff -Nru figtree-1.4.2+dfsg/src/figtree/application/FigTreePanel.java figtree-1.4.3+dfsg/src/figtree/application/FigTreePanel.java --- figtree-1.4.2+dfsg/src/figtree/application/FigTreePanel.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/application/FigTreePanel.java 2016-10-04 14:24:27.000000000 +0000 @@ -48,6 +48,8 @@ public final static int CONTROL_PALETTE_WIDTH = 200; + private final static boolean SEPARATE_NODE_SHAPE_PANELS = true; + public FigTreePanel(JFrame frame, final ExtendedTreeViewer treeViewer, ControlPalette controlPalette) { this.treeViewer = treeViewer; @@ -80,12 +82,30 @@ controlPalette.addController(new LabelPainterController("Tip Labels", "tipLabels", tipLabelPainter, frame, attributeColourController, treeViewer)); treeViewer.setTipLabelPainter(tipLabelPainter); + // Create a node shape painter and its controller + if (SEPARATE_NODE_SHAPE_PANELS) { + final NodeShapePainter tipNodeShapePainter = new NodeShapePainter(); + tipNodeShapePainter.setVisible(false); + controlPalette.addController(new NodeShapeController("Tip Shapes", NodeShapeController.NodeType.EXTERNAL, tipNodeShapePainter, attributeColourController, treeViewer)); + treeViewer.setTipShapePainter(tipNodeShapePainter); + } // Create a node label painter and its controller final BasicLabelPainter nodeLabelPainter = new BasicLabelPainter(BasicLabelPainter.PainterIntent.NODE); nodeLabelPainter.setVisible(false); controlPalette.addController(new LabelPainterController("Node Labels", "nodeLabels", nodeLabelPainter, frame, attributeColourController, treeViewer)); treeViewer.setNodeLabelPainter(nodeLabelPainter); + // Create a node shape painter and its controller + final NodeShapePainter nodeShapePainter = new NodeShapePainter(); + nodeShapePainter.setVisible(false); + controlPalette.addController(new NodeShapeController("Node Shapes", + (SEPARATE_NODE_SHAPE_PANELS ? NodeShapeController.NodeType.INTERNAL : NodeShapeController.NodeType.BOTH), + nodeShapePainter, attributeColourController, treeViewer)); + if (!SEPARATE_NODE_SHAPE_PANELS) { + treeViewer.setTipShapePainter(nodeShapePainter); + } + treeViewer.setNodeShapePainter(nodeShapePainter); + // Create a node bar painter and its controller final NodeBarPainter nodeBarPainter = new NodeBarPainter(); nodeBarPainter.setForeground(new Color(24, 32, 228, 128)); @@ -93,12 +113,6 @@ controlPalette.addController(new NodeBarController("Node Bars", nodeBarPainter, treeViewer)); treeViewer.setNodeBarPainter(nodeBarPainter); - // Create a node shape painter and its controller - final NodeShapePainter nodeShapePainter = new NodeShapePainter(); - nodeShapePainter.setVisible(false); - controlPalette.addController(new NodeShapeController("Node Shapes", nodeShapePainter, attributeColourController, treeViewer)); - treeViewer.setNodeShapePainter(nodeShapePainter); - // Create a branch label painter and its controller final BasicLabelPainter branchLabelPainter = new BasicLabelPainter(BasicLabelPainter.PainterIntent.BRANCH); branchLabelPainter.setVisible(false); @@ -193,17 +207,17 @@ if (utilityPanel == null) { return; } - slideOpenPanel.showUtilityPanel(utilityPanel); + slideOpenPanel.showUtilityPanel(utilityPanel); } - public void hideUtilityPanel() { - slideOpenPanel.hideUtilityPanel(); - } + public void hideUtilityPanel() { + slideOpenPanel.hideUtilityPanel(); + } - public JPanel getUtilityPanel() { - return slideOpenPanel.getUtilityPanel(); - } + public JPanel getUtilityPanel() { + return slideOpenPanel.getUtilityPanel(); + } public void toggleMidpointRoot() { treesController.toggleMidpointRoot(); diff -Nru figtree-1.4.2+dfsg/src/figtree/application/FigTreePDF.java figtree-1.4.3+dfsg/src/figtree/application/FigTreePDF.java --- figtree-1.4.2+dfsg/src/figtree/application/FigTreePDF.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/application/FigTreePDF.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,205 +0,0 @@ -/* - * FigTreePDF.java - * - * Copyright (C) 2006-2014 Andrew Rambaut - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -/** - * TracerApp.java - * - * Title: Tracer - * Description: An application for analysing MCMC trace files. - * @author Andrew Rambaut - * @author Alexei Drummond - * @version $Id: FigTreeApplication.java,v 1.15 2007/09/10 14:52:02 rambaut Exp $ - */ - -package figtree.application; - -import com.itextpdf.text.Document; -import com.itextpdf.text.pdf.PdfContentByte; -import com.itextpdf.text.pdf.PdfTemplate; -import com.itextpdf.text.pdf.PdfWriter; -import figtree.treeviewer.ExtendedTreeViewer; -import jam.controlpalettes.BasicControlPalette; -import jam.controlpalettes.ControlPalette; - -import java.io.*; -import java.util.*; -import java.util.List; -import java.awt.*; - -import jebl.evolution.io.ImportException; -import jebl.evolution.io.NewickImporter; -import jebl.evolution.trees.Tree; - -/** - * Commandline main() to generate PDF graphics from FigTree trees. - * - * @author Andrew Rambaut - * @version $Id$ - * - * $HeadURL$ - * - * $LastChangedBy$ - * $LastChangedDate$ - * $LastChangedRevision$ - */ -public class FigTreePDF { - - public static final String VERSION = "1.4.1"; - public static final String DATES = "2006-2014"; - - static public void createGraphic(int width, int height, String treeFileName, String graphicFileName) { - - try { - BufferedReader bufferedReader = new BufferedReader(new FileReader(treeFileName)); - String line = bufferedReader.readLine(); - while (line != null && line.length() == 0) { - line = bufferedReader.readLine(); - } - - bufferedReader.close(); - - boolean isNexus = (line != null && line.toUpperCase().contains("#NEXUS")); - - Reader reader = new FileReader(treeFileName); - - Map settings = new HashMap(); - - ExtendedTreeViewer treeViewer = new ExtendedTreeViewer(); - ControlPalette controlPalette = new BasicControlPalette(200, BasicControlPalette.DisplayMode.ONLY_ONE_OPEN); - FigTreePanel figTreePanel = new FigTreePanel(null, treeViewer, controlPalette); - - // First of all, fully populate the settings map so that - // all the settings have defaults - controlPalette.getSettings(settings); - - List trees = new ArrayList(); - - if (isNexus) { - FigTreeNexusImporter importer = new FigTreeNexusImporter(reader); - trees.add(importer.importNextTree()); - - // Try to find a figtree block and if found, parse the settings - while (true) { - try { - importer.findNextBlock(); - if (importer.getNextBlockName().equalsIgnoreCase("FIGTREE")) { - importer.parseFigTreeBlock(settings); - } - } catch (EOFException ex) { - break; - } - } - } else { - NewickImporter importer = new NewickImporter(reader, true); - trees.add(importer.importNextTree()); - } - - if (trees.size() == 0) { - throw new ImportException("This file contained no trees."); - } - - treeViewer.setTrees(trees); - - controlPalette.setSettings(settings); - - treeViewer.getContentPane().setSize(width, height); - - OutputStream stream; - if (graphicFileName != null) { - stream = new FileOutputStream(graphicFileName); - } else { - stream = System.out; - } - - Document document = new Document(); - document.setPageSize(new com.itextpdf.text.Rectangle(width, height)); - try { - PdfWriter writer = PdfWriter.getInstance(document, stream); - document.open(); - PdfContentByte cb = writer.getDirectContent(); - PdfTemplate tp = cb.createTemplate(width, height); - Graphics2D g2 = tp.createGraphics(width, height); - tp.setWidth(width); - tp.setHeight(height); - treeViewer.getContentPane().print(g2); - g2.dispose(); - tp.sanityCheck(); // all the g2 content is written to tp, not cb - cb.addTemplate(tp, 0, 0); - cb.sanityCheck(); - } catch (Exception e) { - System.err.println(e.getMessage()); - } - document.close(); - - } catch(ImportException ie) { - throw new RuntimeException("Error writing graphic file: " + ie); - } catch(IOException ioe) { - throw new RuntimeException("Error writing graphic file: " + ioe); - } - - } - - // Main entry point - static public void main(String[] args) { - - Arguments arguments = new Arguments( - new Arguments.Option[] { - new Arguments.IntegerOption("width", "the width of the graphic in pixels"), - new Arguments.IntegerOption("height", "the height of the graphic in pixels") - }); - - try { - arguments.parseArguments(args); - } catch (Arguments.ArgumentException ae) { - System.out.println(); - System.out.println(ae.getMessage()); - System.out.println(); - System.exit(1); - } - - - int width = 800; - int height = 600; - - if (arguments.hasOption("width")) { - width = arguments.getIntegerOption("width"); - } - - if (arguments.hasOption("height")) { - height = arguments.getIntegerOption("height"); - } - - // command line version... - String[] args2 = arguments.getLeftoverArguments(); - - if (args2.length == 0) { - // no tree file specified - System.exit(0); - } else if (args2.length == 1) { - // no graphic file specified - write to stdout - createGraphic(width, height, args2[0], (args2.length > 1 ? args2[1] : null)); - System.exit(0); - } else { - createGraphic(width, height, args2[0], (args2.length > 1 ? args2[1] : null)); - System.exit(0); - } - } -} - diff -Nru figtree-1.4.2+dfsg/src/figtree/application/JSONTreeExporter.java figtree-1.4.3+dfsg/src/figtree/application/JSONTreeExporter.java --- figtree-1.4.2+dfsg/src/figtree/application/JSONTreeExporter.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/application/JSONTreeExporter.java 2016-10-04 14:24:27.000000000 +0000 @@ -56,7 +56,8 @@ public class JSONTreeExporter implements TreeExporter { public static final String treeNameAttributeKey = "name"; - public final static Set ATTRIBUTE_NAMES = new TreeSet(Arrays.asList(new String[] { "location", "host", "Hx", "Nx", "posterior" })); + public final static Set ATTRIBUTE_NAMES = new TreeSet(Arrays.asList(new String[] { + "location", "host", "Hx", "Nx", "posterior", "country", "region" })); public final static String ORIGIN = "2013.34520547945"; public JSONTreeExporter(Writer writer) { diff -Nru figtree-1.4.2+dfsg/src/figtree/panel/FigTreePanel.java figtree-1.4.3+dfsg/src/figtree/panel/FigTreePanel.java --- figtree-1.4.2+dfsg/src/figtree/panel/FigTreePanel.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/panel/FigTreePanel.java 2016-10-04 14:24:27.000000000 +0000 @@ -121,7 +121,8 @@ treeViewer, "tipLabels", tipLabelPainter, "nodeLabels", nodeLabelPainter, - "branchLabels", branchLabelPainter)); + "branchLabels", branchLabelPainter, + true, true)); controlPalette1.addController(new LabelPainterController( "tipLabels", tipLabelPainter, @@ -139,7 +140,7 @@ "tipLabels", tipLabelPainter, "nodeLabels", nodeLabelPainter, "branchLabels", branchLabelPainter, - true)); + true, false)); controlPalette1.addController(new LabelPainterController( "tipLabels", tipLabelPainter, @@ -160,7 +161,7 @@ "tipLabels", tipLabelPainter, "nodeLabels", nodeLabelPainter, "branchLabels", branchLabelPainter, - true)); + true, false)); controlPalette2.addController(new TreeColouringController(treeViewer, "Clustering:")); add(controlPalette2.getPanel(), BorderLayout.NORTH); diff -Nru figtree-1.4.2+dfsg/src/figtree/panel/LabelPainterController.java figtree-1.4.3+dfsg/src/figtree/panel/LabelPainterController.java --- figtree-1.4.2+dfsg/src/figtree/panel/LabelPainterController.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/panel/LabelPainterController.java 2016-10-04 14:24:27.000000000 +0000 @@ -22,6 +22,7 @@ import figtree.treeviewer.TreeViewer; import figtree.treeviewer.painters.AttributeComboHelper; +import figtree.treeviewer.painters.AttributeComboHelperListener; import jam.controlpalettes.AbstractController; import jam.panels.OptionsPanel; @@ -31,7 +32,6 @@ import java.util.Map; import figtree.treeviewer.painters.LabelPainter; -import sun.jvm.hotspot.tools.FinalizerInfo; /** * @author Andrew Rambaut @@ -48,11 +48,11 @@ private static final String DISPLAY_ATTRIBUTE_KEY = "displayAttribute"; public LabelPainterController(String tipKey, - final LabelPainter tipLabelPainter, + final SimpleLabelPainter tipLabelPainter, String nodeKey, - final LabelPainter nodeLabelPainter, + final SimpleLabelPainter nodeLabelPainter, String branchKey, - final LabelPainter branchLabelPainter, + final SimpleLabelPainter branchLabelPainter, final TreeViewer treeViewer) { this.tipKey = tipKey; @@ -68,17 +68,20 @@ } - private JComboBox setupComboBox(String title, final LabelPainter labelPainter, final TreeViewer treeViewer) { + private JComboBox setupComboBox(String title, final SimpleLabelPainter labelPainter, final TreeViewer treeViewer) { // String[] attributes = labelPainter.getAttributes(); final JComboBox displayAttributeCombo = new JComboBox(); displayAttributeCombo.addItem("None"); - new AttributeComboHelper(displayAttributeCombo, treeViewer, "None"); + for (String attribute : labelPainter.getAttributes()) { + displayAttributeCombo.addItem(attribute); + } + new AttributeComboHelper(displayAttributeCombo, treeViewer, "None", labelPainter.getIntent()); optionsPanel.addComponentWithLabel(title, displayAttributeCombo); displayAttributeCombo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent itemEvent) { String attribute = (String)displayAttributeCombo.getSelectedItem(); - if (attribute.equals("none")) { + if (attribute == null || attribute.equalsIgnoreCase("none")) { labelPainter.setVisible(false); } else { labelPainter.setDisplayAttribute(attribute); diff -Nru figtree-1.4.2+dfsg/src/figtree/panel/SimpleLabelPainter.java figtree-1.4.3+dfsg/src/figtree/panel/SimpleLabelPainter.java --- figtree-1.4.2+dfsg/src/figtree/panel/SimpleLabelPainter.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/panel/SimpleLabelPainter.java 2016-10-04 14:24:27.000000000 +0000 @@ -50,298 +50,296 @@ */ public class SimpleLabelPainter extends LabelPainter { - public static final String TAXON_NAMES = "Taxon names"; - public static final String NODE_AGES = "Node ages"; - public static final String BRANCH_LENGTHS = "Branch lengths"; + public static final String NAMES = "Names"; + public static final String NODE_AGES = "Node ages"; + public static final String BRANCH_LENGTHS = "Branch lengths"; - public SimpleLabelPainter(PainterIntent intent) { + public SimpleLabelPainter(PainterIntent intent) { super(intent); - setupAttributes(null); + setupAttributes(null); - if (this.displayAttribute == null) { - this.displayAttribute = attributes[0]; - } else { - this.displayAttribute = ""; - } - - } - - public void setupAttributes(Collection trees) { - - List attributeNames = new ArrayList(); - switch( intent ) { - case TIP: { - attributeNames.add(TAXON_NAMES); - attributeNames.add(NODE_AGES); - attributeNames.add(BRANCH_LENGTHS); - break; - } - case NODE: { - attributeNames.add(NODE_AGES); - attributeNames.add(BRANCH_LENGTHS); - break; - } - case BRANCH: { - attributeNames.add(BRANCH_LENGTHS); - attributeNames.add(NODE_AGES); - break; - } - } - - if (trees != null) { - for (Tree tree : trees) { - Set nodeAttributes = new TreeSet(); - if (intent == PainterIntent.TIP) { - for (Node node : tree.getExternalNodes()) { - nodeAttributes.addAll(node.getAttributeNames()); - } - } else if (intent == PainterIntent.NODE) { - for (Node node : tree.getInternalNodes()) { - nodeAttributes.addAll(node.getAttributeNames()); - } - } else { - for (Node node : tree.getNodes()) { - nodeAttributes.addAll(node.getAttributeNames()); - } - } - for (String attributeName : nodeAttributes) { - if (!attributeName.startsWith("!")) { - attributeNames.add(attributeName); - } - } - } - } - - this.attributes = new String[attributeNames.size()]; - attributeNames.toArray(this.attributes); - - firePainterSettingsChanged(); - } - - public void setTreePane(TreePane treePane) { - this.treePane = treePane; - } - - public Decorator getBorderDecorator() { - return borderDecorator; - } - - public void setBorderDecorator(Decorator borderDecorator) { - this.borderDecorator = borderDecorator; - } - - public Decorator getTextDecorator() { - return textDecorator; - } - - public void setTextDecorator(Decorator textDecorator) { - this.textDecorator = textDecorator; - } + if (this.displayAttribute == null) { + this.displayAttribute = attributes[0]; + } else { + this.displayAttribute = ""; + } + + } + + public void setupAttributes(Collection trees) { + + List attributeNames = new ArrayList(); + switch (getIntent()) { + case TIP: { + attributeNames.add(NAMES); + attributeNames.add(NODE_AGES); + attributeNames.add(BRANCH_LENGTHS); + break; + } + case NODE: { + attributeNames.add(NODE_AGES); + attributeNames.add(BRANCH_LENGTHS); + break; + } + case BRANCH: { + attributeNames.add(BRANCH_LENGTHS); + attributeNames.add(NODE_AGES); + break; + } + } + + if (trees != null) { + for (Tree tree : trees) { + Set nodeAttributes = new TreeSet(); + if (getIntent() == PainterIntent.TIP) { + for (Node node : tree.getExternalNodes()) { + nodeAttributes.addAll(node.getAttributeNames()); + } + } else if (getIntent() == PainterIntent.NODE) { + for (Node node : tree.getInternalNodes()) { + nodeAttributes.addAll(node.getAttributeNames()); + } + } else { + for (Node node : tree.getNodes()) { + nodeAttributes.addAll(node.getAttributeNames()); + } + } + for (String attributeName : nodeAttributes) { + if (!attributeName.startsWith("!")) { + attributeNames.add(attributeName); + } + } + } + } + + this.attributes = new String[attributeNames.size()]; + attributeNames.toArray(this.attributes); + + firePainterSettingsChanged(); + } + + public void setTreePane(TreePane treePane) { + this.treePane = treePane; + } + + public Decorator getBorderDecorator() { + return borderDecorator; + } + + public void setBorderDecorator(Decorator borderDecorator) { + this.borderDecorator = borderDecorator; + } + + public Decorator getTextDecorator() { + return textDecorator; + } + + public void setTextDecorator(Decorator textDecorator) { + this.textDecorator = textDecorator; + } public Set getAttributableItems() { return null; } public Tree getTree() { - return treePane.getTree(); - } + return treePane.getTree(); + } + + protected String getLabel(Tree tree, Node node) { + if (displayAttribute.equalsIgnoreCase(NAMES)) { + Taxon taxon = tree.getTaxon(node); + if (taxon != null) { + if (textDecorator != null) { + textDecorator.setItem(taxon); + } + return taxon.getName(); + } else { + String name = (String)node.getAttribute("name"); + if (name != null) { + return name; + } + return "unlabelled"; + } + } + + if ( tree instanceof RootedTree) { + final RootedTree rtree = (RootedTree) tree; + + if (textDecorator != null) { + textDecorator.setItem(node); + } + + if (displayAttribute.equalsIgnoreCase(NODE_AGES) ) { + return getNumberFormat().format(rtree.getHeight(node)); + } else if (displayAttribute.equalsIgnoreCase(BRANCH_LENGTHS) ) { + return getNumberFormat().format(rtree.getLength(node)); + } + } + + return formatValue(node.getAttribute(displayAttribute)); + } + + private String formatValue(Object value) { + if (value != null) { + if (value instanceof Double) { + return getNumberFormat().format(value); + } else if (value instanceof Object[]) { + Object[] values = (Object[])value; + + if (values.length == 0) return null; + if (values.length == 1) return formatValue(values[0]); + + StringBuilder builder = new StringBuilder("["); + builder.append(formatValue(values[0])); + for (int i = 1; i < values.length; i++) { + builder.append(","); + builder.append(formatValue(values[i])); + } + builder.append("]"); + return builder.toString(); + } + return value.toString(); + } + return null; + } - protected String getLabel(Tree tree, Node node) { - if (displayAttribute.equalsIgnoreCase(TAXON_NAMES)) { - Taxon taxon = tree.getTaxon(node); - if (taxon != null) { - if (textDecorator != null) { - textDecorator.setItem(taxon); - } - return taxon.getName(); - } else { - String name = (String)node.getAttribute("name"); - if (name != null) { - return name; - } - return "unlabelled"; - } - } - - if ( tree instanceof RootedTree) { - final RootedTree rtree = (RootedTree) tree; - - if (textDecorator != null) { - textDecorator.setItem(node); - } - - if (displayAttribute.equalsIgnoreCase(NODE_AGES) ) { - return getNumberFormat().format(rtree.getHeight(node)); - } else if (displayAttribute.equalsIgnoreCase(BRANCH_LENGTHS) ) { - return getNumberFormat().format(rtree.getLength(node)); - } - } - - return formatValue(node.getAttribute(displayAttribute)); - } - - private String formatValue(Object value) { - if (value != null) { - if (value instanceof Double) { - return getNumberFormat().format(value); - } else if (value instanceof Object[]) { - Object[] values = (Object[])value; - - if (values.length == 0) return null; - if (values.length == 1) return formatValue(values[0]); - - StringBuilder builder = new StringBuilder("["); - builder.append(formatValue(values[0])); - for (int i = 1; i < values.length; i++) { - builder.append(","); - builder.append(formatValue(values[i])); - } - builder.append("]"); - return builder.toString(); - } - return value.toString(); - } - return null; - } - - public Rectangle2D calibrate(Graphics2D g2, Node item) { - Tree tree = treePane.getTree(); - - String label = getLabel(tree, item); - - final Font oldFont = g2.getFont(); - if (textDecorator != null) { - g2.setFont(textDecorator.getFont(getFont())); - } else { - g2.setFont(getFont()); - } - - FontMetrics fm = g2.getFontMetrics(); - preferredHeight = fm.getHeight(); - preferredWidth = 0; - - if (label != null) { - Rectangle2D rect = fm.getStringBounds(label, g2); - preferredWidth = rect.getWidth(); - } - - yOffset = (float)fm.getAscent(); - - g2.setFont(oldFont); - - return new Rectangle2D.Double(0.0, 0.0, preferredWidth, preferredHeight); - } - - public double getPreferredWidth() { - return preferredWidth; - } - - public double getPreferredHeight() { - return preferredHeight; - } - - public double getHeightBound() { - return preferredHeight + yOffset; - } - - public void paint(Graphics2D g2, Node item, Justification justification, Rectangle2D bounds) { - Tree tree = treePane.getTree(); - - if (TreePane.DEBUG_OUTLINE) { - g2.setPaint(Color.red); - g2.draw(bounds); - } - - String label = getLabel(tree, item); - - Font oldFont = g2.getFont(); - - Paint backgroundPaint = getBackground(); - Paint borderPaint = getBorderPaint(); - Stroke borderStroke = getBorderStroke(); - - if (borderDecorator != null) { - backgroundPaint = borderDecorator.getPaint(backgroundPaint); - borderPaint = borderDecorator.getPaint(borderPaint); - borderStroke = borderDecorator.getStroke(borderStroke); - } - - if (backgroundPaint != null) { - g2.setPaint(backgroundPaint); - g2.fill(bounds); - } - - if (borderPaint != null && borderStroke != null) { - g2.setPaint(borderPaint); - g2.setStroke(borderStroke); - g2.draw(bounds); - } - - if (textDecorator != null) { - g2.setPaint(textDecorator.getPaint(getForeground())); - g2.setFont(textDecorator.getFont(getFont())); - } else { - g2.setPaint(getForeground()); - g2.setFont(getFont()); - } - - if (label != null) { - - Rectangle2D rect = null; - if (justification == Justification.CENTER || justification == Justification.RIGHT) - rect = g2.getFontMetrics().getStringBounds(label, g2); - - float xOffset; - float y = yOffset + (float) bounds.getY(); - switch (justification) { - case CENTER: - xOffset = (float)(-rect.getWidth()/2.0); - y = yOffset + (float) rect.getY(); + public Rectangle2D calibrate(Graphics2D g2, Node item) { + Tree tree = treePane.getTree(); + + String label = getLabel(tree, item); + + final Font oldFont = g2.getFont(); + if (textDecorator != null) { + g2.setFont(textDecorator.getFont(getFont())); + } else { + g2.setFont(getFont()); + } + + FontMetrics fm = g2.getFontMetrics(); + preferredHeight = fm.getHeight(); + preferredWidth = 0; + + if (label != null) { + Rectangle2D rect = fm.getStringBounds(label, g2); + preferredWidth = rect.getWidth(); + } + + yOffset = (float)fm.getAscent(); + + g2.setFont(oldFont); + + return new Rectangle2D.Double(0.0, 0.0, preferredWidth, preferredHeight); + } + + public double getPreferredWidth() { + return preferredWidth; + } + + public double getPreferredHeight() { + return preferredHeight; + } + + public double getHeightBound() { + return preferredHeight + yOffset; + } + + public void paint(Graphics2D g2, Node item, Justification justification, Rectangle2D bounds) { + Tree tree = treePane.getTree(); + + if (TreePane.DEBUG_OUTLINE) { + g2.setPaint(Color.red); + g2.draw(bounds); + } + + String label = getLabel(tree, item); + + Font oldFont = g2.getFont(); + + Paint backgroundPaint = getBackground(); + Paint borderPaint = getBorderPaint(); + Stroke borderStroke = getBorderStroke(); + + if (borderDecorator != null) { + backgroundPaint = borderDecorator.getPaint(backgroundPaint); + borderPaint = borderDecorator.getPaint(borderPaint); + borderStroke = borderDecorator.getStroke(borderStroke); + } + + if (backgroundPaint != null) { + g2.setPaint(backgroundPaint); + g2.fill(bounds); + } + + if (borderPaint != null && borderStroke != null) { + g2.setPaint(borderPaint); + g2.setStroke(borderStroke); + g2.draw(bounds); + } + + if (textDecorator != null) { + g2.setPaint(textDecorator.getPaint(getForeground())); + g2.setFont(textDecorator.getFont(getFont())); + } else { + g2.setPaint(getForeground()); + g2.setFont(getFont()); + } + + if (label != null) { + + Rectangle2D rect = null; + if (justification == Justification.CENTER || justification == Justification.RIGHT) + rect = g2.getFontMetrics().getStringBounds(label, g2); + + float xOffset; + float y = yOffset + (float) bounds.getY(); + switch (justification) { + case CENTER: + xOffset = (float)(-rect.getWidth()/2.0); + y = yOffset + (float) rect.getY(); //xOffset = (float) (bounds.getX() + (bounds.getWidth() - rect.getWidth()) / 2.0); - break; - case FLUSH: - case LEFT: - xOffset = (float) bounds.getX(); - break; - case RIGHT: - xOffset = (float) (bounds.getX() + bounds.getWidth() - rect.getWidth()); - break; - default: - throw new IllegalArgumentException("Unrecognized alignment enum option"); - } - - g2.drawString(label, xOffset, y); - } - - g2.setFont(oldFont); - } - - public String[] getAttributes() { - return attributes; - } + break; + case FLUSH: + case LEFT: + xOffset = (float) bounds.getX(); + break; + case RIGHT: + xOffset = (float) (bounds.getX() + bounds.getWidth() - rect.getWidth()); + break; + default: + throw new IllegalArgumentException("Unrecognized alignment enum option"); + } + + g2.drawString(label, xOffset, y); + } + + g2.setFont(oldFont); + } + + public String[] getAttributes() { + return attributes; + } public String getDisplayAttribute() { return displayAttribute; } public void setDisplayAttribute(String displayAttribute) { - this.displayAttribute = displayAttribute; - firePainterChanged(); - } - - private PainterIntent intent; + this.displayAttribute = displayAttribute; + firePainterChanged(); + } - private double preferredWidth; - private double preferredHeight; - private float yOffset; + private double preferredWidth; + private double preferredHeight; + private float yOffset; - protected String displayAttribute; - protected String[] attributes; + protected String displayAttribute; + protected String[] attributes; - protected TreePane treePane; + protected TreePane treePane; - private Decorator textDecorator = null; - private Decorator borderDecorator = null; + private Decorator textDecorator = null; + private Decorator borderDecorator = null; } \ No newline at end of file diff -Nru figtree-1.4.2+dfsg/src/figtree/panel/TreeAppearanceController.java figtree-1.4.3+dfsg/src/figtree/panel/TreeAppearanceController.java --- figtree-1.4.2+dfsg/src/figtree/panel/TreeAppearanceController.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/panel/TreeAppearanceController.java 2016-10-04 14:24:27.000000000 +0000 @@ -20,6 +20,7 @@ package figtree.panel; +import jebl.evolution.trees.SortedRootedTree; import jebl.evolution.trees.Tree; import jebl.evolution.graphs.Node; import figtree.treeviewer.TreeViewer; @@ -94,7 +95,7 @@ final LabelPainter nodeLabelPainter, String branchKey, final LabelPainter branchLabelPainter) { - this(treeViewer, tipKey, tipLabelPainter, nodeKey, nodeLabelPainter, branchKey, branchLabelPainter, true); + this(treeViewer, tipKey, tipLabelPainter, nodeKey, nodeLabelPainter, branchKey, branchLabelPainter, true, false); } public TreeAppearanceController(final TreeViewer treeViewer, @@ -104,7 +105,8 @@ final LabelPainter nodeLabelPainter, String branchKey, final LabelPainter branchLabelPainter, - boolean hideColouring) { + boolean hideColouring, + boolean ordering) { this.treeViewer = treeViewer; this.hideColouring = hideColouring; @@ -247,7 +249,30 @@ } }); } - } + + if (ordering) { + orderCombo = new JComboBox(new String[]{"Off", + SortedRootedTree.BranchOrdering.INCREASING_NODE_DENSITY.toString(), + SortedRootedTree.BranchOrdering.DECREASING_NODE_DENSITY.toString()}); + orderCombo.setOpaque(false); + orderCombo.setSelectedItem(treeViewer.isOrderBranchesOn() ? + treeViewer.getBranchOrdering().ordinal() + 1 : 0); + orderCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent itemEvent) { + if (orderCombo.getSelectedIndex() == 0) { + treeViewer.setOrderBranchesOn(false); + } else { + treeViewer.setOrderBranchesOn(true); + treeViewer.setBranchOrdering(SortedRootedTree.BranchOrdering.values()[orderCombo.getSelectedIndex() - 1]); + } + } + }); + + optionsPanel.addComponentWithLabel("Order:", orderCombo); + } else { + orderCombo = null; + } + } private void setupAttributes(Collection trees) { Object selected = branchColourAttributeCombo.getSelectedItem(); @@ -361,7 +386,9 @@ private final JSpinner fontSizeSpinner; private final JSpinner digitsSpinner; - private final TreeViewer treeViewer; + private final JComboBox orderCombo; + + private final TreeViewer treeViewer; private final String tipKey; private final String nodeKey; diff -Nru figtree-1.4.2+dfsg/src/figtree/panel/TreesController.java figtree-1.4.3+dfsg/src/figtree/panel/TreesController.java --- figtree-1.4.2+dfsg/src/figtree/panel/TreesController.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/panel/TreesController.java 2016-10-04 14:24:27.000000000 +0000 @@ -60,69 +60,87 @@ public TreesController(final TreeViewer treeViewer) { + this(treeViewer, true, true, true); + } + public TreesController(final TreeViewer treeViewer, + final boolean rooting, + final boolean ordering, + final boolean transforming) { this.treeViewer = treeViewer; titleLabel = new JLabel(CONTROLLER_TITLE); optionsPanel = new OptionsPanel(); - rootingCheck = new JCheckBox("Midpoint root"); - rootingCheck.setOpaque(false); - optionsPanel.addComponent(rootingCheck); - - rootingCheck.setSelected(treeViewer.isRootingOn()); - - rootingCheck.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent actionEvent) { - if (rootingCheck.isSelected()) { - treeViewer.setRootingOn(true); - treeViewer.setRootingType(TreePane.RootingType.MID_POINT); - } else { - treeViewer.setRootingOn(false); - treeViewer.setRootingType(TreePane.RootingType.USER_ROOTING); - } - - } - }); + if (rooting) { + rootingCheck = new JCheckBox("Midpoint root"); + rootingCheck.setOpaque(false); + optionsPanel.addComponent(rootingCheck); + + rootingCheck.setSelected(treeViewer.isRootingOn()); + + rootingCheck.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + if (rootingCheck.isSelected()) { + treeViewer.setRootingOn(true); + treeViewer.setRootingType(TreePane.RootingType.MID_POINT); + } else { + treeViewer.setRootingOn(false); + treeViewer.setRootingType(TreePane.RootingType.USER_ROOTING); + } - orderCombo = new JComboBox(new String[] {"Off", - SortedRootedTree.BranchOrdering.INCREASING_NODE_DENSITY.toString(), - SortedRootedTree.BranchOrdering.DECREASING_NODE_DENSITY.toString()}); - orderCombo.setOpaque(false); - orderCombo.setSelectedItem(treeViewer.isOrderBranchesOn() ? - treeViewer.getBranchOrdering().ordinal() + 1 : 0); - orderCombo.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent itemEvent) { - if (orderCombo.getSelectedIndex() == 0) { - treeViewer.setOrderBranchesOn(false); - } else { - treeViewer.setOrderBranchesOn(true); - treeViewer.setBranchOrdering(SortedRootedTree.BranchOrdering.values()[orderCombo.getSelectedIndex() - 1]); } - } - }); - - optionsPanel.addComponentWithLabel("Order:", orderCombo); + }); + } else { + rootingCheck = null; + } + + if (ordering) { + orderCombo = new JComboBox(new String[]{"Off", + SortedRootedTree.BranchOrdering.INCREASING_NODE_DENSITY.toString(), + SortedRootedTree.BranchOrdering.DECREASING_NODE_DENSITY.toString()}); + orderCombo.setOpaque(false); + orderCombo.setSelectedItem(treeViewer.isOrderBranchesOn() ? + treeViewer.getBranchOrdering().ordinal() + 1 : 0); + orderCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent itemEvent) { + if (orderCombo.getSelectedIndex() == 0) { + treeViewer.setOrderBranchesOn(false); + } else { + treeViewer.setOrderBranchesOn(true); + treeViewer.setBranchOrdering(SortedRootedTree.BranchOrdering.values()[orderCombo.getSelectedIndex() - 1]); + } + } + }); - transformCombo = new JComboBox(new String[] {"Off", - TransformedRootedTree.Transform.CLADOGRAM.toString(), - TransformedRootedTree.Transform.PROPORTIONAL.toString(), - TransformedRootedTree.Transform.EQUAL_LENGTHS.toString()}); - transformCombo.setOpaque(false); - transformCombo.setSelectedItem(treeViewer.isOrderBranchesOn() ? - treeViewer.getBranchTransform().ordinal() + 1 : 0); - transformCombo.addItemListener(new ItemListener() { - public void itemStateChanged(ItemEvent itemEvent) { - if (transformCombo.getSelectedIndex() == 0) { - treeViewer.setTransformBranchesOn(false); - } else { - treeViewer.setTransformBranchesOn(true); - treeViewer.setBranchTransform(TransformedRootedTree.Transform.values()[transformCombo.getSelectedIndex() - 1]); + optionsPanel.addComponentWithLabel("Order:", orderCombo); + } else { + orderCombo = null; + } + + if (transforming) { + transformCombo = new JComboBox(new String[]{"Off", + TransformedRootedTree.Transform.CLADOGRAM.toString(), + TransformedRootedTree.Transform.PROPORTIONAL.toString(), + TransformedRootedTree.Transform.EQUAL_LENGTHS.toString()}); + transformCombo.setOpaque(false); + transformCombo.setSelectedItem(treeViewer.isOrderBranchesOn() ? + treeViewer.getBranchTransform().ordinal() + 1 : 0); + transformCombo.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent itemEvent) { + if (transformCombo.getSelectedIndex() == 0) { + treeViewer.setTransformBranchesOn(false); + } else { + treeViewer.setTransformBranchesOn(true); + treeViewer.setBranchTransform(TransformedRootedTree.Transform.values()[transformCombo.getSelectedIndex() - 1]); + } } - } - }); - optionsPanel.addComponentWithLabel("Transform:", transformCombo); + }); + optionsPanel.addComponentWithLabel("Transform:", transformCombo); + } else { + transformCombo = null; + } } public JComponent getTitleComponent() { diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/decorators/ContinuousScale.java figtree-1.4.3+dfsg/src/figtree/treeviewer/decorators/ContinuousScale.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/decorators/ContinuousScale.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/decorators/ContinuousScale.java 2016-10-04 14:24:27.000000000 +0000 @@ -43,7 +43,7 @@ */ public ContinuousScale(String settings) { if (settings.startsWith("{")) { - settings = settings.substring(1, settings.length()); + settings = settings.substring(1, settings.length()); } if (settings.endsWith("}")) { settings = settings.substring(0, settings.length() - 1); @@ -88,47 +88,46 @@ // First collect the set of all attribute values Set values = new TreeSet(); - for (Attributable item : items) { - Object value = item.getAttribute(attributeName); - if (value != null) { - values.add(value); - } - } boolean isNumber = true; // Find the range of numbers - for (Object value : values) { - double realValue = -1.0; + for (Attributable item : items) { + Object value = item.getAttribute(attributeName); + if (value != null) { - if (value instanceof Boolean) { - realValue = ((Boolean)value ? 1 : 0); - } else if (value instanceof Number) { - realValue = ((Number)value).doubleValue(); - } else if (value instanceof String) { - // it is a string but it could still code for - // a boolean, integer or real - if (value.toString().equalsIgnoreCase("true")) { - realValue = 1; - } else if (value.toString().equalsIgnoreCase("false")) { - realValue = 0; - } else { - try { - realValue = Double.parseDouble(value.toString()); - } catch(NumberFormatException nfe) { - isNumber = false; + double realValue = -1.0; + + if (value instanceof Boolean) { + realValue = ((Boolean)value ? 1 : 0); + } else if (value instanceof Number) { + realValue = ((Number)value).doubleValue(); + } else if (value instanceof String) { + // it is a string but it could still code for + // a boolean, integer or real + if (value.toString().equalsIgnoreCase("true")) { + realValue = 1; + } else if (value.toString().equalsIgnoreCase("false")) { + realValue = 0; + } else { + try { + realValue = Double.parseDouble(value.toString()); + } catch(NumberFormatException nfe) { + isNumber = false; + } } } - } - if (isNumber) { - if (realValue < minValue) { - minValue = realValue; - } - if (realValue > maxValue) { - maxValue = realValue; - } + if (isNumber) { + if (realValue < minValue) { + minValue = realValue; + } + if (realValue > maxValue) { + maxValue = realValue; + } + } + values.add(realValue); } } diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/DefaultTreeViewer.java figtree-1.4.3+dfsg/src/figtree/treeviewer/DefaultTreeViewer.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/DefaultTreeViewer.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/DefaultTreeViewer.java 2016-10-04 14:24:27.000000000 +0000 @@ -274,6 +274,10 @@ return treePane.getSelectedTips(); } + public Set getSelectedTaxa() { + return treePane.getSelectedTaxa(); + } + /** * Select taxa with a search string matching the currently displayed attribute * @param searchType @@ -288,6 +292,8 @@ } selectTaxa(attributeName, searchType, searchString, caseSensitive); + + scrollToSelectedTips(); } public void selectTaxa(String attributeName, TextSearchType searchType, String searchString, boolean caseSensitive) { @@ -504,6 +510,14 @@ return false; } + public void scrollToSelectedTips() { + Set selectedTips = treePane.getSelectedTips(); + if (selectedTips.size() > 0) { + Point point = treePane.getLocationOfTip(selectedTips.iterator().next()); + treePane.scrollPointToVisible(point); + } + } + public void cartoonSelectedNodes() { treePane.cartoonSelectedNodes(); fireTreeSettingsChanged(); @@ -591,6 +605,11 @@ treePane.removeTreeSelectionListener(treeSelectionListener); } + public TreePaneSelector.SelectionMode getSelectionMode() { + return treePaneSelector.getSelectionMode(); + } + + public void setSelectionMode(TreePaneSelector.SelectionMode selectionMode) { TreePaneSelector.SelectionMode oldSelectionMode = treePaneSelector.getSelectionMode(); @@ -629,6 +648,10 @@ // nodeBarPainter.setupAttributes(trees); } + public void setTipShapePainter(NodeShapePainter tipShapePainter) { + treePane.setTipShapePainter(tipShapePainter); + } + public void setNodeShapePainter(NodeShapePainter nodeShapePainter) { treePane.setNodeShapePainter(nodeShapePainter); } diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/LegendPainter.java figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/LegendPainter.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/LegendPainter.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/LegendPainter.java 2016-10-04 14:24:27.000000000 +0000 @@ -122,6 +122,11 @@ } String attribute = colourDecorator.getAttributeName(); + if (TreePane.DEBUG_OUTLINE) { + g2.setPaint(Color.red); + g2.draw(bounds); + } + Font oldFont = g2.getFont(); Paint oldPaint = g2.getPaint(); Stroke oldStroke = g2.getStroke(); diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/NodeBarController.java figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/NodeBarController.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/NodeBarController.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/NodeBarController.java 2016-10-04 14:24:27.000000000 +0000 @@ -50,7 +50,7 @@ */ public class NodeBarController extends AbstractController { - private static Preferences PREFS = Preferences.userNodeForPackage(NodeBarController.class); + private static Preferences PREFS = Preferences.userNodeForPackage(TreeViewer.class); private static final String NODE_BARS_KEY = "nodeBars"; public static final String DISPLAY_ATTRIBUTE_KEY = "displayAttribute"; diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/NodeShapeController.java figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/NodeShapeController.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/NodeShapeController.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/NodeShapeController.java 2016-10-04 14:24:27.000000000 +0000 @@ -24,12 +24,12 @@ import figtree.treeviewer.TreeViewer; import figtree.treeviewer.decorators.Decorator; import jam.controlpalettes.AbstractController; -import jam.controlpalettes.ControllerListener; import jam.panels.OptionsPanel; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Map; @@ -49,8 +49,14 @@ */ public class NodeShapeController extends AbstractController { - private static Preferences PREFS = Preferences.userNodeForPackage(NodeBarController.class); + public enum NodeType { + INTERNAL, EXTERNAL, BOTH + } + + private static Preferences PREFS = Preferences.userNodeForPackage(TreeViewer.class); + private static final String IS_EXTERNAL = "isExternal"; + private static final String IS_INTERNAL = "isInternal"; private static final String NODE_SHAPE_KEY = "nodeShape"; public static final String SHAPE_TYPE_KEY = "shapeType"; public static final String SCALE_TYPE_KEY = "scaleType"; @@ -59,18 +65,19 @@ private static final String SHAPE_SIZE_KEY = "size"; private static final String SHAPE_MIN_SIZE_KEY = "minSize"; - public NodeShapeController(String title, final NodeShapePainter nodeShapePainter, + public NodeShapeController(final String title, final NodeType type, final NodeShapePainter nodeShapePainter, final AttributeColourController colourController, final TreeViewer treeViewer) { this.title = title; - this.nodeShapePainter = nodeShapePainter; + + this.type = type; final float defaultShapeSize = PREFS.getFloat(SHAPE_SIZE_KEY, (float)NodeShapePainter.MAX_SIZE); optionsPanel = new ControllerOptionsPanel(2, 2); titleCheckBox = new JCheckBox(getTitle()); - titleCheckBox.setSelected(this.nodeShapePainter.isVisible()); + titleCheckBox.setSelected(nodeShapePainter.isVisible()); titleCheckBox.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent changeEvent) { @@ -79,6 +86,35 @@ } }); + final ControllerOptionsPanel nodeCheckPanel; + if (type == NodeType.BOTH) { + externalNodeCheck = new JCheckBox("external"); + internalNodeCheck = new JCheckBox("internal"); + ActionListener listener = new ActionListener() { + public void actionPerformed(ActionEvent event) { + nodeShapePainter.setNodeType(externalNodeCheck.isSelected(), internalNodeCheck.isSelected()); + } + }; + externalNodeCheck.addActionListener(listener); + internalNodeCheck.addActionListener(listener); + nodeCheckPanel = new ControllerOptionsPanel(2, 2); + nodeCheckPanel.setBorder(BorderFactory.createEmptyBorder()); + nodeCheckPanel.addSpanningComponent(externalNodeCheck); + nodeCheckPanel.addSpanningComponent(internalNodeCheck); + + externalNodeCheck.setSelected(nodeShapePainter.isExternal()); + internalNodeCheck.setSelected(nodeShapePainter.isInternal()); + } else { + nodeCheckPanel = null; + externalNodeCheck = null; + internalNodeCheck = null; + if (type == NodeType.EXTERNAL) { + nodeShapePainter.setNodeType(true, false); + } else if (type == NodeType.INTERNAL) { + nodeShapePainter.setNodeType(false, true); + } + } + shapeTypeCombo = new JComboBox(NodeShapePainter.ShapeType.values()); shapeTypeCombo.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { @@ -116,6 +152,33 @@ } }); + outlineStrokeCombo = new JComboBox(new String[] {"None", "0.25", "0.5", "1.0", "2.0", "3.0", "4.0", "5.0"}); + outlineStrokeCombo.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + nodeShapePainter.setOutline((outlineStrokeCombo.getSelectedIndex() == 0 ? 0.0f : + Float.parseFloat(outlineStrokeCombo.getSelectedItem().toString())), + (Paint)outlinePaintCombo.getSelectedItem() + ); + } + }); + + final Paint[] outlinePaints = {Color.black, Color.white}; + outlinePaintCombo = new JComboBox(new String[] {"black", "white"}); + outlinePaintCombo.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent event) { + nodeShapePainter.setOutline((outlineStrokeCombo.getSelectedIndex() == 0 ? 0.0f : + Float.parseFloat(outlineStrokeCombo.getSelectedItem().toString())), + outlinePaints[outlinePaintCombo.getSelectedIndex()] + ); + } + }); + + final JLabel label8; + if (type == NodeType.BOTH) { + label8 = optionsPanel.addComponentWithLabel("Show:", nodeCheckPanel); + } else { + label8 = null; + } final JLabel label1 = optionsPanel.addComponentWithLabel("Shape:", shapeTypeCombo); final JLabel label2 = optionsPanel.addComponentWithLabel("Max size:", shapeSizeSpinner); @@ -126,6 +189,9 @@ final JLabel label6 = optionsPanel.addComponentWithLabel("Colour by:", colourAttributeCombo); final JLabel label7 = optionsPanel.addComponentWithLabel("Setup:", setupColourButton); + final JLabel label9 = optionsPanel.addComponentWithLabel("Outline width:", outlineStrokeCombo); + final JLabel label10 = optionsPanel.addComponentWithLabel("Outline colour:", outlinePaintCombo); + new AttributeComboHelper(colourAttributeCombo, treeViewer, "User selection").addListener(new AttributeComboHelperListener() { @Override public void attributeComboChanged() { @@ -162,6 +228,11 @@ addComponent(label1); addComponent(shapeTypeCombo); + if (type == NodeType.BOTH) { + addComponent(label8); + addComponent(externalNodeCheck); + addComponent(internalNodeCheck); + } addComponent(label2); addComponent(shapeSizeSpinner); addComponent(label3); @@ -174,6 +245,10 @@ addComponent(colourAttributeCombo); addComponent(label7); addComponent(setupColourButton); + addComponent(label9); + addComponent(outlineStrokeCombo); + addComponent(label10); + addComponent(outlinePaintCombo); enableComponents(titleCheckBox.isSelected()); titleCheckBox.addChangeListener(new ChangeListener() { @@ -206,40 +281,55 @@ } public void setSettings(Map settings) { - titleCheckBox.setSelected((Boolean)settings.get(NODE_SHAPE_KEY + "." + IS_SHOWN)); + String key = NODE_SHAPE_KEY + (type == NodeType.INTERNAL ? "Internal" : (type == NodeType.EXTERNAL ? "External" : "")); + + titleCheckBox.setSelected((Boolean)settings.get(key + "." + IS_SHOWN)); - shapeTypeCombo.setSelectedItem((NodeShapePainter.ShapeType.valueOf(settings.get(NODE_SHAPE_KEY + "." + SHAPE_TYPE_KEY).toString().toUpperCase()))); - scaleTypeCombo.setSelectedItem((NodeShapePainter.ScaleType.valueOf(settings.get(NODE_SHAPE_KEY + "." + SCALE_TYPE_KEY).toString().toUpperCase()))); - colourAttributeCombo.setSelectedItem((String) settings.get(NODE_SHAPE_KEY + "." + COLOUR_ATTRIBUTE_KEY)); - sizeAttributeCombo.setSelectedItem((String) settings.get(NODE_SHAPE_KEY + "." + SIZE_ATTRIBUTE_KEY)); - shapeSizeSpinner.setValue((Double)settings.get(NODE_SHAPE_KEY + "." + SHAPE_SIZE_KEY)); - shapeMinSizeSpinner.setValue((Double) settings.get(NODE_SHAPE_KEY + "." + SHAPE_MIN_SIZE_KEY)); + if (type == NodeType.BOTH) { + externalNodeCheck.setSelected((Boolean) settings.get(key + "." + IS_EXTERNAL)); + internalNodeCheck.setSelected((Boolean) settings.get(key + "." + IS_INTERNAL)); + } + shapeTypeCombo.setSelectedItem((NodeShapePainter.ShapeType.valueOf(settings.get(key + "." + SHAPE_TYPE_KEY).toString().toUpperCase()))); + scaleTypeCombo.setSelectedItem((NodeShapePainter.ScaleType.valueOf(settings.get(key + "." + SCALE_TYPE_KEY).toString().toUpperCase()))); + colourAttributeCombo.setSelectedItem((String) settings.get(key + "." + COLOUR_ATTRIBUTE_KEY)); + sizeAttributeCombo.setSelectedItem((String) settings.get(key + "." + SIZE_ATTRIBUTE_KEY)); + shapeSizeSpinner.setValue((Double)settings.get(key + "." + SHAPE_SIZE_KEY)); + shapeMinSizeSpinner.setValue((Double) settings.get(key + "." + SHAPE_MIN_SIZE_KEY)); } public void getSettings(Map settings) { - settings.put(NODE_SHAPE_KEY + "." + IS_SHOWN, titleCheckBox.isSelected()); - settings.put(NODE_SHAPE_KEY + "." + SHAPE_TYPE_KEY, shapeTypeCombo.getSelectedItem()); - settings.put(NODE_SHAPE_KEY + "." + SCALE_TYPE_KEY, scaleTypeCombo.getSelectedItem()); - settings.put(NODE_SHAPE_KEY + "." + COLOUR_ATTRIBUTE_KEY, colourAttributeCombo.getSelectedItem()); - settings.put(NODE_SHAPE_KEY + "." + SIZE_ATTRIBUTE_KEY, sizeAttributeCombo.getSelectedItem()); - settings.put(NODE_SHAPE_KEY + "." + SHAPE_SIZE_KEY, shapeSizeSpinner.getValue()); - settings.put(NODE_SHAPE_KEY + "." + SHAPE_MIN_SIZE_KEY, shapeMinSizeSpinner.getValue()); + String key = NODE_SHAPE_KEY + (type == NodeType.INTERNAL ? "Internal" : (type == NodeType.EXTERNAL ? "External" : "")); + settings.put(key + "." + IS_SHOWN, titleCheckBox.isSelected()); + if (type == NodeType.BOTH) { + settings.put(key + "." + IS_EXTERNAL, externalNodeCheck.isSelected()); + settings.put(key + "." + IS_INTERNAL, internalNodeCheck.isSelected()); + } + settings.put(key + "." + SHAPE_TYPE_KEY, shapeTypeCombo.getSelectedItem()); + settings.put(key + "." + SCALE_TYPE_KEY, scaleTypeCombo.getSelectedItem()); + settings.put(key + "." + COLOUR_ATTRIBUTE_KEY, colourAttributeCombo.getSelectedItem()); + settings.put(key + "." + SIZE_ATTRIBUTE_KEY, sizeAttributeCombo.getSelectedItem()); + settings.put(key + "." + SHAPE_SIZE_KEY, shapeSizeSpinner.getValue()); + settings.put(key + "." + SHAPE_MIN_SIZE_KEY, shapeMinSizeSpinner.getValue()); } private final JCheckBox titleCheckBox; private final OptionsPanel optionsPanel; + private final JCheckBox externalNodeCheck; + private final JCheckBox internalNodeCheck; private final JComboBox shapeTypeCombo; private final JComboBox scaleTypeCombo; private final JComboBox sizeAttributeCombo; private final JComboBox colourAttributeCombo; private final JSpinner shapeSizeSpinner; private final JSpinner shapeMinSizeSpinner; + private final JComboBox outlineStrokeCombo; + private final JComboBox outlinePaintCombo; public String getTitle() { return title; } private final String title; - private final NodeShapePainter nodeShapePainter; + private final NodeType type; } diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/NodeShapePainter.java figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/NodeShapePainter.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/NodeShapePainter.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/NodeShapePainter.java 2016-10-04 14:24:27.000000000 +0000 @@ -117,6 +117,20 @@ firePainterChanged(); } + public void setNodeType(boolean external, boolean internal) { + this.external = external; + this.internal = internal; + firePainterChanged(); + } + + public boolean isExternal() { + return external; + } + + public boolean isInternal() { + return internal; + } + public double getPreferredWidth() { return 1.0; } @@ -147,9 +161,11 @@ g2.setPaint(paint); g2.fill(nodeShape); - g2.setPaint(Color.black); - g2.setStroke(new BasicStroke(0.5F)); - g2.draw(nodeShape); + if (outlineStroke > 0.0F) { + g2.setPaint(outlinePaint); + g2.setStroke(new BasicStroke(outlineStroke)); + g2.draw(nodeShape); + } } /** @@ -184,6 +200,12 @@ firePainterChanged(); } + public void setOutline(final float outlineStroke, final Paint outlinePaint) { + this.outlineStroke = outlineStroke; + this.outlinePaint = outlinePaint; + firePainterChanged(); + } + private Shape createNodeShape(Node node, double x, double y) { double size = maxSize; @@ -247,8 +269,14 @@ private ScaleType scaleType = ScaleType.WIDTH; private String sizeAttribute = null; + private boolean external = true; + private boolean internal = true; + private Decorator colourDecorator = null; private ContinuousScale sizeScale = null; + private float outlineStroke = 0.5f; + private Paint outlinePaint = Color.black; + private TreePane treePane; } diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/ScaleAxisPainterController.java figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/ScaleAxisPainterController.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/ScaleAxisPainterController.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/ScaleAxisPainterController.java 2016-10-04 14:24:27.000000000 +0000 @@ -314,7 +314,7 @@ titleCheckBox.setSelected((Boolean)settings.get(SCALE_AXIS_KEY + "." + IS_SHOWN)); reverseAxisCheck.setSelected((Boolean)settings.get(SCALE_AXIS_KEY + "." + REVERSE_AXIS_KEY)); showGridCheck.setSelected((Boolean)settings.get(SCALE_AXIS_KEY + "." + SHOW_GRID_KEY)); -// minorTicksText.setValue((Double)settings.get(SCALE_AXIS_KEY + "." + MINOR_TICKS_KEY)); + minorTicksText.setValue((Double)settings.get(SCALE_AXIS_KEY + "." + MINOR_TICKS_KEY)); majorTicksText.setValue((Double)settings.get(SCALE_AXIS_KEY + "." + MAJOR_TICKS_KEY)); originText.setValue((Double)settings.get(SCALE_AXIS_KEY + "." + ORIGIN_KEY)); autoScaleCheck.setSelected((Boolean)settings.get(SCALE_AXIS_KEY + "." + AUTOMATIC_SCALE_KEY)); @@ -329,7 +329,7 @@ settings.put(SCALE_AXIS_KEY + "." + REVERSE_AXIS_KEY, reverseAxisCheck.isSelected()); settings.put(SCALE_AXIS_KEY + "." + SHOW_GRID_KEY, showGridCheck.isSelected()); settings.put(SCALE_AXIS_KEY + "." + AUTOMATIC_SCALE_KEY, autoScaleCheck.isSelected()); -// settings.put(SCALE_AXIS_KEY + "." + MINOR_TICKS_KEY, minorTicksText.getValue()); + settings.put(SCALE_AXIS_KEY + "." + MINOR_TICKS_KEY, minorTicksText.getValue()); settings.put(SCALE_AXIS_KEY + "." + MAJOR_TICKS_KEY, majorTicksText.getValue()); settings.put(SCALE_AXIS_KEY + "." + ORIGIN_KEY, originText.getValue()); settings.put(SCALE_AXIS_KEY + "." + FONT_SIZE_KEY, fontSizeSpinner.getValue()); diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/ScaleAxisPainter.java figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/ScaleAxisPainter.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/ScaleAxisPainter.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/ScaleAxisPainter.java 2016-10-04 14:24:27.000000000 +0000 @@ -192,55 +192,55 @@ protected void paintAxis(Graphics2D g2, Rectangle2D axisBounds) { - ScaleAxis axis = treePane.getScaleAxis(); + ScaleAxis axis = treePane.getScaleAxis(); - g2.setPaint(getForeground()); - g2.setStroke(getScaleBarStroke()); + g2.setPaint(getForeground()); + g2.setStroke(getScaleBarStroke()); - double minX = treePane.scaleOnAxis(axis.getMinAxis()); - double maxX = treePane.scaleOnAxis(axis.getMaxAxis()); + double minX = treePane.scaleOnAxis(axis.getMinAxis()); + double maxX = treePane.scaleOnAxis(axis.getMaxAxis()); - Line2D line = new Line2D.Double(minX, axisBounds.getMinY(), maxX, axisBounds.getMinY()); - g2.draw(line); + Line2D line = new Line2D.Double(minX, axisBounds.getY() + topMargin, maxX, axisBounds.getY() + topMargin); + g2.draw(line); - int n1 = axis.getMajorTickCount(); - int n2, i, j; + int n1 = axis.getMajorTickCount(); + int n2, i, j; - n2 = axis.getMinorTickCount(-1); - if (axis.getLabelFirst()) { // Draw first minor tick as a major one (with a label) + n2 = axis.getMinorTickCount(-1); + if (axis.getLabelFirst()) { // Draw first minor tick as a major one (with a label) - paintMajorTick(g2, axisBounds, axis, axis.getMinorTickValue(0, -1)); + paintMajorTick(g2, axisBounds, axis, axis.getMinorTickValue(0, -1)); - for (j = 1; j < n2; j++) { - paintMinorTick(g2, axisBounds, axis.getMinorTickValue(j, -1)); - } - } else { + for (j = 1; j < n2; j++) { + paintMinorTick(g2, axisBounds, axis.getMinorTickValue(j, -1)); + } + } else { - for (j = 0; j < n2; j++) { - paintMinorTick(g2, axisBounds, axis.getMinorTickValue(j, -1)); - } - } + for (j = 0; j < n2; j++) { + paintMinorTick(g2, axisBounds, axis.getMinorTickValue(j, -1)); + } + } - for (i = 0; i < n1; i++) { + for (i = 0; i < n1; i++) { - paintMajorTick(g2, axisBounds, axis, axis.getMajorTickValue(i)); - n2 = axis.getMinorTickCount(i); + paintMajorTick(g2, axisBounds, axis, axis.getMajorTickValue(i)); + n2 = axis.getMinorTickCount(i); - if (i == (n1-1) && axis.getLabelLast()) { // Draw last minor tick as a major one + if (i == (n1-1) && axis.getLabelLast()) { // Draw last minor tick as a major one - paintMajorTick(g2, axisBounds, axis, axis.getMinorTickValue(0, i)); + paintMajorTick(g2, axisBounds, axis, axis.getMinorTickValue(0, i)); - for (j = 1; j < n2; j++) { - paintMinorTick(g2, axisBounds, axis.getMinorTickValue(j, i)); - } - } else { + for (j = 1; j < n2; j++) { + paintMinorTick(g2, axisBounds, axis.getMinorTickValue(j, i)); + } + } else { - for (j = 0; j < n2; j++) { - paintMinorTick(g2, axisBounds, axis.getMinorTickValue(j, i)); - } - } - } - } + for (j = 0; j < n2; j++) { + paintMinorTick(g2, axisBounds, axis.getMinorTickValue(j, i)); + } + } + } + } protected void paintMajorTick(Graphics2D g2, Rectangle2D axisBounds, ScaleAxis axis, double value) { @@ -251,12 +251,12 @@ String label = getNumberFormat().format(value); double pos = treePane.scaleOnAxis(value); - Line2D line = new Line2D.Double(pos, axisBounds.getMinY(), pos, axisBounds.getMinY() + majorTickSize); + Line2D line = new Line2D.Double(pos, axisBounds.getMinY() + topMargin, pos, axisBounds.getMinY() + majorTickSize + topMargin); g2.draw(line); g2.setPaint(getForeground()); double width = g2.getFontMetrics().stringWidth(label); - g2.drawString(label, (float)(pos - (width / 2)), (float)(axisBounds.getMinY() + tickLabelOffset)); + g2.drawString(label, (float)(pos - (width / 2)), (float)(axisBounds.getMinY() + tickLabelOffset + topMargin)); } protected void paintMinorTick(Graphics2D g2, Rectangle2D axisBounds, double value) @@ -267,7 +267,7 @@ double pos = treePane.scaleOnAxis(value); - Line2D line = new Line2D.Double(pos, axisBounds.getMinY(), pos, axisBounds.getMinY() + minorTickSize); + Line2D line = new Line2D.Double(pos, axisBounds.getMinY() + topMargin, pos, axisBounds.getMinY() + minorTickSize + topMargin); g2.draw(line); } diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/ScaleGridPainter.java figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/ScaleGridPainter.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/painters/ScaleGridPainter.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/painters/ScaleGridPainter.java 2016-10-04 14:24:27.000000000 +0000 @@ -57,7 +57,7 @@ preferredWidth = treePane.getTreeBounds().getWidth(); preferredHeight = treePane.getTreeBounds().getHeight(); - return new Rectangle2D.Double(0.0, 0.0, preferredWidth, preferredHeight); + return new Rectangle2D.Double(0.0, 0.0, preferredWidth, preferredHeight); } public void paint(Graphics2D g2, TreePane treePane, Justification justification, Rectangle2D bounds) { @@ -66,7 +66,7 @@ Stroke oldStroke = g2.getStroke(); if (TreePane.DEBUG_OUTLINE) { - g2.setPaint(Color.red); + g2.setPaint(Color.blue); g2.draw(bounds); } diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/ScaleAxis.java figtree-1.4.3+dfsg/src/figtree/treeviewer/ScaleAxis.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/ScaleAxis.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/ScaleAxis.java 2016-10-04 14:24:27.000000000 +0000 @@ -666,6 +666,10 @@ if (!isCalibrated) calibrate(); + if (minorTick <= 0) { + return 0; + } + if (majorTickIndex == majorTickCount-1) return (int)((maxAxis-maxTick)/minorTick); else if (majorTickIndex==-1) diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/TimeScale.java figtree-1.4.3+dfsg/src/figtree/treeviewer/TimeScale.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/TimeScale.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/TimeScale.java 2016-10-04 14:24:27.000000000 +0000 @@ -34,7 +34,9 @@ */ public class TimeScale { - public TimeScale(double rootAge) { + private boolean isReversed = false; + + public TimeScale(double rootAge) { this.rootAge = rootAge; this.scaleFactor = Double.NaN; this.offsetAge = 0.0; @@ -50,7 +52,7 @@ if (Double.isNaN(scaleFactor)) { return rootAge / tree.getHeight(tree.getRootNode()); } - return scaleFactor; + return scaleFactor * (isReversed ? -1.0 : 1.0); } public double getAge(double height, RootedTree tree) { @@ -71,7 +73,12 @@ return (time / getScaleFactor(tree)); } - private final double rootAge; + public void setReversed(boolean isReversed) { + this.isReversed = isReversed; + } + + private final double rootAge; private final double offsetAge; private final double scaleFactor; + } diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/treelayouts/AbstractTreeLayout.java figtree-1.4.3+dfsg/src/figtree/treeviewer/treelayouts/AbstractTreeLayout.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/treelayouts/AbstractTreeLayout.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/treelayouts/AbstractTreeLayout.java 2016-10-04 14:24:27.000000000 +0000 @@ -35,15 +35,6 @@ */ public abstract class AbstractTreeLayout implements TreeLayout { private double rootLength = 0.0; - private boolean isAxisReversed; - - public boolean isAxisReversed() { - return isAxisReversed; - } - - public void setAxisReversed(final boolean axisReversed) { - isAxisReversed = axisReversed; - } public double getRootLength() { return rootLength; diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/treelayouts/PolarTreeLayout.java figtree-1.4.3+dfsg/src/figtree/treeviewer/treelayouts/PolarTreeLayout.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/treelayouts/PolarTreeLayout.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/treelayouts/PolarTreeLayout.java 2016-10-04 14:24:27.000000000 +0000 @@ -93,9 +93,6 @@ public Shape getAxisLine(double height) { double x = height; - if (isAxisReversed()) { - x = maxXPosition - x; - } return new Ellipse2D.Double(-x, -x, x * 2.0, x * 2.0); } diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/treelayouts/RectilinearTreeLayout.java figtree-1.4.3+dfsg/src/figtree/treeviewer/treelayouts/RectilinearTreeLayout.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/treelayouts/RectilinearTreeLayout.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/treelayouts/RectilinearTreeLayout.java 2016-10-04 14:24:27.000000000 +0000 @@ -85,9 +85,6 @@ public Shape getAxisLine(double height) { double x = height; - if (isAxisReversed()) { - x = maxXPosition - x; - } double y1 = 0.0; double y2 = 1.0; return new Line2D.Double(x, y1, x, y2); @@ -95,9 +92,6 @@ public Shape getHeightArea(double height1, double height2) { double x = height1; - if (isAxisReversed()) { - x = maxXPosition - x; - } double y = 0.0; double w = Math.abs(height2 - height1); double h = 1.0; diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/treelayouts/TreeLayout.java figtree-1.4.3+dfsg/src/figtree/treeviewer/treelayouts/TreeLayout.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/treelayouts/TreeLayout.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/treelayouts/TreeLayout.java 2016-10-04 14:24:27.000000000 +0000 @@ -82,11 +82,6 @@ void setRootLength(double rootLength); - boolean isAxisReversed(); - - void setAxisReversed(final boolean axisReversed); - - /** * Return whether this layout is showing a branch colouring * @return showing colouring? diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/TreePane.java figtree-1.4.3+dfsg/src/figtree/treeviewer/TreePane.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/TreePane.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/TreePane.java 2016-10-04 14:24:27.000000000 +0000 @@ -33,7 +33,6 @@ import java.awt.*; import java.awt.geom.*; import java.awt.print.*; -import java.io.IOException; import java.util.*; import java.util.List; @@ -48,6 +47,8 @@ * $LastChangedRevision$ */ public class TreePane extends JComponent implements PainterListener, Printable { + public final static boolean DEBUG_OUTLINE = false; + public enum RootingType { USER_ROOTING("User Selection"), MID_POINT("Midpoint"); @@ -63,8 +64,6 @@ } - public final static boolean DEBUG_OUTLINE = false; - public final String CARTOON_ATTRIBUTE_NAME = "!cartoon"; public final String COLLAPSE_ATTRIBUTE_NAME = "!collapse"; public final String HILIGHT_ATTRIBUTE_NAME = "!hilight"; @@ -91,12 +90,16 @@ } } + private void recalibrate() { + calibrated = false; + } + private void setupTree() { tree = constructTransformedTree(originalTree); recalculateCollapsedNodes(); - calibrated = false; + recalibrate(); invalidate(); repaint(); } @@ -152,11 +155,11 @@ treeLayout.addTreeLayoutListener(new TreeLayoutListener() { public void treeLayoutChanged() { - calibrated = false; + recalibrate(); repaint(); } }); - calibrated = false; + recalibrate(); invalidate(); repaint(); } @@ -167,7 +170,8 @@ public void setTimeScale(TimeScale timeScale) { this.timeScale = timeScale; - calibrated = false; + this.timeScale.setReversed(isAxisReversed()); + recalibrate(); repaint(); } @@ -233,7 +237,7 @@ } node.setAttribute("!rotate", rotate); - calibrated = false; + recalibrate(); invalidate(); repaint(); } @@ -247,7 +251,7 @@ node.removeAttribute("!rotate"); } - calibrated = false; + recalibrate(); invalidate(); repaint(); } @@ -300,14 +304,19 @@ */ public double scaleOnAxis(double value) { double height = timeScale.getHeight(value, tree); - if (treeLayout.isAxisReversed()) { - return treeBounds.getX() + treeBounds.getWidth() - (height * treeScale); + if (isAxisReversed()) { + return (treeBounds.getX() + treeBounds.getWidth()) - (height * treeScale); } else { return treeBounds.getX() + (height * treeScale); } } public Shape getAxisLine(double value) { + if (isAxisReversed()) { + value = maxTreeHeight - value; + } else { + value -= rootHeightOffset; + } double height = timeScale.getHeight(value, tree); Shape line = treeLayout.getAxisLine(height); if (line != null) { @@ -327,16 +336,21 @@ public void setAxisOrigin(double axisOrigin) { this.axisOrigin = axisOrigin; - calibrated = false; + recalibrate(); repaint(); } public void setAxisReversed(final boolean isAxisReversed) { - treeLayout.setAxisReversed(isAxisReversed); - calibrated = false; + this.isAxisReversed = isAxisReversed; + this.timeScale.setReversed(isAxisReversed()); + recalibrate(); repaint(); } + public boolean isAxisReversed() { + return isAxisReversed; + } + private void setupScaleAxis() { double minValue = timeScale.getAge(0.0, tree); double maxValue = timeScale.getAge(maxTreeHeight, tree); @@ -357,7 +371,7 @@ public void setRootAge(double rootAge) { double rootLength = timeScale.getHeight(rootAge, tree) - tree.getHeight(tree.getRootNode()); treeLayout.setRootLength(rootLength); - calibrated = false; + recalibrate(); repaint(); } @@ -376,28 +390,28 @@ public void setTickSpacing(double userMajorTickSpacing, double userMinorTickSpacing) { scaleAxis.setManualAxis(userMajorTickSpacing, userMinorTickSpacing); - calibrated = false; + recalibrate(); repaint(); } public void setAutomaticScale() { scaleAxis.setAutomatic(); - calibrated = false; + recalibrate(); repaint(); } public void painterChanged() { - calibrated = false; + recalibrate(); repaint(); } public void painterSettingsChanged() { - calibrated = false; + recalibrate(); repaint(); } public void attributesChanged() { - calibrated = false; + recalibrate(); repaint(); } @@ -496,7 +510,7 @@ public void setShowingTipCallouts(boolean showingTipCallouts) { this.showingTipCallouts = showingTipCallouts; - calibrated = false; + recalibrate(); repaint(); } @@ -720,7 +734,7 @@ Object[] values = new Object[] { tipCount, height }; node.setAttribute(CARTOON_ATTRIBUTE_NAME, values); } - calibrated = false; + recalibrate(); repaint(); } else { for (Node child : tree.getChildren(node)) { @@ -746,7 +760,7 @@ Object[] values = new Object[] { tipName, height }; node.setAttribute(COLLAPSE_ATTRIBUTE_NAME, values); } - calibrated = false; + recalibrate(); repaint(); } else { for (Node child : tree.getChildren(node)) { @@ -769,7 +783,7 @@ Object[] values = new Object[] { tipCount, height, color }; node.setAttribute(HILIGHT_ATTRIBUTE_NAME, values); - calibrated = false; + recalibrate(); repaint(); } else { for (Node child : tree.getChildren(node)) { @@ -806,7 +820,7 @@ Object[] values = new Object[] { tipCount, height, oldValues[2] }; node.setAttribute(HILIGHT_ATTRIBUTE_NAME, values); } - calibrated = false; + recalibrate(); repaint(); } else { for (Node child : tree.getChildren(node)) { @@ -828,7 +842,7 @@ node.removeAttribute(CARTOON_ATTRIBUTE_NAME); } } - calibrated = false; + recalibrate(); repaint(); } } @@ -846,7 +860,7 @@ if (node.getAttribute(CARTOON_ATTRIBUTE_NAME) != null) { node.removeAttribute(CARTOON_ATTRIBUTE_NAME); } - calibrated = false; + recalibrate(); repaint(); } else { for (Node child : tree.getChildren(node)) { @@ -865,7 +879,7 @@ node.removeAttribute(HILIGHT_ATTRIBUTE_NAME); } } - calibrated = false; + recalibrate(); repaint(); } } @@ -876,7 +890,7 @@ if (selectedNodes.size() == 0 || selectedNodes.contains(node)) { if (node.getAttribute(HILIGHT_ATTRIBUTE_NAME) != null) { node.removeAttribute(HILIGHT_ATTRIBUTE_NAME); - calibrated = false; + recalibrate(); repaint(); } } @@ -977,7 +991,7 @@ if (this.tipLabelPainter != null) { this.tipLabelPainter.addPainterListener(this); } - calibrated = false; + recalibrate(); repaint(); } @@ -994,7 +1008,7 @@ if (this.nodeLabelPainter != null) { this.nodeLabelPainter.addPainterListener(this); } - calibrated = false; + recalibrate(); repaint(); } @@ -1011,7 +1025,7 @@ if (this.branchLabelPainter != null) { this.branchLabelPainter.addPainterListener(this); } - calibrated = false; + recalibrate(); repaint(); } @@ -1028,7 +1042,7 @@ if (this.nodeBarPainter != null) { this.nodeBarPainter.addPainterListener(this); } - calibrated = false; + recalibrate(); repaint(); } @@ -1036,6 +1050,22 @@ return nodeBarPainter; } + public void setTipShapePainter(NodeShapePainter tipShapePainter) { + tipShapePainter.setTreePane(this); + if (this.tipShapePainter != null) { + this.tipShapePainter.removePainterListener(this); + } + this.tipShapePainter = tipShapePainter; + if (this.tipShapePainter != null) { + this.tipShapePainter.addPainterListener(this); + } + recalibrate(); + repaint(); + } + + public NodeShapePainter getTipShapePainter() { + return tipShapePainter; + } public void setNodeShapePainter(NodeShapePainter nodeShapePainter) { nodeShapePainter.setTreePane(this); @@ -1046,7 +1076,7 @@ if (this.nodeShapePainter != null) { this.nodeShapePainter.addPainterListener(this); } - calibrated = false; + recalibrate(); repaint(); } @@ -1062,7 +1092,7 @@ scalePainters.add(scalePainter); - calibrated = false; + recalibrate(); repaint(); } @@ -1073,7 +1103,7 @@ scalePainters.remove(scalePainter); - calibrated = false; + recalibrate(); repaint(); } @@ -1086,7 +1116,7 @@ if (this.scaleGridPainter != null) { this.scaleGridPainter.addPainterListener(this); } - calibrated = false; + recalibrate(); repaint(); } @@ -1096,7 +1126,7 @@ this.legendPainter = legendPainter; - calibrated = false; + recalibrate(); repaint(); } @@ -1110,7 +1140,7 @@ public void setLabelSpacing(float labelSpacing) { this.labelXOffset = labelSpacing; - calibrated = false; + recalibrate(); repaint(); } @@ -1121,7 +1151,7 @@ super.setPreferredSize(dimension); } - calibrated = false; + recalibrate(); } public double getHeightAt(Graphics2D graphics2D, Point2D point) { @@ -1135,6 +1165,7 @@ public Node getNodeAt(Graphics2D g2, Point point) { Rectangle rect = new Rectangle(point.x - 1, point.y - 1, 3, 3); + rect.translate(-insets.left, -insets.top); for (Node node : tree.getExternalNodes()) { Shape taxonLabelBound = tipLabelBounds.get(node); @@ -1192,6 +1223,14 @@ return selectedTips; } + public Set getSelectedTaxa() { + Set selectedTaxa = new LinkedHashSet(); + for (Node node : getSelectedTips()) { + selectedTaxa.add(tree.getTaxon(node)); + } + return selectedTaxa; + } + public RootedTree getSelectedSubtree() { if (selectedNodes.size() == 0 && selectedTips.size() == 0) { // nothing selected so return the whole tree @@ -1277,6 +1316,14 @@ this.rulerHeight = rulerHeight; } + public Point getLocationOfTip(Node tip) { + if (tip == null) { + return new Point(0,0); + } + Shape path = transform.createTransformedShape(treeLayoutCache.getTipLabelPath(tip)); + return path.getBounds().getLocation(); + } + public void scrollPointToVisible(Point point) { scrollRectToVisible(new Rectangle(point.x, point.y, 0, 0)); } @@ -1317,13 +1364,15 @@ public void paint(Graphics graphics) { if (tree == null) return; - graphics.setColor(Color.white); - Rectangle r = graphics.getClipBounds(); - if (r != null) { - graphics.fillRect(r.x, r.y, r.width, r.height); - } - +// graphics.setColor(Color.white); +// Rectangle r = graphics.getClipBounds(); +// if (r != null) { +// graphics.fillRect(r.x, r.y, r.width, r.height); +// } +// final Graphics2D g2 = (Graphics2D) graphics; + g2.translate(insets.left, insets.top); + if (!calibrated) { calibrate(g2, getWidth(), getHeight()); } @@ -1402,13 +1451,13 @@ Graphics2D g2 = (Graphics2D) graphics; g2.translate(pageFormat.getImageableX(), pageFormat.getImageableY()); - calibrated = false; + recalibrate(); setDoubleBuffered(false); drawTree(g2, pageFormat.getImageableWidth(), pageFormat.getImageableHeight()); setDoubleBuffered(true); - calibrated = false; + recalibrate(); return PAGE_EXISTS; } @@ -1445,6 +1494,14 @@ } } + if (scaleGridPainter != null && scaleGridPainter.isVisible()) { + Rectangle2D gridBounds = new Rectangle2D.Double( + treeBounds.getX(), 0.0, + treeBounds.getWidth(), treeBounds.getHeight()); + scaleGridPainter.paint(g2, this, null, gridBounds); + } + + // Paint backgrounds if (nodeBackgroundDecorator != null) { for (Node node : treeLayoutCache.getNodeAreaMap().keySet() ) { @@ -1457,7 +1514,7 @@ g2.setPaint(background); g2.fill(transNodePath); -// Experimental outlining - requires order of drawing to be pre-order +// Experimental outlining - requires order of drawing to be pre-order // g2.setStroke(new BasicStroke(8, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND)); // g2.draw(transNodePath); } @@ -1496,15 +1553,8 @@ } } - if (scaleGridPainter != null && scaleGridPainter.isVisible()) { - Rectangle2D gridBounds = new Rectangle2D.Double( - treeBounds.getX(), 0.0, - treeBounds.getWidth(), totalScaleBounds.getY()); - scaleGridPainter.paint(g2, this, null, gridBounds); - } - if (DEBUG_OUTLINE) { - g2.setPaint(Color.red); + g2.setPaint(Color.blue); g2.draw(treeBounds); } @@ -1627,6 +1677,14 @@ } } + if (tipShapePainter != null && tipShapePainter.isVisible()) { + for (Node node : tipPoints.keySet()) { + Point2D point = tipPoints.get(node); + point = transform.transform(point, null); + tipShapePainter.paint(g2, node, point, nodeShapeTransforms.get(node)); + } + } + // Paint tip labels if (tipLabelPainter != null && tipLabelPainter.isVisible()) { @@ -1637,8 +1695,9 @@ Painter.Justification tipLabelJustification = tipLabelJustifications.get(node); g2.transform(tipLabelTransform); + double labelWidth = tipLabelWidths.get(node); tipLabelPainter.paint(g2, node, tipLabelJustification, - new Rectangle2D.Double(0.0, 0.0, tipLabelWidth, tipLabelPainter.getPreferredHeight())); + new Rectangle2D.Double(0.0, 0.0, labelWidth, tipLabelPainter.getPreferredHeight())); g2.setTransform(oldTransform); @@ -1681,10 +1740,7 @@ final double preferredWidth = branchLabelPainter.getPreferredWidth(); final double preferredHeight = branchLabelPainter.getPreferredHeight(); - //Line2D labelPath = treeLayout.getBranchLabelPath(node); - branchLabelPainter.paint(g2, node, Painter.Justification.CENTER, - //new Rectangle2D.Double(-preferredWidth/2, -preferredHeight, preferredWidth, preferredHeight)); new Rectangle2D.Double(0, 0, preferredWidth, preferredHeight)); g2.setTransform(oldTransform); @@ -1702,6 +1758,8 @@ treeLayout.layout(tree, treeLayoutCache); maxTreeHeight = tree.getHeight(tree.getRootNode()) + treeLayout.getRootLength(); + rootHeightOffset = 0.0; + // First of all get the bounds for the unscaled tree treeBounds = null; @@ -1755,6 +1813,7 @@ // bounds on node bars if (!isTransformBranchesOn() && nodeBarPainter != null && nodeBarPainter.isVisible()) { nodeBars.clear(); + // Iterate though the nodes for (Node node : tree.getInternalNodes()) { @@ -1764,24 +1823,29 @@ nodeBars.put(node, nodeBarPainter.getNodeBar()); } } + if (nodeBarPainter.getMaxHeight() > maxTreeHeight) { + rootHeightOffset = Math.max(nodeBarPainter.getMaxHeight() - maxTreeHeight, 0.0); maxTreeHeight = nodeBarPainter.getMaxHeight(); } } + // totalTreeBounds includes all the stuff which is not in a tree scale (like labels and shapes) but in // screen pixel scale. This is added to the treeBounds to make space round the edge. // add the tree bounds - final Rectangle2D totalTreeBounds = treeBounds.getBounds2D(); // (YH) same as (Rectangle2D) treeBounds.clone(); + final Rectangle2D totalTreeBounds = treeBounds.getBounds2D(); +// final Rectangle2D totalTreeBounds = new Rectangle2D.Double(0.0, 0.0,treeBounds.getWidth(),treeBounds.getHeight()); + + tipLabelWidths.clear(); if (tipLabelPainter != null && tipLabelPainter.isVisible()) { - tipLabelWidth = 0.0; - final double tipLabelHeight = tipLabelPainter.getPreferredHeight(); +// calculateMaxTipLabelWidth(g2, tree.getRootNode()); // put this in a recursive function to allow for collapsed node labels - calibrateTipLabels(g2, tree.getRootNode(), tipLabelHeight, totalTreeBounds); + calibrateTipLabels(g2, tree.getRootNode(), totalTreeBounds); } if (nodeLabelPainter != null && nodeLabelPainter.isVisible()) { @@ -1824,10 +1888,24 @@ } // bounds on nodeShapes + if (tipShapePainter != null && tipShapePainter.isVisible()) { + tipPoints.clear(); + // Iterate though the external nodes + for (Node node : tree.getExternalNodes()) { + + Rectangle2D shapeBounds = tipShapePainter.calibrate(g2, node); + if (shapeBounds != null) { + totalTreeBounds.add(shapeBounds); + + // just at the centroid in here as the actual shape will be reconstructed when drawing + tipPoints.put(node, new Point2D.Double(shapeBounds.getCenterX(), shapeBounds.getCenterY())); + } + } + } if (nodeShapePainter != null && nodeShapePainter.isVisible()) { nodePoints.clear(); - // Iterate though the nodes - for (Node node : tree.getNodes()) { + // Iterate though the internal nodes + for (Node node : tree.getInternalNodes()) { Rectangle2D shapeBounds = nodeShapePainter.calibrate(g2, node); if (shapeBounds != null) { @@ -1842,37 +1920,28 @@ // Now rescale the scale axis setupScaleAxis(); - totalScaleBounds = new Rectangle2D.Double(0.0, 0.0, 0.0, 0.0); + bottomPanelBounds = new Rectangle2D.Double(); double y = totalTreeBounds.getHeight(); for (ScalePainter scalePainter : scalePainters) { if (scalePainter.isVisible()) { scalePainter.calibrate(g2, this); Rectangle2D sb = new Rectangle2D.Double( - totalTreeBounds.getX(), y, - totalTreeBounds.getWidth(), scalePainter.getPreferredHeight()); + treeBounds.getX(), y, + treeBounds.getWidth(), scalePainter.getPreferredHeight()); y += sb.getHeight(); - totalScaleBounds.add(sb); + bottomPanelBounds.add(sb); scaleBounds.put(scalePainter, sb); } } - totalTreeBounds.add(totalScaleBounds); + leftPanelBounds = new Rectangle2D.Double(); if (legendPainter != null && legendPainter.isVisible()) { legendPainter.calibrate(g2, this); final double w2 = legendPainter.getPreferredWidth(); - legendBounds = new Rectangle2D.Double(-w2, 0, w2, treeBounds.getHeight()); - totalTreeBounds.add(legendBounds); + legendBounds = new Rectangle2D.Double(0.0, 0.0, w2, height); + leftPanelBounds.add(legendBounds); } -// // translate treeBounds to the inset within totalTreeBounds -// treeBounds.setRect(-totalTreeBounds.getX(), -totalTreeBounds.getY(), treeBounds.getWidth(), treeBounds.getHeight()); -// -// // translate totalTreeBounds so it is at 0, 0 -// totalTreeBounds.setRect(0, 0, -// totalTreeBounds.getWidth(), -// totalTreeBounds.getHeight()); - - final double availableW = width - insets.left - insets.right; final double availableH = height - insets.top - insets.bottom; @@ -1913,8 +1982,8 @@ // Get the amount of canvas that is going to be taken up by the tree - // The rest is taken up by taxon labels which don't scale - final double w = availableW - xDiff; - final double h = availableH - yDiff; + final double w = availableW - xDiff - leftPanelBounds.getWidth() - rightPanelBounds.getWidth(); + final double h = availableH - yDiff - topPanelBounds.getHeight() - bottomPanelBounds.getHeight(); double xScale; double yScale; @@ -1948,9 +2017,8 @@ yScale = h / treeBounds.getHeight(); // and set the origin in the top left corner - xOffset = - treeBounds.getX() * xScale; - yOffset = - treeBounds.getY() * yScale; - + xOffset = -treeBounds.getX() * xScale + (treeBounds.getX() - totalTreeBounds.getX()); + yOffset = -treeBounds.getY() * yScale + (treeBounds.getY() - totalTreeBounds.getY()); treeScale = xScale; } @@ -1958,7 +2026,7 @@ // Create the overall transform transform = new AffineTransform(); - transform.translate(xOffset + insets.left, yOffset + insets.top); + transform.translate(xOffset + leftPanelBounds.getWidth(), yOffset + topPanelBounds.getHeight()); transform.scale(xScale, yScale); // Get the bounds for the newly scaled tree @@ -1993,6 +2061,7 @@ Rectangle2D shapeBounds = nodeBarPainter.calibrate(g2, node); if (shapeBounds != null) { + shapeBounds = transform.createTransformedShape(shapeBounds).getBounds2D(); treeBounds.add(shapeBounds); nodeBars.put(node, nodeBarPainter.getNodeBar()); } @@ -2006,15 +2075,17 @@ if (tipLabelPainter != null && tipLabelPainter.isVisible()) { final double labelHeight = tipLabelPainter.getPreferredHeight(); - Rectangle2D labelBounds = new Rectangle2D.Double(0.0, 0.0, tipLabelWidth, labelHeight); // Iterate though the external nodes with tip labels for (Node node : treeLayoutCache.getTipLabelPathMap().keySet()) { // Get the line that represents the path for the tip label Line2D tipPath = treeLayoutCache.getTipLabelPath(node); + final double labelWidth = tipLabelWidths.get(node); + Rectangle2D labelBounds = new Rectangle2D.Double(0.0, 0.0, labelWidth, labelHeight); + // Work out how it is rotated and create a transform that matches that - AffineTransform taxonTransform = calculateTransform(transform, tipPath, tipLabelWidth, labelHeight, true); + AffineTransform taxonTransform = calculateTransform(transform, tipPath, labelWidth, labelHeight, true); // Store the transformed bounds in the map for use when selecting tipLabelBounds.put(node, taxonTransform.createTransformedShape(labelBounds)); @@ -2102,8 +2173,8 @@ } } + nodeShapeTransforms.clear(); if (nodeShapePainter != null && nodeShapePainter.isVisible()) { - nodeShapeTransforms.clear(); // Iterate though the nodes for (Node node : nodePoints.keySet()) { Line2D shapePath = getTreeLayoutCache().getNodeShapePath(node); @@ -2112,8 +2183,18 @@ } } } + if (tipShapePainter != null && tipShapePainter.isVisible()) { + // Iterate though the nodes + for (Node node : tipPoints.keySet()) { + Line2D shapePath = getTreeLayoutCache().getNodeShapePath(node); + if (shapePath != null) { + nodeShapeTransforms.put(node, calculateTransform(transform, shapePath)); + } + } + } + - y = height; + y = availableH; for (ScalePainter scalePainter : scalePainters) { if (scalePainter.isVisible()) { scalePainter.calibrate(g2, this); @@ -2121,22 +2202,25 @@ } } - totalScaleBounds = new Rectangle2D.Double(0, y, treeBounds.getWidth(), 0.0); + bottomPanelBounds = new Rectangle2D.Double(0, y, treeBounds.getWidth(), 0.0); for (ScalePainter scalePainter : scalePainters) { if (scalePainter.isVisible()) { scalePainter.calibrate(g2, this); final double h1 = scalePainter.getPreferredHeight(); Rectangle2D sb = new Rectangle2D.Double(treeBounds.getX(), y, treeBounds.getWidth(), h1); y += h1; - totalScaleBounds.add(sb); + bottomPanelBounds.add(sb); scaleBounds.put(scalePainter, sb); } } + leftPanelBounds = new Rectangle2D.Double(0, 0, 0.0, 0.0); if (legendPainter != null && legendPainter.isVisible()) { legendPainter.calibrate(g2, this); final double w2 = legendPainter.getPreferredWidth(); - legendBounds = new Rectangle2D.Double(0, 0, w2, treeBounds.getHeight()); + legendBounds = new Rectangle2D.Double(0.0, 0.0, w2, availableH); + leftPanelBounds.add(legendBounds); + } calloutPaths.clear(); @@ -2145,34 +2229,49 @@ calibrated = true; } - private void calibrateTipLabels(final Graphics2D g2, final Node node, final double tipLabelHeight, final Rectangle2D totalTreeBounds) { +// private void calculateMaxTipLabelWidth(final Graphics2D g2, final Node node) { +// +// if (tree.isExternal(node) || node.getAttribute(COLLAPSE_ATTRIBUTE_NAME) != null) { +// tipLabelPainter.calibrate(g2, node); +// double labelWidth = tipLabelPainter.getPreferredWidth(); +// tipLabelWidths.put(node, labelWidth); +// maxTipLabelWidth = Math.max(maxTipLabelWidth, labelWidth); +// } else { +// for (Node child : tree.getChildren(node)) { +// calculateMaxTipLabelWidth(g2, child); +// } +// } +// } + + private void calibrateTipLabels(final Graphics2D g2, final Node node, final Rectangle2D totalTreeBounds) { if (tree.isExternal(node) || node.getAttribute(COLLAPSE_ATTRIBUTE_NAME) != null) { tipLabelPainter.calibrate(g2, node); - double width = tipLabelPainter.getPreferredWidth(); - tipLabelWidth = Math.max(tipLabelWidth, width); + double labelWidth = tipLabelPainter.getPreferredWidth(); + double labelHeight = tipLabelPainter.getPreferredHeight(); - Rectangle2D labelBounds = new Rectangle2D.Double(0.0, 0.0, width, tipLabelHeight); + tipLabelWidths.put(node, labelWidth); + Rectangle2D labelBounds = new Rectangle2D.Double(0.0, 0.0, labelWidth, labelHeight); // Get the line that represents the path for the taxon label Line2D taxonPath = treeLayoutCache.getTipLabelPath(node); if (taxonPath != null) { // Work out how it is rotated and create a transform that matches that - AffineTransform taxonTransform = calculateTransform(null, taxonPath, tipLabelWidth, tipLabelHeight, true); + AffineTransform taxonTransform = calculateTransform(null, taxonPath, labelWidth, labelHeight, true); // and add the translated bounds to the overall bounds totalTreeBounds.add(taxonTransform.createTransformedShape(labelBounds).getBounds2D()); } } else { for (Node child : tree.getChildren(node)) { - calibrateTipLabels(g2, child, tipLabelHeight, totalTreeBounds); + calibrateTipLabels(g2, child, totalTreeBounds); } } } private AffineTransform calculateTransform(AffineTransform globalTransform, Line2D line, - double width, double height, boolean just) { + double width, double height, boolean justify) { final Point2D origin = line.getP1(); if (globalTransform != null) { globalTransform.transform(origin, origin); @@ -2193,7 +2292,7 @@ // to shift it by the entire width of the string. final double ty = origin.getY() - (height / 2.0); double tx = origin.getX(); - if( just) { + if (justify) { if (line.getX2() > line.getX1()) { tx += labelXOffset; } else { @@ -2227,22 +2326,22 @@ // Overridden methods to recalibrate tree when bounds change public void setBounds(int x, int y, int width, int height) { - calibrated = false; + recalibrate(); super.setBounds(x, y, width, height); } public void setBounds(Rectangle rectangle) { - calibrated = false; + recalibrate(); super.setBounds(rectangle); } public void setSize(Dimension dimension) { - calibrated = false; + recalibrate(); super.setSize(dimension); } public void setSize(int width, int height) { - calibrated = false; + recalibrate(); super.setSize(width, height); } @@ -2265,16 +2364,18 @@ private Rectangle2D treeBounds = new Rectangle2D.Double(); private double treeScale; private double maxTreeHeight; + private double rootHeightOffset; private ScaleAxis scaleAxis = new ScaleAxis(ScaleAxis.AT_DATA, ScaleAxis.AT_DATA); private double axisOrigin = 0.0; private TimeScale timeScale = new TimeScale(1.0, 0.0); + private boolean isAxisReversed = false; //private Insets insets = new Insets(0, 0, 0, 0); private Insets insets = new Insets(6, 6, 6, 6); private Set selectedNodes = new HashSet(); - private Set selectedTips = new HashSet(); + private Set selectedTips = new LinkedHashSet(); private double rulerHeight = -1.0; private Rectangle2D dragRectangle = null; @@ -2291,18 +2392,18 @@ private Decorator nodeBackgroundDecorator = null; - private float labelXOffset = 5.0F; + private float labelXOffset = 10.0F; private LabelPainter tipLabelPainter = null; - private double tipLabelWidth; + //private double maxTipLabelWidth; private LabelPainter nodeLabelPainter = null; private LabelPainter branchLabelPainter = null; private NodeBarPainter nodeBarPainter = null; private NodeShapePainter nodeShapePainter = null; + private NodeShapePainter tipShapePainter = null; private List scalePainters = new ArrayList(); - private Rectangle2D totalScaleBounds = null; private Map scaleBounds = new HashMap(); private ScaleGridPainter scaleGridPainter = null; @@ -2310,6 +2411,11 @@ private LegendPainter legendPainter = null; private Rectangle2D legendBounds = new Rectangle2D.Double(); + private Rectangle2D topPanelBounds = new Rectangle2D.Double(); + private Rectangle2D leftPanelBounds = new Rectangle2D.Double(); + private Rectangle2D bottomPanelBounds = new Rectangle2D.Double(); + private Rectangle2D rightPanelBounds = new Rectangle2D.Double(); + private BasicStroke branchLineStroke = new BasicStroke(1.0F, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); private BasicStroke calloutStroke = new BasicStroke(0.5F, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f, new float[]{0.5f, 2.0f}, 0.0f); @@ -2325,6 +2431,7 @@ private Map tipLabelTransforms = new HashMap(); private Map tipLabelBounds = new HashMap(); + private Map tipLabelWidths = new HashMap(); private Map tipLabelJustifications = new HashMap(); private Map nodeLabelTransforms = new HashMap(); @@ -2336,6 +2443,7 @@ private Map branchLabelJustifications = new HashMap(); private Map nodeBars = new HashMap(); + private Map tipPoints = new HashMap(); private Map nodePoints = new HashMap(); private Map nodeShapeTransforms = new HashMap(); diff -Nru figtree-1.4.2+dfsg/src/figtree/treeviewer/TreePaneRollOver.java figtree-1.4.3+dfsg/src/figtree/treeviewer/TreePaneRollOver.java --- figtree-1.4.2+dfsg/src/figtree/treeviewer/TreePaneRollOver.java 2014-10-15 14:22:10.000000000 +0000 +++ figtree-1.4.3+dfsg/src/figtree/treeviewer/TreePaneRollOver.java 2016-10-04 14:24:27.000000000 +0000 @@ -46,8 +46,7 @@ public TreePaneRollOver(TreePane treePane) { this.treePane = treePane; treePane.addMouseMotionListener(this); - - } + } public void mouseEntered(MouseEvent mouseEvent) { } @@ -60,25 +59,29 @@ if (tree != null) { Node node = treePane.getNodeAt((Graphics2D) treePane.getGraphics(), mouseEvent.getPoint()); if (node != null) { - StringBuilder sb = new StringBuilder(); - if (!tree.isExternal(node)) { - int n = RootedTreeUtils.getTipCount(tree, node); - sb.append("Subtree: ").append(n).append(" tips"); - } else { - sb.append("Tip: \"").append(tree.getTaxon(node).toString()).append("\""); - } - sb.append(" [height = ").append(formatter.getFormattedValue(tree.getHeight(node))); - sb.append(", length = ").append(formatter.getFormattedValue(tree.getLength(node))); - sb.append("]"); - fireStatusChanged(StatusPanel.NORMAL, sb.toString()); + fireStatusChanged(StatusPanel.NORMAL, getNodeText(tree, node)); } else { - fireStatusChanged(StatusPanel.NORMAL, " "); + fireStatusChanged(StatusPanel.NORMAL, getNodeText(tree, tree.getRootNode())); } } else { fireStatusChanged(StatusPanel.NORMAL, " "); } } + private String getNodeText(RootedTree tree, Node node) { + StringBuilder sb = new StringBuilder(); + if (!tree.isExternal(node)) { + int n = RootedTreeUtils.getTipCount(tree, node); + sb.append(tree.isRoot(node) ? "Tree: " : "Subtree: ").append(n).append(" tips"); + } else { + sb.append("Tip: \"").append(tree.getTaxon(node).toString()).append("\""); + } + sb.append(" [height = ").append(formatter.getFormattedValue(tree.getHeight(node))); + sb.append(", length = ").append(formatter.getFormattedValue(tree.getLength(node))); + sb.append("]"); + return sb.toString(); + } + public void mouseDragged(MouseEvent mouseEvent) { }