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