JAL-1976 Added progress indicators for HTML_SVG and BioJS export operations
[jalview.git] / src / jalview / io / BioJsHTMLOutput.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.api.AlignmentViewPanel;
25 import jalview.datamodel.AlignmentExportData;
26 import jalview.exceptions.NoFileSelectedException;
27 import jalview.gui.IProgressIndicator;
28 import jalview.json.binding.biojs.BioJSReleasePojo;
29 import jalview.json.binding.biojs.BioJSRepositoryPojo;
30 import jalview.util.MessageManager;
31
32 import java.io.BufferedInputStream;
33 import java.io.BufferedReader;
34 import java.io.File;
35 import java.io.IOException;
36 import java.io.InputStream;
37 import java.io.InputStreamReader;
38 import java.io.PrintWriter;
39 import java.net.URISyntaxException;
40 import java.net.URL;
41 import java.util.Objects;
42 import java.util.TreeMap;
43
44 public class BioJsHTMLOutput
45 {
46   private AlignmentViewPanel ap;
47
48   private long pSessionId;
49
50   private IProgressIndicator pIndicator;
51
52   private boolean headless;
53
54   private static File currentBJSTemplateFile;
55
56   private static TreeMap<String, File> bioJsMSAVersions;
57
58   public static final String DEFAULT_DIR = System.getProperty("user.home")
59           + File.separatorChar + ".biojs_templates" + File.separatorChar;
60
61   public static final String BJS_TEMPLATES_LOCAL_DIRECTORY = jalview.bin.Cache
62           .getDefault("biojs_template_directory", DEFAULT_DIR);
63
64   public static final String BJS_TEMPLATE_GIT_REPO = jalview.bin.Cache
65           .getDefault(
66                   "biojs_template_git_repo",
67                   "https://raw.githubusercontent.com/jalview/exporter-templates/master/biojs/package.json");
68
69   public BioJsHTMLOutput(AlignmentViewPanel ap,
70           IProgressIndicator pIndicator)
71   {
72     if (ap != null)
73     {
74       this.ap = ap;
75       this.pSessionId = System.currentTimeMillis();
76       this.pIndicator = pIndicator;
77       this.headless = (System.getProperty("java.awt.headless") != null && System
78               .getProperty("java.awt.headless").equals("true"));
79     }
80   }
81
82   public void exportJalviewAlignmentAsBioJsHtmlFile()
83   {
84     try
85     {
86       String outputFile = getOutputFile();
87       // String jalviewAlignmentJson = JSONFile.getJSONData(ap);
88       AlignExportSettingI exportSettings = new AlignExportSettingI()
89       {
90         @Override
91         public boolean isExportHiddenSequences()
92         {
93           return true;
94         }
95
96         @Override
97         public boolean isExportHiddenColumns()
98         {
99           return true;
100         }
101
102         @Override
103         public boolean isExportAnnotations()
104         {
105           return true;
106         }
107
108         @Override
109         public boolean isExportFeatures()
110         {
111           return true;
112         }
113
114         @Override
115         public boolean isExportGroups()
116         {
117           return true;
118         }
119
120         @Override
121         public boolean isCancelled()
122         {
123           return false;
124         }
125
126       };
127       AlignmentExportData exportData = jalview.gui.AlignFrame
128               .getAlignmentForExport(JSONFile.FILE_DESC,
129                       ap.getAlignViewport(), exportSettings);
130       String bioJSON = new FormatAdapter(ap, exportData.getSettings())
131               .formatSequences(JSONFile.FILE_DESC, exportData
132                       .getAlignment(), exportData.getOmitHidden(),
133                       exportData.getStartEndPostions(), ap
134                               .getAlignViewport().getColumnSelection());
135
136       String bioJSTemplateString = getBioJsTemplateAsString();
137       String generatedBioJsWithJalviewAlignmentAsJson = bioJSTemplateString
138               .replaceAll("#sequenceData#", bioJSON).toString();
139
140       PrintWriter out = new java.io.PrintWriter(new java.io.FileWriter(
141               outputFile));
142       out.print(generatedBioJsWithJalviewAlignmentAsJson);
143       out.flush();
144       out.close();
145       jalview.util.BrowserLauncher.openURL("file:///" + outputFile);
146       if (pIndicator != null && !headless)
147       {
148         pIndicator.setProgressBar(MessageManager.formatMessage(
149                 "status.export_complete", "BioJS"), pSessionId);
150       }
151     } catch (NoFileSelectedException ex)
152     {
153       // do noting if no file was selected
154     } catch (Exception e)
155     {
156       pIndicator.setProgressBar(MessageManager.formatMessage(
157               "info.error_creating_file", "HTML"), pSessionId);
158       e.printStackTrace();
159     }
160   }
161
162   public String getOutputFile() throws NoFileSelectedException
163   {
164     String selectedFile = null;
165     if (pIndicator != null && !headless)
166     {
167       pIndicator.setProgressBar(MessageManager.formatMessage(
168               "status.waiting_for_user_to_select_output_file", "HTML"),
169               pSessionId);
170     }
171
172     JalviewFileChooser jvFileChooser = new JalviewFileChooser(
173             jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
174             new String[] { "html" }, new String[] { "HTML files" },
175             "HTML files");
176     jvFileChooser.setFileView(new JalviewFileView());
177
178     jvFileChooser.setDialogTitle(MessageManager
179             .getString("label.save_as_biojs_html"));
180     jvFileChooser.setToolTipText(MessageManager.getString("action.save"));
181
182     int fileChooserOpt = jvFileChooser.showSaveDialog(null);
183     if (fileChooserOpt == JalviewFileChooser.APPROVE_OPTION)
184     {
185       jalview.bin.Cache.setProperty("LAST_DIRECTORY", jvFileChooser
186               .getSelectedFile().getParent());
187       selectedFile = jvFileChooser.getSelectedFile().getPath();
188     }
189     else
190     {
191       pIndicator.setProgressBar(MessageManager.formatMessage(
192               "status.cancelled_image_export_operation", "BioJS"),
193               pSessionId);
194       throw new NoFileSelectedException("No file was selected.");
195     }
196     return selectedFile;
197   }
198
199   public static String getBioJsTemplateAsString() throws IOException
200   {
201     InputStreamReader isReader = null;
202     BufferedReader buffReader = null;
203     StringBuilder sb = new StringBuilder();
204     Objects.requireNonNull(getCurrentBJSTemplateFile(),
205             "BioJsTemplate File not initialized!");
206     @SuppressWarnings("deprecation")
207     URL url = getCurrentBJSTemplateFile().toURL();
208     if (url != null)
209     {
210       try
211       {
212         isReader = new InputStreamReader(url.openStream());
213         buffReader = new BufferedReader(isReader);
214         String line;
215         String lineSeparator = System.getProperty("line.separator");
216         while ((line = buffReader.readLine()) != null)
217         {
218           sb.append(line).append(lineSeparator);
219         }
220
221       } catch (Exception ex)
222       {
223         ex.printStackTrace();
224       } finally
225       {
226         if (isReader != null)
227         {
228           isReader.close();
229         }
230
231         if (buffReader != null)
232         {
233           buffReader.close();
234         }
235       }
236     }
237     return sb.toString();
238   }
239
240   public static void refreshBioJSVersionsInfo(String dirName)
241           throws URISyntaxException
242   {
243     File directory = new File(BJS_TEMPLATES_LOCAL_DIRECTORY);
244     Objects.requireNonNull(dirName, "dirName MUST not be null!");
245     Objects.requireNonNull(directory, "directory MUST not be null!");
246     TreeMap<String, File> versionFileMap = new TreeMap<String, File>();
247
248     for (File file : directory.listFiles())
249     {
250       if (file.isFile())
251       {
252         String fileName = file.getName().substring(0,
253                 file.getName().lastIndexOf("."));
254         String fileMeta[] = fileName.split("_");
255         if (fileMeta.length > 2)
256         {
257           setCurrentBJSTemplateFile(file);
258           versionFileMap.put(fileMeta[2], file);
259         }
260         else if (fileMeta.length > 1)
261         {
262           versionFileMap.put(fileMeta[1], file);
263         }
264       }
265     }
266     if (getCurrentBJSTemplateFile() == null && versionFileMap.size() > 0)
267     {
268       setCurrentBJSTemplateFile(versionFileMap.lastEntry().getValue());
269     }
270     setBioJsMSAVersions(versionFileMap);
271   }
272
273   public static void updateBioJS()
274   {
275     Thread updateThread = new Thread()
276     {
277       @Override
278       public void run()
279       {
280         try
281         {
282           String gitRepoPkgJson = getURLContentAsString(BJS_TEMPLATE_GIT_REPO);
283           if (gitRepoPkgJson != null)
284           {
285             BioJSRepositoryPojo release = new BioJSRepositoryPojo(
286                     gitRepoPkgJson);
287             syncUpdates(BJS_TEMPLATES_LOCAL_DIRECTORY, release);
288             refreshBioJSVersionsInfo(BJS_TEMPLATES_LOCAL_DIRECTORY);
289           }
290         } catch (URISyntaxException e)
291         {
292           e.printStackTrace();
293         }
294       }
295     };
296     updateThread.start();
297
298   }
299
300   public static void syncUpdates(String localDir, BioJSRepositoryPojo repo)
301   {
302     for (BioJSReleasePojo bjsRelease : repo.getReleases())
303     {
304       String releaseUrl = bjsRelease.getUrl();
305       String releaseVersion = bjsRelease.getVersion();
306       String releaseFile = "BioJsMSA_" + releaseVersion + ".txt";
307       if (releaseVersion.equals(repo.getLatestReleaseVersion()))
308       {
309         releaseFile = "Latest_BioJsMSA_" + releaseVersion + ".txt";
310       }
311
312       File biojsDirectory = new File(BJS_TEMPLATES_LOCAL_DIRECTORY);
313       if (!biojsDirectory.exists())
314       {
315         if (!biojsDirectory.mkdirs())
316         {
317           System.out.println("Couldn't create local directory : "
318                   + BJS_TEMPLATES_LOCAL_DIRECTORY);
319           return;
320         }
321       }
322
323       File file = new File(BJS_TEMPLATES_LOCAL_DIRECTORY + releaseFile);
324       if (!file.exists())
325       {
326
327         PrintWriter out = null;
328         try
329         {
330           out = new java.io.PrintWriter(new java.io.FileWriter(file));
331           out.print(getURLContentAsString(releaseUrl));
332         } catch (IOException e)
333         {
334           e.printStackTrace();
335         } finally
336         {
337           if (out != null)
338           {
339             out.flush();
340             out.close();
341           }
342         }
343       }
344     }
345
346   }
347
348   public static String getURLContentAsString(String url)
349           throws OutOfMemoryError
350   {
351     StringBuilder responseStrBuilder = null;
352     InputStream is = null;
353     try
354     {
355       URL resourceUrl = new URL(url);
356       is = new BufferedInputStream(resourceUrl.openStream());
357       BufferedReader br = new BufferedReader(new InputStreamReader(is));
358       responseStrBuilder = new StringBuilder();
359       String lineContent;
360
361       while ((lineContent = br.readLine()) != null)
362       {
363         responseStrBuilder.append(lineContent).append("\n");
364       }
365     } catch (OutOfMemoryError er)
366     {
367       er.printStackTrace();
368     } catch (Exception ex)
369     {
370       ex.printStackTrace();
371     } finally
372     {
373       if (is != null)
374       {
375         try
376         {
377           is.close();
378         } catch (IOException e)
379         {
380           e.printStackTrace();
381         }
382       }
383     }
384     return responseStrBuilder == null ? null : responseStrBuilder
385             .toString();
386   }
387
388   public static File getCurrentBJSTemplateFile()
389   {
390     return currentBJSTemplateFile;
391   }
392
393   public static void setCurrentBJSTemplateFile(File currentBJSTemplateFile)
394   {
395     BioJsHTMLOutput.currentBJSTemplateFile = currentBJSTemplateFile;
396   }
397
398   public static TreeMap<String, File> getBioJsMSAVersions()
399   {
400     return bioJsMSAVersions;
401   }
402
403   public static void setBioJsMSAVersions(
404           TreeMap<String, File> bioJsMSAVersions)
405   {
406     BioJsHTMLOutput.bioJsMSAVersions = bioJsMSAVersions;
407   }
408
409 }