X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fio%2FHtmlSvgOutput.java;h=4ea3000b05ed4ab7a69d388d5566120305b9e189;hb=eb3e681d6e82ccdd5d312d1981dfb306e7f479f0;hp=7fcf629ca06a95188e77184b00523b91a1aa1211;hpb=e58c9b0c6d453c75810eb08cb2651769fccf7f8a;p=jalview.git diff --git a/src/jalview/io/HtmlSvgOutput.java b/src/jalview/io/HtmlSvgOutput.java index 7fcf629..4ea3000 100644 --- a/src/jalview/io/HtmlSvgOutput.java +++ b/src/jalview/io/HtmlSvgOutput.java @@ -1,337 +1,164 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview 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 3 + * of the License, or (at your option) any later version. + * + * Jalview 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 Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ package jalview.io; -import jalview.api.FeatureRenderer; -import jalview.datamodel.AlignmentExportData; -import jalview.datamodel.SequenceI; -import jalview.gui.AlignViewport; -import jalview.gui.AlignmentPanel; -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 java.io.IOException; +import java.util.Locale; +import java.util.concurrent.atomic.AtomicBoolean; import org.jfree.graphics2d.svg.SVGGraphics2D; import org.jfree.graphics2d.svg.SVGHints; -public class HtmlSvgOutput -{ - AlignViewport av; - - FeatureRenderer fr; - AlignmentPanel ap; - +import jalview.bin.Cache; +import jalview.gui.AlignmentPanel; +import jalview.gui.LineartOptions; +import jalview.gui.OOMWarning; +import jalview.math.AlignmentDimension; +import jalview.util.MessageManager; - public HtmlSvgOutput(File file, AlignmentPanel ap) +public class HtmlSvgOutput extends HTMLOutput +{ + public HtmlSvgOutput(AlignmentPanel ap) { - this.av = ap.av; - this.ap = ap; - fr = ap.cloneFeatureRenderer(); - generateHtmlSvgOutput(file); + super(ap, "HTML"); } - public void generateHtmlSvgOutput(File file) - { - try - { - if (file == null /* - * && !(System.getProperty("java.awt.headless") != null - * && System - * .getProperty("java.awt.headless").equals("true")) - */) - { - - 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); - - String titleSvgData = g1.getSVGDocument(); - String alignSvgData = g2.getSVGDocument(); - String jsonData = null; - boolean isEmbbedBioJSON = Boolean.valueOf(jalview.bin.Cache - .getDefault("EXPORT_EMBBED_BIOJSON", "true")); - if (isEmbbedBioJSON) - { - AlignmentExportData exportData = ap.alignFrame.getAlignmentForExport( - JSONFile.FILE_DESC, av); - if (exportData.getSettings().isCancelled()) - { - return; - } - jsonData = new FormatAdapter(ap, exportData.getSettings()) - .formatSequences(JSONFile.FILE_DESC, exportData - .getAlignment(), exportData.getOmitHidden(), - exportData.getStartEndPostions(), ap - .getAlignViewport().getColumnSelection()); - } - String htmlData = getHtml(titleSvgData, alignSvgData, jsonData); - FileOutputStream out = new FileOutputStream(file); - out.write(htmlData.getBytes()); - out.flush(); - out.close(); - if (!(System.getProperty("java.awt.headless") != null && System - .getProperty("java.awt.headless").equals("true"))) - { - jalview.util.BrowserLauncher.openURL("file:///" + file); - } - } catch (Exception e) - { - e.printStackTrace(); - } - } - - static JalviewFileChooser getHTMLChooser() + public int printUnwrapped(int pwidth, int pheight, int pi, + Graphics idGraphics, Graphics alignmentGraphics) + throws PrinterException { - return new jalview.io.JalviewFileChooser( - jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[] - { "html" }, new String[] - { "Hypertext Markup Language" }, "Hypertext Markup Language"); + return ap.printUnwrapped(pwidth, pheight, pi, idGraphics, + alignmentGraphics); } - public int printUnwrapped(int pwidth, int pheight, int pi, Graphics... pg) + public int printWrapped(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; + return ap.printWrappedAlignment(pwidth, pheight, pi, pg[0]); } - - private String getHtml(String titleSvg, String alignmentSvg, - String jsonData) + + String getHtml(String titleSvg, String alignmentSvg, String jsonData, + boolean wrapped) { StringBuilder htmlSvg = new StringBuilder(); htmlSvg.append("\n"); if (jsonData != null) { - htmlSvg.append(""); - htmlSvg.append(""); + htmlSvg.append( + "  "); + htmlSvg.append( + ""); + htmlSvg.append( + "
" + + jsonData + "
"); + htmlSvg.append("
 "); } htmlSvg.append("\n"); - htmlSvg.append("
"); - htmlSvg.append( -"
"); - htmlSvg.append( -"
") - .append(titleSvg) - .append("
") - .append("
\n\n\n\n"); - htmlSvg.append( -"
"); - htmlSvg.append( - "
") - .append(alignmentSvg) -.append("
") - .append("
"); - htmlSvg.append("
"); - - htmlSvg.append("\n" - + "\n" - + "\n"); + + "object {pointer-events: none;}"); + if (jsonData != null) + { + // facebox style sheet for displaying raw BioJSON data + htmlSvg.append( + "#facebox { position: absolute; top: 0; left: 0; z-index: 100; text-align: left; }\n" + + "#facebox .popup{ position:relative; border:3px solid rgba(0,0,0,0); -webkit-border-radius:5px;" + + "-moz-border-radius:5px; border-radius:5px; -webkit-box-shadow:0 0 18px rgba(0,0,0,0.4); -moz-box-shadow:0 0 18px rgba(0,0,0,0.4);" + + "box-shadow:0 0 18px rgba(0,0,0,0.4); }\n" + + "#facebox .content { display:table; width: 98%; padding: 10px; background: #fff; -webkit-border-radius:4px; -moz-border-radius:4px;" + + " border-radius:4px; }\n" + + "#facebox .content > p:first-child{ margin-top:0; }\n" + + "#facebox .content > p:last-child{ margin-bottom:0; }\n" + + "#facebox .close{ position:absolute; top:5px; right:5px; padding:2px; background:#fff; }\n" + + "#facebox .close img{ opacity:0.3; }\n" + + "#facebox .close:hover img{ opacity:1.0; }\n" + + "#facebox .loading { text-align: center; }\n" + + "#facebox .image { text-align: center;}\n" + + "#facebox img { border: 0; margin: 0; }\n" + + "#facebox_overlay { position: fixed; top: 0px; left: 0px; height:100%; width:100%; }\n" + + ".facebox_hide { z-index:-100; }\n" + + ".facebox_overlayBG { background-color: #000; z-index: 99; }"); + } + htmlSvg.append(""); + if (!wrapped) + { + htmlSvg.append("
"); + htmlSvg.append("
\n"); + htmlSvg.append("
\n"); + htmlSvg.append(titleSvg); + htmlSvg.append("
"); + htmlSvg.append( + "
\n\n\n\n"); + htmlSvg.append("
"); + htmlSvg.append( + "
") + .append(alignmentSvg).append("
").append("
"); + htmlSvg.append("
"); + + htmlSvg.append( + "\n" + + "\n" + + "\n"); + } + else + { + htmlSvg.append("
\n").append(alignmentSvg).append("
"); + htmlSvg.append( + "\n" + + "\n"); + } // javascript for launching file in Jalview - htmlSvg.append("\n"); - htmlSvg.append(""); + htmlSvg.append(""); return htmlSvg.toString(); } + + @Override + public boolean isEmbedData() + { + return Boolean + .valueOf(Cache.getDefault("EXPORT_EMBBED_BIOJSON", "true")); + } + + @Override + public boolean isLaunchInBrowserAfterExport() + { + return true; + } + + @Override + public void run() + { + run(null); + } + + @Override + public void run(String renderer) + { + try + { + String renderStyle = renderer == null + ? Cache.getDefault("HTML_RENDERING", + LineartOptions.PROMPT_EACH_TIME) + : renderer; + AtomicBoolean textOption = new AtomicBoolean( + !"lineart".equals(renderStyle.toLowerCase(Locale.ROOT))); + + /* + * configure the action to run on OK in the dialog + */ + Runnable okAction = () -> { + doOutput(textOption.get()); + }; + + /* + * Prompt for character rendering style if preference is not set + */ + if (renderStyle.equalsIgnoreCase(LineartOptions.PROMPT_EACH_TIME) + && !isHeadless()) + { + LineartOptions svgOption = new LineartOptions("HTML", textOption); + svgOption.setResponseAction(1, () -> { + setProgressMessage(MessageManager.formatMessage( + "status.cancelled_image_export_operation", + getDescription())); + }); + svgOption.setResponseAction(0, okAction); + svgOption.showDialog(); + /* no code here - JalviewJS cannot execute it */ + } + else + { + /* + * else (if preference set) just do the export action + */ + doOutput(textOption.get()); + } + } catch (OutOfMemoryError err) + { + jalview.bin.Console + .outPrintln("########################\n" + "OUT OF MEMORY " + + generatedFile + "\n" + "########################"); + new OOMWarning("Creating Image for " + generatedFile, err); + } catch (Exception e) + { + e.printStackTrace(); + setProgressMessage(MessageManager + .formatMessage("info.error_creating_file", getDescription())); + } + } + + /** + * Builds and writes the image to the file specified by field + * generatedFile + * + * @param textCharacters + * true for Text character rendering, false for Lineart + */ + protected void doOutput(boolean textCharacters) + { + try + { + AlignmentDimension aDimension = ap.getAlignmentDimension(); + SVGGraphics2D idPanelGraphics = new SVGGraphics2D( + aDimension.getWidth(), aDimension.getHeight()); + SVGGraphics2D alignPanelGraphics = new SVGGraphics2D( + aDimension.getWidth(), aDimension.getHeight()); + if (!textCharacters) // Lineart selected + { + idPanelGraphics.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE, + SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR); + alignPanelGraphics.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE, + SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR); + } + if (ap.av.getWrapAlignment()) + { + printWrapped(aDimension.getWidth(), aDimension.getHeight(), 0, + alignPanelGraphics); + } + else + { + printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0, + idPanelGraphics, alignPanelGraphics); + } + + String idPanelSvgData = idPanelGraphics.getSVGDocument(); + String alignPanelSvgData = alignPanelGraphics.getSVGDocument(); + String jsonData = getBioJSONData(); + String htmlData = getHtml(idPanelSvgData, alignPanelSvgData, jsonData, + ap.av.getWrapAlignment()); + FileOutputStream out = new FileOutputStream(generatedFile); + out.write(htmlData.getBytes()); + out.flush(); + out.close(); + setProgressMessage(MessageManager + .formatMessage("status.export_complete", getDescription())); + exportCompleted(); + } catch (Exception e) + { + e.printStackTrace(); + setProgressMessage(MessageManager + .formatMessage("info.error_creating_file", getDescription())); + } + } }