JAL-4059 Tidy getting the namespace, and save the namespace in the Jalview instance...
[jalview.git] / src / jalview / io / HTMLOutput.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.io;
22
23 import java.io.BufferedReader;
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.InputStreamReader;
27 import java.net.URL;
28 import java.util.Objects;
29
30 import jalview.api.AlignExportSettingsI;
31 import jalview.bin.Cache;
32 import jalview.bin.Jalview;
33 import jalview.datamodel.AlignExportSettingsAdapter;
34 import jalview.datamodel.AlignmentExportData;
35 import jalview.gui.AlignmentPanel;
36 import jalview.gui.IProgressIndicator;
37 import jalview.io.exceptions.ImageOutputException;
38 import jalview.util.IdUtils;
39 import jalview.util.IdUtils.IdType;
40 import jalview.util.MessageManager;
41
42 public abstract class HTMLOutput implements Runnable
43 {
44   protected AlignmentPanel ap;
45
46   /*
47    * key for progress or status messages
48    */
49   protected long pSessionId;
50
51   /*
52    * (optional) place to write progress messages to
53    */
54   protected IProgressIndicator pIndicator;
55
56   protected File generatedFile;
57
58   String _bioJson = null;
59
60   private String description;
61
62   /**
63    * Constructor given an alignment panel (which should not be null)
64    * 
65    * @param ap
66    * @param desc
67    */
68   public HTMLOutput(AlignmentPanel ap, String desc)
69   {
70     this.ap = ap;
71     this.pIndicator = ap.alignFrame;
72     this.description = desc;
73     this.pSessionId = IdUtils.newId(IdType.PROGRESS);
74   }
75
76   /**
77    * Gets the BioJSON data as a string, with lazy evaluation (first time called
78    * only). If the output format is configured not to embed BioJSON, returns
79    * null.
80    * 
81    * @return
82    */
83   public String getBioJSONData()
84   {
85     if (!isEmbedData())
86     {
87       return null;
88     }
89     if (_bioJson == null)
90     {
91       AlignExportSettingsI options = new AlignExportSettingsAdapter(true);
92       AlignmentExportData exportData = ap.getAlignViewport()
93               .getAlignExportData(options);
94       _bioJson = new FormatAdapter(ap, options).formatSequences(
95               FileFormat.Json, exportData.getAlignment(),
96               exportData.getOmitHidden(), exportData.getStartEndPostions(),
97               ap.getAlignViewport().getAlignment().getHiddenColumns());
98     }
99
100     return _bioJson;
101   }
102
103   /**
104    * Read a template file content as string
105    * 
106    * @param file
107    *          - the file to be read
108    * @return File content as String
109    * @throws IOException
110    */
111   public static String readFileAsString(File file) throws IOException
112   {
113     InputStreamReader isReader = null;
114     BufferedReader buffReader = null;
115     StringBuilder sb = new StringBuilder();
116     Objects.requireNonNull(file, "File must not be null!");
117     @SuppressWarnings("deprecation")
118     URL url = file.toURL();
119     if (url != null)
120     {
121       try
122       {
123         isReader = new InputStreamReader(url.openStream());
124         buffReader = new BufferedReader(isReader);
125         String line;
126         String lineSeparator = System.getProperty("line.separator");
127         while ((line = buffReader.readLine()) != null)
128         {
129           sb.append(line).append(lineSeparator);
130         }
131
132       } catch (Exception ex)
133       {
134         ex.printStackTrace();
135       } finally
136       {
137         if (isReader != null)
138         {
139           isReader.close();
140         }
141
142         if (buffReader != null)
143         {
144           buffReader.close();
145         }
146       }
147     }
148     return sb.toString();
149   }
150
151   public static String getImageMapHTML()
152   {
153     return new String("<html>\n" + "<head>\n"
154             + "<script language=\"JavaScript\">\n"
155             + "var ns4 = document.layers;\n"
156             + "var ns6 = document.getElementById && !document.all;\n"
157             + "var ie4 = document.all;\n" + "offsetX = 0;\n"
158             + "offsetY = 20;\n" + "var toolTipSTYLE=\"\";\n"
159             + "function initToolTips()\n" + "{\n" + "  if(ns4||ns6||ie4)\n"
160             + "  {\n"
161             + "    if(ns4) toolTipSTYLE = document.toolTipLayer;\n"
162             + "    else if(ns6) toolTipSTYLE = document.getElementById(\"toolTipLayer\").style;\n"
163             + "    else if(ie4) toolTipSTYLE = document.all.toolTipLayer.style;\n"
164             + "    if(ns4) document.captureEvents(Event.MOUSEMOVE);\n"
165             + "    else\n" + "    {\n"
166             + "      toolTipSTYLE.visibility = \"visible\";\n"
167             + "      toolTipSTYLE.display = \"none\";\n" + "    }\n"
168             + "    document.onmousemove = moveToMouseLoc;\n" + "  }\n"
169             + "}\n" + "function toolTip(msg, fg, bg)\n" + "{\n"
170             + "  if(toolTip.arguments.length < 1) // hide\n" + "  {\n"
171             + "    if(ns4) toolTipSTYLE.visibility = \"hidden\";\n"
172             + "    else toolTipSTYLE.display = \"none\";\n" + "  }\n"
173             + "  else // show\n" + "  {\n"
174             + "    if(!fg) fg = \"#555555\";\n"
175             + "    if(!bg) bg = \"#FFFFFF\";\n" + "    var content =\n"
176             + "    '<table border=\"0\" cellspacing=\"0\" cellpadding=\"1\" bgcolor=\"' + fg + '\"><td>' +\n"
177             + "    '<table border=\"0\" cellspacing=\"0\" cellpadding=\"1\" bgcolor=\"' + bg + \n"
178             + "    '\"><td align=\"center\"><font face=\"sans-serif\" color=\"' + fg +\n"
179             + "    '\" size=\"-2\">&nbsp;' + msg +\n"
180             + "    '&nbsp;</font></td></table></td></table>';\n"
181             + "    if(ns4)\n" + "    {\n"
182             + "      toolTipSTYLE.document.write(content);\n"
183             + "      toolTipSTYLE.document.close();\n"
184             + "      toolTipSTYLE.visibility = \"visible\";\n" + "    }\n"
185             + "    if(ns6)\n" + "    {\n"
186             + "      document.getElementById(\"toolTipLayer\").innerHTML = content;\n"
187             + "      toolTipSTYLE.display='block'\n" + "    }\n"
188             + "    if(ie4)\n" + "    {\n"
189             + "      document.all(\"toolTipLayer\").innerHTML=content;\n"
190             + "      toolTipSTYLE.display='block'\n" + "    }\n" + "  }\n"
191             + "}\n" + "function moveToMouseLoc(e)\n" + "{\n"
192             + "  if(ns4||ns6)\n" + "  {\n" + "    x = e.pageX;\n"
193             + "    y = e.pageY;\n" + "  }\n" + "  else\n" + "  {\n"
194             + "    x = event.x + document.body.scrollLeft;\n"
195             + "    y = event.y + document.body.scrollTop;\n" + "  }\n"
196             + "  toolTipSTYLE.left = x + offsetX;\n"
197             + "  toolTipSTYLE.top = y + offsetY;\n" + "  return true;\n"
198             + "}\n" + "</script>\n" + "</head>\n" + "<body>\n"
199             + "<div id=\"toolTipLayer\" style=\"position:absolute; visibility: hidden\"></div>\n"
200             + "<script language=\"JavaScript\"><!--\n"
201             + "initToolTips(); //--></script>\n");
202
203   }
204
205   /**
206    * Prompts the user to choose an output file and returns the file path, or
207    * null on Cancel
208    * 
209    * @return
210    */
211   public String getOutputFile()
212   {
213     String selectedFile = null;
214
215     // TODO: JAL-3048 generate html rendered view (requires SvgGraphics and/or
216     // Jalview HTML rendering system- probably not required for Jalview-JS)
217     JalviewFileChooser jvFileChooser = new JalviewFileChooser("html",
218             "HTML files");
219     jvFileChooser.setFileView(new JalviewFileView());
220
221     jvFileChooser
222             .setDialogTitle(MessageManager.getString("label.save_as_html"));
223     jvFileChooser.setToolTipText(MessageManager.getString("action.save"));
224
225     int fileChooserOpt = jvFileChooser.showSaveDialog(null);
226     if (fileChooserOpt == JalviewFileChooser.APPROVE_OPTION)
227     {
228       Cache.setProperty("LAST_DIRECTORY",
229               jvFileChooser.getSelectedFile().getParent());
230       selectedFile = jvFileChooser.getSelectedFile().getPath();
231     }
232
233     return selectedFile;
234   }
235
236   protected void setProgressMessage(String message)
237   {
238     if (pIndicator != null && !isHeadless())
239     {
240       pIndicator.setProgressBar(message, pSessionId);
241     }
242     else
243     {
244       jalview.bin.Console.outPrintln(message);
245     }
246   }
247
248   /**
249    * Answers true if HTML export is invoke in headless mode or false otherwise
250    * 
251    * @return
252    */
253   protected boolean isHeadless()
254   {
255     return System.getProperty("java.awt.headless") != null
256             && System.getProperty("java.awt.headless").equals("true");
257   }
258
259   /**
260    * This method provides implementation of consistent behaviour which should
261    * occur after a HTML file export. It MUST be called at the end of the
262    * exportHTML() method implementation.
263    */
264   protected void exportCompleted()
265   {
266     if (isLaunchInBrowserAfterExport() && !isHeadless())
267     {
268       /*
269       try
270       {
271       */
272       jalview.util.BrowserLauncher.openURL("file:///" + getExportedFile());
273       /*
274       } catch (IOException e)
275       {
276         e.printStackTrace();
277       }
278       */
279     }
280   }
281
282   /**
283    * if this answers true then BioJSON data will be embedded to the exported
284    * HTML file otherwise it won't be embedded.
285    * 
286    * @return
287    */
288   public abstract boolean isEmbedData();
289
290   /**
291    * if this answers true then the generated HTML file is opened for viewing in
292    * a browser after its generation otherwise it won't be opened in a browser
293    * 
294    * @return
295    */
296   public abstract boolean isLaunchInBrowserAfterExport();
297
298   /**
299    * handle to the generated HTML file
300    * 
301    * @return
302    */
303   public File getExportedFile()
304   {
305     return generatedFile;
306   }
307
308   public void exportHTML(String outputFile) throws ImageOutputException
309   {
310     exportHTML(outputFile, null);
311   }
312
313   public void exportHTML(String outputFile, String renderer)
314           throws ImageOutputException
315   {
316     setProgressMessage(MessageManager.formatMessage(
317             "status.exporting_alignment_as_x_file", getDescription()));
318     try
319     {
320       if (outputFile == null)
321       {
322         /*
323          * prompt for output file
324          */
325         outputFile = getOutputFile();
326         if (outputFile == null)
327         {
328           setProgressMessage(MessageManager.formatMessage(
329                   "status.cancelled_image_export_operation",
330                   getDescription()));
331           return;
332         }
333       }
334       generatedFile = new File(outputFile);
335     } catch (Exception e)
336     {
337       setProgressMessage(MessageManager
338               .formatMessage("info.error_creating_file", getDescription()));
339       e.printStackTrace();
340       return;
341     }
342     if (Jalview.isHeadlessMode())
343     {
344       this.run(renderer);
345     }
346     else
347     {
348       new Thread(this).start();
349     }
350
351   }
352
353   /**
354    * Answers a short description of the image format suitable for display in
355    * messages
356    * 
357    * @return
358    */
359   protected final String getDescription()
360   {
361     return description;
362   }
363
364   // used to pass an option such as render to run
365   public abstract void run(String string) throws ImageOutputException;
366 }