+package jalview.io;
+
+import jalview.datamodel.SequenceI;
+import jalview.gui.AlignViewport;
+import jalview.gui.AlignmentPanel;
+import jalview.gui.AnnotationPanel;
+import jalview.gui.FeatureRenderer;
+import jalview.gui.HTMLOptions;
+import jalview.math.AlignmentDimension;
+import jalview.util.MessageManager;
+
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+import java.io.File;
+import java.io.FileOutputStream;
+
+import org.jfree.graphics2d.svg.SVGGraphics2D;
+import org.jfree.graphics2d.svg.SVGHints;
+
+public class HtmlSvgOutput
+{
+ AlignViewport av;
+
+ FeatureRenderer fr;
+ AlignmentPanel ap;
+
+ AnnotationPanel annotationPanel;
+
+ public HtmlSvgOutput(AlignmentPanel ap)
+ {
+
+ this.av = ap.av;
+ this.ap = ap;
+ this.annotationPanel = ap.getAnnotationPanel();
+ generateHtmlSvgOutput();
+ }
+
+ public void generateHtmlSvgOutput()
+ {
+ File file = null;
+ try
+ {
+ JalviewFileChooser chooser = getHTMLChooser();
+ chooser.setFileView(new jalview.io.JalviewFileView());
+ chooser.setDialogTitle(ap.alignFrame.getTitle());
+ chooser.setToolTipText(MessageManager.getString("action.save"));
+ int value = chooser.showSaveDialog(ap.alignFrame);
+
+ if (value == jalview.io.JalviewFileChooser.APPROVE_OPTION)
+ {
+ jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
+ .getSelectedFile().getParent());
+ file = chooser.getSelectedFile();
+ }
+
+ AlignmentDimension aDimension = ap.getAlignmentDimension();
+ SVGGraphics2D g1 = new SVGGraphics2D(aDimension.getWidth(),
+ aDimension.getHeight());
+ SVGGraphics2D g2 = new SVGGraphics2D(aDimension.getWidth(),
+ aDimension.getHeight());
+
+ String renderStyle = jalview.bin.Cache.getDefault("HTML_RENDERING",
+ "Prompt each time");
+
+ // If we need to prompt, and if the GUI is visible then
+ // Prompt for rendering style
+ if (renderStyle.equalsIgnoreCase("Prompt each time")
+ && !(System.getProperty("java.awt.headless") != null && System
+ .getProperty("java.awt.headless").equals("true")))
+ {
+ HTMLOptions svgOption = new HTMLOptions();
+ renderStyle = svgOption.getValue();
+
+ if (renderStyle == null || svgOption.cancelled)
+ {
+ return;
+ }
+ }
+
+ if (renderStyle.equalsIgnoreCase("lineart"))
+ {
+ g1.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
+ SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
+ g2.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
+ SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
+ }
+ printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0, g1,
+ g2);
+ FileOutputStream out = new FileOutputStream(file);
+
+ String titleSvgData = g1.getSVGDocument();
+ String alignSvgData = g2.getSVGDocument();
+ String htmlData = getHtml(titleSvgData, alignSvgData);
+
+ out.write(htmlData.getBytes());
+ out.flush();
+ out.close();
+
+ jalview.util.BrowserLauncher.openURL("file:///" + file);
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ static JalviewFileChooser getHTMLChooser()
+ {
+ return new jalview.io.JalviewFileChooser(
+ jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
+ { "html" }, new String[]
+ { "Hypertext Markup Language" }, "Hypertext Markup Language");
+ }
+
+ public int printUnwrapped(int pwidth, int pheight, int pi, Graphics... pg)
+ throws PrinterException
+ {
+ int idWidth = ap.getVisibleIdWidth(false);
+ FontMetrics fm = ap.getFontMetrics(av.getFont());
+ int scaleHeight = av.getCharHeight() + fm.getDescent();
+
+ pg[0].setColor(Color.white);
+ pg[0].fillRect(0, 0, pwidth, pheight);
+ pg[0].setFont(av.getFont());
+
+ // //////////////////////////////////
+ // / How many sequences and residues can we fit on a printable page?
+ int totalRes = (pwidth - idWidth) / av.getCharWidth();
+ int totalSeq = (pheight - scaleHeight) / av.getCharHeight() - 1;
+ int pagesWide = (av.getAlignment().getWidth() / totalRes) + 1;
+
+ // ///////////////////////////
+ // / Only print these sequences and residues on this page
+ int startRes;
+
+ // ///////////////////////////
+ // / Only print these sequences and residues on this page
+ int endRes;
+
+ // ///////////////////////////
+ // / Only print these sequences and residues on this page
+ int startSeq;
+
+ // ///////////////////////////
+ // / Only print these sequences and residues on this page
+ int endSeq;
+ startRes = (pi % pagesWide) * totalRes;
+ endRes = (startRes + totalRes) - 1;
+
+ if (endRes > (av.getAlignment().getWidth() - 1))
+ {
+ endRes = av.getAlignment().getWidth() - 1;
+ }
+ startSeq = (pi / pagesWide) * totalSeq;
+ endSeq = startSeq + totalSeq;
+ if (endSeq > av.getAlignment().getHeight())
+ {
+ endSeq = av.getAlignment().getHeight();
+ }
+ int pagesHigh = ((av.getAlignment().getHeight() / totalSeq) + 1)
+ * pheight;
+ if (av.isShowAnnotation())
+ {
+ pagesHigh += ap.getAnnotationPanel().adjustPanelHeight() + 3;
+ }
+ pagesHigh /= pheight;
+ if (pi >= (pagesWide * pagesHigh))
+ {
+ return Printable.NO_SUCH_PAGE;
+ }
+
+ // draw Scale
+ pg[1].translate(0, 0);
+ ap.getScalePanel().drawScale(pg[1], startRes, endRes, pwidth - idWidth,
+ scaleHeight);
+ pg[1].translate(-idWidth, scaleHeight);
+
+ // //////////////
+ // Draw the ids
+ Color currentColor = null;
+ Color currentTextColor = null;
+ pg[0].translate(0, scaleHeight);
+ pg[0].setFont(ap.getIdPanel().getIdCanvas().getIdfont());
+ SequenceI seq;
+ for (int i = startSeq; i < endSeq; i++)
+ {
+ seq = av.getAlignment().getSequenceAt(i);
+ if ((av.getSelectionGroup() != null)
+ && av.getSelectionGroup().getSequences(null).contains(seq))
+ {
+ currentColor = Color.gray;
+ currentTextColor = Color.black;
+ }
+ else
+ {
+ currentColor = av.getSequenceColour(seq);
+ currentTextColor = Color.black;
+ }
+ pg[0].setColor(currentColor);
+ pg[0].fillRect(0, (i - startSeq) * av.getCharHeight(), idWidth,
+ av.getCharHeight());
+ pg[0].setColor(currentTextColor);
+ int xPos = 0;
+ if (av.isRightAlignIds())
+ {
+ fm = pg[0].getFontMetrics();
+ xPos = idWidth
+ - fm.stringWidth(seq.getDisplayId(av.getShowJVSuffix()))
+ - 4;
+ }
+ pg[0].drawString(
+ seq.getDisplayId(av.getShowJVSuffix()),
+ xPos,
+ (((i - startSeq) * av.getCharHeight()) + av.getCharHeight())
+ - (av.getCharHeight() / 5));
+ }
+ pg[0].setFont(av.getFont());
+ pg[0].translate(idWidth, 0);
+
+ // draw main sequence panel
+ pg[1].translate(idWidth, 0);
+ ap.getSeqPanel().seqCanvas.drawPanel(pg[1], startRes, endRes, startSeq,
+ endSeq, 0);
+ if (av.isShowAnnotation() && (endSeq == av.getAlignment().getHeight()))
+ {
+ // draw annotation label - need to offset for current scroll position
+ int offset = -ap.getAlabels().getScrollOffset();
+ pg[0].translate(0, offset);
+ pg[0].translate(-idWidth - 3,
+ (endSeq - startSeq) * av.getCharHeight() + 3);
+ ap.getAlabels().drawComponent(pg[0], idWidth);
+ pg[0].translate(idWidth + 3, 0);
+ pg[0].translate(0, -offset);
+
+ // draw annotation - need to offset for current scroll position
+ pg[1].translate(0, offset);
+ pg[1].translate(-idWidth - 3,
+ (endSeq - startSeq) * av.getCharHeight() + 3);
+ pg[1].translate(idWidth + 3, 0);
+ ap.getAnnotationPanel().renderer.drawComponent(
+ ap.getAnnotationPanel(), av, pg[1], -1, startRes, endRes + 1);
+ pg[1].translate(0, -offset);
+ }
+
+ return Printable.PAGE_EXISTS;
+ }
+
+ private String getHtml(String titleSvg, String alignmentSvg)
+ {
+ StringBuilder htmlSvg = new StringBuilder();
+ htmlSvg.append("<html><style type=\"text/css\">" + "div.title {"
+ + "height: 100%;" + "width: 9%;" + "float: left;" + "}"
+ + "div.align {" + "height: 100%;" + "width: 91%;"
+ + "overflow: scroll;" + "float: right;" + "}" + "</style>"
+ + "<div style=\"width:100%; height:100%; overflow: hidden\">"
+ + "<div class=\"title\">");
+ htmlSvg.append(titleSvg);
+ htmlSvg.append("</div><div class=\"align\">").append(alignmentSvg);
+ htmlSvg.append("</div>");
+ return htmlSvg.toString();
+ }
+}