JAL-3130 JAL-3007 Added gradle build for Java 11 and additional taskbar icon change...
[jalview.git] / src / jalview / bin / Jalview.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.bin;
22
23 import jalview.ext.so.SequenceOntology;
24 import jalview.gui.AlignFrame;
25 import jalview.gui.Desktop;
26 import jalview.gui.PromptUserConfig;
27 import jalview.io.AppletFormatAdapter;
28 import jalview.io.BioJsHTMLOutput;
29 import jalview.io.DataSourceType;
30 import jalview.io.FileFormat;
31 import jalview.io.FileFormatException;
32 import jalview.io.FileFormatI;
33 import jalview.io.FileLoader;
34 import jalview.io.HtmlSvgOutput;
35 import jalview.io.IdentifyFile;
36 import jalview.io.NewickFile;
37 import jalview.io.gff.SequenceOntologyFactory;
38 import jalview.schemes.ColourSchemeI;
39 import jalview.schemes.ColourSchemeProperty;
40 import jalview.util.MessageManager;
41 import jalview.util.Platform;
42 import jalview.ws.jws2.Jws2Discoverer;
43
44 import java.awt.Image;
45 import java.awt.Taskbar;
46 import java.io.BufferedReader;
47 import java.io.File;
48 import java.io.FileOutputStream;
49 import java.io.IOException;
50 import java.io.InputStreamReader;
51 import java.io.OutputStreamWriter;
52 import java.io.PrintWriter;
53 import java.net.MalformedURLException;
54 import java.net.URI;
55 import java.net.URISyntaxException;
56 import java.net.URL;
57 import java.security.AllPermission;
58 import java.security.CodeSource;
59 import java.security.PermissionCollection;
60 import java.security.Permissions;
61 import java.security.Policy;
62 import java.util.HashMap;
63 import java.util.Map;
64 import java.util.Vector;
65
66 import javax.swing.LookAndFeel;
67 import javax.swing.UIManager;
68
69 import groovy.lang.Binding;
70 import groovy.util.GroovyScriptEngine;
71
72 /**
73  * Main class for Jalview Application <br>
74  * <br>
75  * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
76  * jalview.bin.Jalview
77  * 
78  * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
79  * jalview.bin.Jalview jalview.bin.Jalview
80  * 
81  * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
82  * embellish '*' to e.g. '*.jar')
83  * 
84  * @author $author$
85  * @version $Revision$
86  */
87 public class Jalview
88 {
89   /*
90    * singleton instance of this class
91    */
92   private static Jalview instance;
93
94   private Desktop desktop;
95
96   public static AlignFrame currentAlignFrame;
97
98   static
99   {
100     // grab all the rights we can the JVM
101     Policy.setPolicy(new Policy()
102     {
103       @Override
104       public PermissionCollection getPermissions(CodeSource codesource)
105       {
106         Permissions perms = new Permissions();
107         perms.add(new AllPermission());
108         return (perms);
109       }
110
111       @Override
112       public void refresh()
113       {
114       }
115     });
116   }
117
118   /**
119    * keep track of feature fetching tasks.
120    * 
121    * @author JimP
122    * 
123    */
124   class FeatureFetcher
125   {
126     /*
127      * TODO: generalise to track all jalview events to orchestrate batch
128      * processing events.
129      */
130
131     private int queued = 0;
132
133     private int running = 0;
134
135     public FeatureFetcher()
136     {
137
138     }
139
140     public void addFetcher(final AlignFrame af,
141             final Vector<String> dasSources)
142     {
143       final long id = System.currentTimeMillis();
144       queued++;
145       final FeatureFetcher us = this;
146       new Thread(new Runnable()
147       {
148
149         @Override
150         public void run()
151         {
152           synchronized (us)
153           {
154             queued--;
155             running++;
156           }
157
158           af.setProgressBar(MessageManager
159                   .getString("status.das_features_being_retrived"), id);
160           af.featureSettings_actionPerformed(null);
161           af.setProgressBar(null, id);
162           synchronized (us)
163           {
164             running--;
165           }
166         }
167       }).start();
168     }
169
170     public synchronized boolean allFinished()
171     {
172       return queued == 0 && running == 0;
173     }
174
175   }
176
177   public static Jalview getInstance()
178   {
179     return instance;
180   }
181
182   /**
183    * main class for Jalview application
184    * 
185    * @param args
186    *          open <em>filename</em>
187    */
188   public static void main(String[] args)
189   {
190     instance = new Jalview();
191     instance.doMain(args);
192   }
193
194   /**
195    * @param args
196    */
197   void doMain(String[] args)
198   {
199     System.setSecurityManager(null);
200     System.out
201             .println("Java version: " + System.getProperty("java.version"));
202     System.out.println(System.getProperty("os.arch") + " "
203             + System.getProperty("os.name") + " "
204             + System.getProperty("os.version"));
205
206     ArgsParser aparser = new ArgsParser(args);
207     boolean headless = false;
208
209     if (aparser.contains("help") || aparser.contains("h"))
210     {
211       showUsage();
212       System.exit(0);
213     }
214     if (aparser.contains("nodisplay") || aparser.contains("nogui")
215             || aparser.contains("headless"))
216     {
217       System.setProperty("java.awt.headless", "true");
218       headless = true;
219     }
220     String usrPropsFile = aparser.getValue("props");
221     Cache.loadProperties(usrPropsFile); // must do this before
222     if (usrPropsFile != null)
223     {
224       System.out.println(
225               "CMD [-props " + usrPropsFile + "] executed successfully!");
226     }
227
228     // anything else!
229
230     final String jabawsUrl = aparser.getValue("jabaws");
231     if (jabawsUrl != null)
232     {
233       try
234       {
235         Jws2Discoverer.getDiscoverer().setPreferredUrl(jabawsUrl);
236         System.out.println(
237                 "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
238       } catch (MalformedURLException e)
239       {
240         System.err.println(
241                 "Invalid jabaws parameter: " + jabawsUrl + " ignored");
242       }
243     }
244
245     String defs = aparser.getValue("setprop");
246     while (defs != null)
247     {
248       int p = defs.indexOf('=');
249       if (p == -1)
250       {
251         System.err.println("Ignoring invalid setprop argument : " + defs);
252       }
253       else
254       {
255         System.out.println("Executing setprop argument: " + defs);
256         // DISABLED FOR SECURITY REASONS
257         // TODO: add a property to allow properties to be overriden by cli args
258         // Cache.setProperty(defs.substring(0,p), defs.substring(p+1));
259       }
260       defs = aparser.getValue("setprop");
261     }
262     if (System.getProperty("java.awt.headless") != null
263             && System.getProperty("java.awt.headless").equals("true"))
264     {
265       headless = true;
266     }
267     System.setProperty("http.agent",
268             "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
269     try
270     {
271       Cache.initLogger();
272     } catch (NoClassDefFoundError error)
273     {
274       error.printStackTrace();
275       System.out.println("\nEssential logging libraries not found."
276               + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
277       System.exit(0);
278     }
279
280     desktop = null;
281
282     try
283     {
284       UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
285     } catch (Exception ex)
286     {
287       System.err.println("Unexpected Look and Feel Exception");
288       ex.printStackTrace();
289     }
290     if (Platform.isAMac())
291     {
292
293       LookAndFeel lookAndFeel = ch.randelshofer.quaqua.QuaquaManager
294               .getLookAndFeel();
295       System.setProperty("com.apple.mrj.application.apple.menu.about.name",
296               "Jalview");
297       System.setProperty("apple.laf.useScreenMenuBar", "true");
298       if (lookAndFeel != null)
299       {
300         try
301         {
302           UIManager.setLookAndFeel(lookAndFeel);
303         } catch (Throwable e)
304         {
305           System.err.println(
306                   "Failed to set QuaQua look and feel: " + e.toString());
307         }
308       }
309       if (lookAndFeel == null || !(lookAndFeel.getClass()
310               .isAssignableFrom(UIManager.getLookAndFeel().getClass()))
311               || !UIManager.getLookAndFeel().getClass().toString()
312                       .toLowerCase().contains("quaqua"))
313       {
314         try
315         {
316           System.err.println(
317                   "Quaqua LaF not available on this plaform. Using VAqua(4).\nSee https://issues.jalview.org/browse/JAL-2976");
318           UIManager.setLookAndFeel("org.violetlib.aqua.AquaLookAndFeel");
319         } catch (Throwable e)
320         {
321           System.err.println(
322                   "Failed to reset look and feel: " + e.toString());
323         }
324       }
325     }
326
327     /*
328      * configure 'full' SO model if preferences say to, 
329      * else use the default (SO Lite)
330      */
331     if (Cache.getDefault("USE_FULL_SO", false))
332     {
333       SequenceOntologyFactory.setInstance(new SequenceOntology());
334     }
335
336     if (!headless)
337     {
338       desktop = new Desktop();
339       desktop.setInBatchMode(true); // indicate we are starting up
340
341       if (Taskbar.isTaskbarSupported())
342       {
343         Taskbar tb = Taskbar.getTaskbar();
344         if (tb.isSupported(Taskbar.Feature.ICON_IMAGE))
345         {
346           try
347           {
348             java.net.URL url = getClass()
349                     .getResource("/images/JalviewLogo_Huge.png");
350             if (url != null)
351             {
352               Image image = java.awt.Toolkit.getDefaultToolkit()
353                       .createImage(url);
354               tb.setIconImage(image);
355             }
356           } catch (Exception e)
357           {
358             e.printStackTrace();
359           }
360         }
361       }
362
363       desktop.setVisible(true);
364       desktop.startServiceDiscovery();
365       if (!aparser.contains("nousagestats"))
366       {
367         startUsageStats(desktop);
368       }
369       else
370       {
371         System.err.println("CMD [-nousagestats] executed successfully!");
372       }
373
374       if (!aparser.contains("noquestionnaire"))
375       {
376         String url = aparser.getValue("questionnaire");
377         if (url != null)
378         {
379           // Start the desktop questionnaire prompter with the specified
380           // questionnaire
381           Cache.log.debug("Starting questionnaire url at " + url);
382           desktop.checkForQuestionnaire(url);
383           System.out.println(
384                   "CMD questionnaire[-" + url + "] executed successfully!");
385         }
386         else
387         {
388           if (Cache.getProperty("NOQUESTIONNAIRES") == null)
389           {
390             // Start the desktop questionnaire prompter with the specified
391             // questionnaire
392             // String defurl =
393             // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
394             // //
395             String defurl = "http://www.jalview.org/cgi-bin/questionnaire.pl";
396             Cache.log.debug(
397                     "Starting questionnaire with default url: " + defurl);
398             desktop.checkForQuestionnaire(defurl);
399           }
400         }
401       }
402       else
403       {
404         System.err.println("CMD [-noquestionnaire] executed successfully!");
405       }
406
407       if (!aparser.contains("nonews"))
408       {
409         desktop.checkForNews();
410       }
411
412       BioJsHTMLOutput.updateBioJS();
413     }
414
415     String file = null, data = null;
416     FileFormatI format = null;
417     DataSourceType protocol = null;
418     FileLoader fileLoader = new FileLoader(!headless);
419
420     String groovyscript = null; // script to execute after all loading is
421     // completed one way or another
422     // extract groovy argument and execute if necessary
423     groovyscript = aparser.getValue("groovy", true);
424     file = aparser.getValue("open", true);
425
426     if (file == null && desktop == null)
427     {
428       System.out.println("No files to open!");
429       System.exit(1);
430     }
431     String vamsasImport = aparser.getValue("vdoc");
432     String vamsasSession = aparser.getValue("vsess");
433     if (vamsasImport != null || vamsasSession != null)
434     {
435       if (desktop == null || headless)
436       {
437         System.out.println(
438                 "Headless vamsas sessions not yet supported. Sorry.");
439         System.exit(1);
440       }
441       // if we have a file, start a new session and import it.
442       boolean inSession = false;
443       if (vamsasImport != null)
444       {
445         try
446         {
447           DataSourceType viprotocol = AppletFormatAdapter
448                   .checkProtocol(vamsasImport);
449           if (viprotocol == DataSourceType.FILE)
450           {
451             inSession = desktop.vamsasImport(new File(vamsasImport));
452           }
453           else if (viprotocol == DataSourceType.URL)
454           {
455             inSession = desktop.vamsasImport(new URL(vamsasImport));
456           }
457
458         } catch (Exception e)
459         {
460           System.err.println("Exeption when importing " + vamsasImport
461                   + " as a vamsas document.");
462           e.printStackTrace();
463         }
464         if (!inSession)
465         {
466           System.err.println("Failed to import " + vamsasImport
467                   + " as a vamsas document.");
468         }
469         else
470         {
471           System.out.println("Imported Successfully into new session "
472                   + desktop.getVamsasApplication().getCurrentSession());
473         }
474       }
475       if (vamsasSession != null)
476       {
477         if (vamsasImport != null)
478         {
479           // close the newly imported session and import the Jalview specific
480           // remnants into the new session later on.
481           desktop.vamsasStop_actionPerformed(null);
482         }
483         // now join the new session
484         try
485         {
486           if (desktop.joinVamsasSession(vamsasSession))
487           {
488             System.out.println(
489                     "Successfully joined vamsas session " + vamsasSession);
490           }
491           else
492           {
493             System.err.println("WARNING: Failed to join vamsas session "
494                     + vamsasSession);
495           }
496         } catch (Exception e)
497         {
498           System.err.println(
499                   "ERROR: Failed to join vamsas session " + vamsasSession);
500           e.printStackTrace();
501         }
502         if (vamsasImport != null)
503         {
504           // the Jalview specific remnants can now be imported into the new
505           // session at the user's leisure.
506           Cache.log.info(
507                   "Skipping Push for import of data into existing vamsas session."); // TODO:
508           // enable
509           // this
510           // when
511           // debugged
512           // desktop.getVamsasApplication().push_update();
513         }
514       }
515     }
516     long progress = -1;
517     // Finally, deal with the remaining input data.
518     if (file != null)
519     {
520       if (!headless)
521       {
522         desktop.setProgressBar(
523                 MessageManager
524                         .getString("status.processing_commandline_args"),
525                 progress = System.currentTimeMillis());
526       }
527       System.out.println("CMD [-open " + file + "] executed successfully!");
528
529       if (!file.startsWith("http://"))
530       {
531         if (!(new File(file)).exists())
532         {
533           System.out.println("Can't find " + file);
534           if (headless)
535           {
536             System.exit(1);
537           }
538         }
539       }
540
541       protocol = AppletFormatAdapter.checkProtocol(file);
542
543       try
544       {
545         format = new IdentifyFile().identify(file, protocol);
546       } catch (FileFormatException e1)
547       {
548         // TODO ?
549       }
550
551       AlignFrame af = fileLoader.LoadFileWaitTillLoaded(file, protocol,
552               format);
553       if (af == null)
554       {
555         System.out.println("error");
556       }
557       else
558       {
559         setCurrentAlignFrame(af);
560         data = aparser.getValue("colour", true);
561         if (data != null)
562         {
563           data.replaceAll("%20", " ");
564
565           ColourSchemeI cs = ColourSchemeProperty
566                   .getColourScheme(af.getViewport(),
567                           af.getViewport().getAlignment(), data);
568
569           if (cs != null)
570           {
571             System.out.println(
572                     "CMD [-color " + data + "] executed successfully!");
573           }
574           af.changeColour(cs);
575         }
576
577         // Must maintain ability to use the groups flag
578         data = aparser.getValue("groups", true);
579         if (data != null)
580         {
581           af.parseFeaturesFile(data,
582                   AppletFormatAdapter.checkProtocol(data));
583           // System.out.println("Added " + data);
584           System.out.println(
585                   "CMD groups[-" + data + "]  executed successfully!");
586         }
587         data = aparser.getValue("features", true);
588         if (data != null)
589         {
590           af.parseFeaturesFile(data,
591                   AppletFormatAdapter.checkProtocol(data));
592           // System.out.println("Added " + data);
593           System.out.println(
594                   "CMD [-features " + data + "]  executed successfully!");
595         }
596
597         data = aparser.getValue("annotations", true);
598         if (data != null)
599         {
600           af.loadJalviewDataFile(data, null, null, null);
601           // System.out.println("Added " + data);
602           System.out.println(
603                   "CMD [-annotations " + data + "] executed successfully!");
604         }
605         // set or clear the sortbytree flag.
606         if (aparser.contains("sortbytree"))
607         {
608           af.getViewport().setSortByTree(true);
609           if (af.getViewport().getSortByTree())
610           {
611             System.out.println("CMD [-sortbytree] executed successfully!");
612           }
613         }
614         if (aparser.contains("no-annotation"))
615         {
616           af.getViewport().setShowAnnotation(false);
617           if (!af.getViewport().isShowAnnotation())
618           {
619             System.out.println("CMD no-annotation executed successfully!");
620           }
621         }
622         if (aparser.contains("nosortbytree"))
623         {
624           af.getViewport().setSortByTree(false);
625           if (!af.getViewport().getSortByTree())
626           {
627             System.out
628                     .println("CMD [-nosortbytree] executed successfully!");
629           }
630         }
631         data = aparser.getValue("tree", true);
632         if (data != null)
633         {
634           try
635           {
636             System.out.println(
637                     "CMD [-tree " + data + "] executed successfully!");
638             NewickFile nf = new NewickFile(data,
639                     AppletFormatAdapter.checkProtocol(data));
640             af.getViewport()
641                     .setCurrentTree(af.showNewickTree(nf, data).getTree());
642           } catch (IOException ex)
643           {
644             System.err.println("Couldn't add tree " + data);
645             ex.printStackTrace(System.err);
646           }
647         }
648         // TODO - load PDB structure(s) to alignment JAL-629
649         // (associate with identical sequence in alignment, or a specified
650         // sequence)
651         if (groovyscript != null)
652         {
653           // Execute the groovy script after we've done all the rendering stuff
654           // and before any images or figures are generated.
655           System.out.println("Executing script " + groovyscript);
656           executeGroovyScript(groovyscript, af);
657           System.out.println("CMD groovy[" + groovyscript
658                   + "] executed successfully!");
659           groovyscript = null;
660         }
661         String imageName = "unnamed.png";
662         while (aparser.getSize() > 1)
663         {
664           String outputFormat = aparser.nextValue();
665           file = aparser.nextValue();
666
667           if (outputFormat.equalsIgnoreCase("png"))
668           {
669             af.createPNG(new File(file));
670             imageName = (new File(file)).getName();
671             System.out.println("Creating PNG image: " + file);
672             continue;
673           }
674           else if (outputFormat.equalsIgnoreCase("svg"))
675           {
676             File imageFile = new File(file);
677             imageName = imageFile.getName();
678             af.createSVG(imageFile);
679             System.out.println("Creating SVG image: " + file);
680             continue;
681           }
682           else if (outputFormat.equalsIgnoreCase("html"))
683           {
684             File imageFile = new File(file);
685             imageName = imageFile.getName();
686             HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
687             htmlSVG.exportHTML(file);
688
689             System.out.println("Creating HTML image: " + file);
690             continue;
691           }
692           else if (outputFormat.equalsIgnoreCase("biojsmsa"))
693           {
694             if (file == null)
695             {
696               System.err.println("The output html file must not be null");
697               return;
698             }
699             try
700             {
701               BioJsHTMLOutput.refreshVersionInfo(
702                       BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
703             } catch (URISyntaxException e)
704             {
705               e.printStackTrace();
706             }
707             BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
708             bjs.exportHTML(file);
709             System.out
710                     .println("Creating BioJS MSA Viwer HTML file: " + file);
711             continue;
712           }
713           else if (outputFormat.equalsIgnoreCase("imgMap"))
714           {
715             af.createImageMap(new File(file), imageName);
716             System.out.println("Creating image map: " + file);
717             continue;
718           }
719           else if (outputFormat.equalsIgnoreCase("eps"))
720           {
721             File outputFile = new File(file);
722             System.out.println(
723                     "Creating EPS file: " + outputFile.getAbsolutePath());
724             af.createEPS(outputFile);
725             continue;
726           }
727
728           if (af.saveAlignment(file, format))
729           {
730             System.out.println("Written alignment in " + format
731                     + " format to " + file);
732           }
733           else
734           {
735             System.out.println("Error writing file " + file + " in "
736                     + format + " format!!");
737           }
738
739         }
740
741         while (aparser.getSize() > 0)
742         {
743           System.out.println("Unknown arg: " + aparser.nextValue());
744         }
745       }
746     }
747     AlignFrame startUpAlframe = null;
748     // We'll only open the default file if the desktop is visible.
749     // And the user
750     // ////////////////////
751
752     if (!headless && file == null && vamsasImport == null
753             && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true))
754     {
755       file = jalview.bin.Cache.getDefault("STARTUP_FILE",
756               jalview.bin.Cache.getDefault("www.jalview.org",
757                       "http://www.jalview.org")
758                       + "/examples/exampleFile_2_7.jar");
759       if (file.equals(
760               "http://www.jalview.org/examples/exampleFile_2_3.jar"))
761       {
762         // hardwire upgrade of the startup file
763         file.replace("_2_3.jar", "_2_7.jar");
764         // and remove the stale setting
765         jalview.bin.Cache.removeProperty("STARTUP_FILE");
766       }
767
768       protocol = DataSourceType.FILE;
769
770       if (file.indexOf("http:") > -1)
771       {
772         protocol = DataSourceType.URL;
773       }
774
775       if (file.endsWith(".jar"))
776       {
777         format = FileFormat.Jalview;
778       }
779       else
780       {
781         try
782         {
783           format = new IdentifyFile().identify(file, protocol);
784         } catch (FileFormatException e)
785         {
786           // TODO what?
787         }
788       }
789
790       startUpAlframe = fileLoader.LoadFileWaitTillLoaded(file, protocol,
791               format);
792       // extract groovy arguments before anything else.
793     }
794
795     // Once all other stuff is done, execute any groovy scripts (in order)
796     if (groovyscript != null)
797     {
798       if (Cache.groovyJarsPresent())
799       {
800         System.out.println("Executing script " + groovyscript);
801         executeGroovyScript(groovyscript, startUpAlframe);
802       }
803       else
804       {
805         System.err.println(
806                 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
807                         + groovyscript);
808       }
809     }
810     // and finally, turn off batch mode indicator - if the desktop still exists
811     if (desktop != null)
812     {
813       if (progress != -1)
814       {
815         desktop.setProgressBar(null, progress);
816       }
817       desktop.setInBatchMode(false);
818     }
819   }
820
821   private static void showUsage()
822   {
823     System.out.println(
824             "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
825                     + "-nodisplay\tRun Jalview without User Interface.\n"
826                     + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
827                     + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
828                     + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
829                     + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
830                     + "-features FILE\tUse the given file to mark features on the alignment.\n"
831                     + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
832                     + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
833                     + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
834                     + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
835                     + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
836                     + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
837                     + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
838                     + "-json FILE\tCreate alignment file FILE in JSON format.\n"
839                     + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
840                     + "-png FILE\tCreate PNG image FILE from alignment.\n"
841                     + "-svg FILE\tCreate SVG image FILE from alignment.\n"
842                     + "-html FILE\tCreate HTML file from alignment.\n"
843                     + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
844                     + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
845                     + "-eps FILE\tCreate EPS file FILE from alignment.\n"
846                     + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
847                     + "-noquestionnaire\tTurn off questionnaire check.\n"
848                     + "-nonews\tTurn off check for Jalview news.\n"
849                     + "-nousagestats\tTurn off google analytics tracking for this session.\n"
850                     + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
851                     // +
852                     // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
853                     // after all other properties files have been read\n\t
854                     // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
855                     // passed in correctly)"
856                     + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
857                     + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
858                     // +
859                     // "-vdoc vamsas-document\tImport vamsas document into new
860                     // session or join existing session with same URN\n"
861                     // + "-vses vamsas-session\tJoin session with given URN\n"
862                     + "-groovy FILE\tExecute groovy script in FILE, after all other arguments have been processed (if FILE is the text 'STDIN' then the file will be read from STDIN)\n"
863                     + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
864   }
865
866   private static void startUsageStats(final Desktop desktop)
867   {
868     /**
869      * start a User Config prompt asking if we can log usage statistics.
870      */
871     PromptUserConfig prompter = new PromptUserConfig(Desktop.desktop,
872             "USAGESTATS", "Jalview Usage Statistics",
873             "Do you want to help make Jalview better by enabling "
874                     + "the collection of usage statistics with Google Analytics ?"
875                     + "\n\n(you can enable or disable usage tracking in the preferences)",
876             new Runnable()
877             {
878               @Override
879               public void run()
880               {
881                 Cache.log.debug(
882                         "Initialising googletracker for usage stats.");
883                 Cache.initGoogleTracker();
884                 Cache.log.debug("Tracking enabled.");
885               }
886             }, new Runnable()
887             {
888               @Override
889               public void run()
890               {
891                 Cache.log.debug("Not enabling Google Tracking.");
892               }
893             }, null, true);
894     desktop.addDialogThread(prompter);
895   }
896
897   /**
898    * Locate the given string as a file and pass it to the groovy interpreter.
899    * 
900    * @param groovyscript
901    *          the script to execute
902    * @param jalviewContext
903    *          the Jalview Desktop object passed in to the groovy binding as the
904    *          'Jalview' object.
905    */
906   private void executeGroovyScript(String groovyscript, AlignFrame af)
907   {
908     /**
909      * for scripts contained in files
910      */
911     File tfile = null;
912     /**
913      * script's URI
914      */
915     URL sfile = null;
916     if (groovyscript.trim().equals("STDIN"))
917     {
918       // read from stdin into a tempfile and execute it
919       try
920       {
921         tfile = File.createTempFile("jalview", "groovy");
922         PrintWriter outfile = new PrintWriter(
923                 new OutputStreamWriter(new FileOutputStream(tfile)));
924         BufferedReader br = new BufferedReader(
925                 new InputStreamReader(System.in));
926         String line = null;
927         while ((line = br.readLine()) != null)
928         {
929           outfile.write(line + "\n");
930         }
931         br.close();
932         outfile.flush();
933         outfile.close();
934
935       } catch (Exception ex)
936       {
937         System.err.println("Failed to read from STDIN into tempfile "
938                 + ((tfile == null) ? "(tempfile wasn't created)"
939                         : tfile.toString()));
940         ex.printStackTrace();
941         return;
942       }
943       try
944       {
945         sfile = tfile.toURI().toURL();
946       } catch (Exception x)
947       {
948         System.err.println(
949                 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
950                         + tfile.toURI());
951         x.printStackTrace();
952         return;
953       }
954     }
955     else
956     {
957       try
958       {
959         sfile = new URI(groovyscript).toURL();
960       } catch (Exception x)
961       {
962         tfile = new File(groovyscript);
963         if (!tfile.exists())
964         {
965           System.err.println("File '" + groovyscript + "' does not exist.");
966           return;
967         }
968         if (!tfile.canRead())
969         {
970           System.err.println("File '" + groovyscript + "' cannot be read.");
971           return;
972         }
973         if (tfile.length() < 1)
974         {
975           System.err.println("File '" + groovyscript + "' is empty.");
976           return;
977         }
978         try
979         {
980           sfile = tfile.getAbsoluteFile().toURI().toURL();
981         } catch (Exception ex)
982         {
983           System.err.println("Failed to create a file URL for "
984                   + tfile.getAbsoluteFile());
985           return;
986         }
987       }
988     }
989     try
990     {
991       Map<String, Object> vbinding = new HashMap<>();
992       vbinding.put("Jalview", this);
993       if (af != null)
994       {
995         vbinding.put("currentAlFrame", af);
996       }
997       Binding gbinding = new Binding(vbinding);
998       GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
999       gse.run(sfile.toString(), gbinding);
1000       if ("STDIN".equals(groovyscript))
1001       {
1002         // delete temp file that we made -
1003         // only if it was successfully executed
1004         tfile.delete();
1005       }
1006     } catch (Exception e)
1007     {
1008       System.err.println("Exception Whilst trying to execute file " + sfile
1009               + " as a groovy script.");
1010       e.printStackTrace(System.err);
1011
1012     }
1013   }
1014
1015   public static boolean isHeadlessMode()
1016   {
1017     String isheadless = System.getProperty("java.awt.headless");
1018     if (isheadless != null && isheadless.equalsIgnoreCase("true"))
1019     {
1020       return true;
1021     }
1022     return false;
1023   }
1024
1025   public AlignFrame[] getAlignFrames()
1026   {
1027     return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1028             : Desktop.getAlignFrames();
1029
1030   }
1031
1032   /**
1033    * Quit method delegates to Desktop.quit - unless running in headless mode
1034    * when it just ends the JVM
1035    */
1036   public void quit()
1037   {
1038     if (desktop != null)
1039     {
1040       desktop.quit();
1041     }
1042     else
1043     {
1044       System.exit(0);
1045     }
1046   }
1047
1048   public static AlignFrame getCurrentAlignFrame()
1049   {
1050     return Jalview.currentAlignFrame;
1051   }
1052
1053   public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
1054   {
1055     Jalview.currentAlignFrame = currentAlignFrame;
1056   }
1057 }