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