JAL-1807 Bob's first commit -- Applet loaded; needs image
[jalview.git] / src / jalview / io / HtmlSvgOutput.java
1 package jalview.io;
2 import jalview.api.FeatureRenderer;
3 import jalview.bin.Cache;
4 import jalview.datamodel.AlignmentExportData;
5 import jalview.datamodel.SequenceI;
6 import jalview.gui.AlignViewport;
7 import jalview.gui.AlignmentPanel;
8 import jalview.gui.HTMLOptions;
9 import jalview.math.AlignmentDimension;
10 import jalview.util.BrowserLauncher;
11 import jalview.util.MessageManager;
12
13 import java.awt.Color;
14 import java.awt.FontMetrics;
15 import java.awt.Graphics;
16 import java.awt.print.Printable;
17 import java.awt.print.PrinterException;
18 import java.io.File;
19 import java.io.FileOutputStream;
20
21 import org.jfree.graphics2d.svg.SVGGraphics2D;
22 import org.jfree.graphics2d.svg.SVGHints;
23
24 public class HtmlSvgOutput
25 {
26   AlignViewport av;
27
28   FeatureRenderer fr;
29   AlignmentPanel ap;
30
31
32   public HtmlSvgOutput(File file, AlignmentPanel ap)
33   {
34     this.av = ap.av;
35     this.ap = ap;
36     fr = ap.cloneFeatureRenderer();
37     generateHtmlSvgOutput(file);
38   }
39
40   public void generateHtmlSvgOutput(File file)
41   {
42     try
43     {
44       if (file == null /*
45                         * && !(System.getProperty("java.awt.headless") != null
46                         * && System
47                         * .getProperty("java.awt.headless").equals("true"))
48                         */)
49       {
50
51       JalviewFileChooser chooser = getHTMLChooser();
52         chooser.setFileView(new JalviewFileView());
53       chooser.setDialogTitle(ap.alignFrame.getTitle());
54       chooser.setToolTipText(MessageManager.getString("action.save"));
55       int value = chooser.showSaveDialog(ap.alignFrame);
56
57         if (value == JalviewFileChooser.APPROVE_OPTION)
58       {
59         Cache.setProperty("LAST_DIRECTORY", chooser
60                 .getSelectedFile().getParent());
61         file = chooser.getSelectedFile();
62       }
63       }
64
65       AlignmentDimension aDimension = ap.getAlignmentDimension();
66       SVGGraphics2D g1 = new SVGGraphics2D(aDimension.getWidth(),
67               aDimension.getHeight());
68       SVGGraphics2D g2 = new SVGGraphics2D(aDimension.getWidth(),
69               aDimension.getHeight());
70
71       String renderStyle = Cache.getDefault("HTML_RENDERING",
72               "Prompt each time");
73
74       // If we need to prompt, and if the GUI is visible then
75       // Prompt for rendering style
76       if (renderStyle.equalsIgnoreCase("Prompt each time")
77               && !(System.getProperty("java.awt.headless") != null && System
78                       .getProperty("java.awt.headless").equals("true")))
79       {
80         HTMLOptions svgOption = new HTMLOptions();
81         renderStyle = svgOption.getValue();
82
83         if (renderStyle == null || svgOption.cancelled)
84         {
85           return;
86         }
87       }
88
89       if (renderStyle.equalsIgnoreCase("lineart"))
90       {
91         g1.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
92                 SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
93         g2.setRenderingHint(SVGHints.KEY_DRAW_STRING_TYPE,
94                 SVGHints.VALUE_DRAW_STRING_TYPE_VECTOR);
95       }
96       printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0, g1,
97               g2);
98
99       String titleSvgData = g1.getSVGDocument();
100       String alignSvgData = g2.getSVGDocument();
101
102       AlignmentExportData exportData = ap.alignFrame.getAlignmentForExport(
103               JSONFile.FILE_DESC, av);
104       if (exportData.getSettings().isCancelled())
105       {
106         return;
107       }
108       String jsonData = new FormatAdapter(ap, exportData.getSettings())
109               .formatSequences(JSONFile.FILE_DESC, exportData
110                       .getAlignment(), exportData.getOmitHidden(),
111                       exportData.getStartEndPostions(), ap
112                               .getAlignViewport().getColumnSelection());
113
114       // String jsonData = JSONFile.getJSONData(ap);
115       String htmlData = getHtml(titleSvgData, alignSvgData, jsonData);
116
117       FileOutputStream out = new FileOutputStream(file);
118       out.write(htmlData.getBytes());
119       out.flush();
120       out.close();
121       if (!(System.getProperty("java.awt.headless") != null && System
122               .getProperty("java.awt.headless").equals("true")))
123       {
124         BrowserLauncher.openURL("file:///" + file);
125       }
126     } catch (Exception e)
127     {
128       e.printStackTrace();
129     }
130   }
131   
132   static JalviewFileChooser getHTMLChooser()
133   {
134     return new JalviewFileChooser(
135             Cache.getProperty("LAST_DIRECTORY"), new String[]
136             { "html" }, new String[]
137             { "Hypertext Markup Language" }, "Hypertext Markup Language");
138   }
139
140   public int printUnwrapped(int pwidth, int pheight, int pi, Graphics... pg)
141           throws PrinterException
142   {
143     int idWidth = ap.getVisibleIdWidth(false);
144     FontMetrics fm = ap.getFontMetrics(av.getFont());
145     int scaleHeight = av.getCharHeight() + fm.getDescent();
146
147     pg[0].setColor(Color.white);
148     pg[0].fillRect(0, 0, pwidth, pheight);
149     pg[0].setFont(av.getFont());
150
151     // //////////////////////////////////
152     // / How many sequences and residues can we fit on a printable page?
153     int totalRes = (pwidth - idWidth) / av.getCharWidth();
154     int totalSeq = (pheight - scaleHeight) / av.getCharHeight() - 1;
155     int pagesWide = (av.getAlignment().getWidth() / totalRes) + 1;
156
157     // ///////////////////////////
158     // / Only print these sequences and residues on this page
159     int startRes;
160
161     // ///////////////////////////
162     // / Only print these sequences and residues on this page
163     int endRes;
164
165     // ///////////////////////////
166     // / Only print these sequences and residues on this page
167     int startSeq;
168
169     // ///////////////////////////
170     // / Only print these sequences and residues on this page
171     int endSeq;
172     startRes = (pi % pagesWide) * totalRes;
173     endRes = (startRes + totalRes) - 1;
174
175     if (endRes > (av.getAlignment().getWidth() - 1))
176     {
177       endRes = av.getAlignment().getWidth() - 1;
178     }
179     startSeq = (pi / pagesWide) * totalSeq;
180     endSeq = startSeq + totalSeq;
181     if (endSeq > av.getAlignment().getHeight())
182     {
183       endSeq = av.getAlignment().getHeight();
184     }
185     int pagesHigh = ((av.getAlignment().getHeight() / totalSeq) + 1)
186             * pheight;
187     if (av.isShowAnnotation())
188     {
189       pagesHigh += ap.getAnnotationPanel().adjustPanelHeight() + 3;
190     }
191     pagesHigh /= pheight;
192     if (pi >= (pagesWide * pagesHigh))
193     {
194       return Printable.NO_SUCH_PAGE;
195     }
196
197     // draw Scale
198     pg[1].translate(0, 0);
199     ap.getScalePanel().drawScale(pg[1], startRes, endRes, pwidth - idWidth,
200             scaleHeight);
201     pg[1].translate(-idWidth, scaleHeight);
202
203     // //////////////
204     // Draw the ids
205     Color currentColor = null;
206     Color currentTextColor = null;
207     pg[0].translate(0, scaleHeight);
208     pg[0].setFont(ap.getIdPanel().getIdCanvas().getIdfont());
209     SequenceI seq;
210     for (int i = startSeq; i < endSeq; i++)
211     {
212       seq = av.getAlignment().getSequenceAt(i);
213       if ((av.getSelectionGroup() != null)
214               && av.getSelectionGroup().getSequences(null).contains(seq))
215       {
216         currentColor = Color.gray;
217         currentTextColor = Color.black;
218       }
219       else
220       {
221         currentColor = av.getSequenceColour(seq);
222         currentTextColor = Color.black;
223       }
224       pg[0].setColor(currentColor);
225       pg[0].fillRect(0, (i - startSeq) * av.getCharHeight(), idWidth,
226               av.getCharHeight());
227       pg[0].setColor(currentTextColor);
228       int xPos = 0;
229       if (av.isRightAlignIds())
230       {
231         fm = pg[0].getFontMetrics();
232         xPos = idWidth
233                 - fm.stringWidth(seq.getDisplayId(av.getShowJVSuffix()))
234                 - 4;
235       }
236       pg[0].drawString(
237               seq.getDisplayId(av.getShowJVSuffix()),
238               xPos,
239               (((i - startSeq) * av.getCharHeight()) + av.getCharHeight())
240                       - (av.getCharHeight() / 5));
241     }
242     pg[0].setFont(av.getFont());
243     pg[0].translate(idWidth, 0);
244
245     // draw main sequence panel
246     pg[1].translate(idWidth, 0);
247     ap.getSeqPanel().seqCanvas.drawPanel(pg[1], startRes, endRes, startSeq,
248             endSeq, 0);
249     if (av.isShowAnnotation() && (endSeq == av.getAlignment().getHeight()))
250     {
251       // draw annotation label - need to offset for current scroll position
252       int offset = -ap.getAlabels().getScrollOffset();
253       pg[0].translate(0, offset);
254       pg[0].translate(-idWidth - 3,
255               (endSeq - startSeq) * av.getCharHeight() + 3);
256       ap.getAlabels().drawComponent(pg[0], idWidth);
257       pg[0].translate(idWidth + 3, 0);
258       pg[0].translate(0, -offset);
259
260       // draw annotation - need to offset for current scroll position
261       pg[1].translate(0, offset);
262       pg[1].translate(-idWidth - 3,
263               (endSeq - startSeq) * av.getCharHeight() + 3);
264       pg[1].translate(idWidth + 3, 0);
265       ap.getAnnotationPanel().renderer.drawComponent(
266               ap.getAnnotationPanel(), av, pg[1], -1, startRes, endRes + 1);
267       pg[1].translate(0, -offset);
268     }
269
270     return Printable.PAGE_EXISTS;
271   }
272   
273   private String getHtml(String titleSvg, String alignmentSvg,
274           String jsonData)
275   {
276     StringBuilder htmlSvg = new StringBuilder();
277     htmlSvg.append("<html>\n");
278     if (jsonData != null)
279     {
280       htmlSvg.append("<input type=\"hidden\" name=\"seqData\" id=\"seqData\" value='"
281               + jsonData + "'>");
282     }
283     htmlSvg.append("\n<style type=\"text/css\"> "
284             + "div.parent{ width:100%;<!-- overflow: auto; -->}\n"
285             + "div.titlex{ width:11%; float: left; }\n"
286             + "div.align{ width:89%; float: right; }\n"
287             + ".sub-category-container {overflow-y: scroll; overflow-x: hidden; width: 100%; height: 100%;}\n"
288             + "object {pointer-events: none;}"
289             + "</style>");
290     htmlSvg.append("<div>");
291     htmlSvg.append(
292 "<div class=\"titlex\">");
293     htmlSvg.append(
294 "<div class=\"sub-category-container\"> ")
295             .append(titleSvg)
296             .append("</div>")
297             .append("</div>\n\n<!-- ========================================================================================== -->\n\n");
298     htmlSvg.append(
299 "<div class=\"align\" >");
300     htmlSvg.append(
301             "<div class=\"sub-category-container\"> <div style=\"overflow-x: scroll;\">")
302             .append(alignmentSvg)
303 .append("</div></div>")
304             .append("</div>");
305     htmlSvg.append("</div>");
306
307     htmlSvg.append("<script language=\"JavaScript\" type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js\"></script>\n"
308             + "<script language=\"JavaScript\" type=\"text/javascript\"  src=\"//ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js\"></script>\n"
309             + "<script>\n"
310             + "var subCatContainer = $(\".sub-category-container\");\n"
311             + "subCatContainer.scroll(\nfunction() {\n"
312             + "subCatContainer.scrollTop($(this).scrollTop());\n});\n");
313
314     htmlSvg.append("</script></hmtl>");
315
316     return htmlSvg.toString();
317   }
318 }