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