JAL-3451 JalviewJS embedded mode not resizing
[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.api.AlignCalcWorkerI;
24 import jalview.api.AlignFrameI;
25 import jalview.api.AlignViewportI;
26 import jalview.api.JalviewApp;
27 import jalview.api.StructureSelectionManagerProvider;
28 import jalview.bin.ApplicationSingletonProvider.ApplicationSingletonI;
29 import jalview.datamodel.ColumnSelection;
30 import jalview.datamodel.HiddenColumns;
31 import jalview.datamodel.PDBEntry;
32 import jalview.datamodel.SequenceGroup;
33 import jalview.datamodel.SequenceI;
34 import jalview.ext.so.SequenceOntology;
35 import jalview.gui.AlignFrame;
36 import jalview.gui.AlignViewport;
37 import jalview.gui.AlignmentPanel;
38 import jalview.gui.CalculationChooser;
39 import jalview.gui.Desktop;
40 import jalview.gui.Preferences;
41 import jalview.gui.PromptUserConfig;
42 import jalview.gui.StructureViewer;
43 import jalview.io.AppletFormatAdapter;
44 import jalview.io.BioJsHTMLOutput;
45 import jalview.io.DataSourceType;
46 import jalview.io.FileFormat;
47 import jalview.io.FileFormatException;
48 import jalview.io.FileFormatI;
49 import jalview.io.FileFormats;
50 import jalview.io.FileLoader;
51 import jalview.io.HtmlSvgOutput;
52 import jalview.io.IdentifyFile;
53 import jalview.io.NewickFile;
54 import jalview.io.gff.SequenceOntologyFactory;
55 import jalview.javascript.JSFunctionExec;
56 import jalview.javascript.MouseOverStructureListener;
57 import jalview.renderer.seqfeatures.FeatureRenderer;
58 import jalview.schemes.ColourSchemeI;
59 import jalview.schemes.ColourSchemeProperty;
60 import jalview.structure.SelectionSource;
61 import jalview.structure.VamsasSource;
62 import jalview.util.MessageManager;
63 import jalview.util.Platform;
64 import jalview.ws.jws2.Jws2Discoverer;
65
66 import java.applet.AppletContext;
67 import java.io.BufferedReader;
68 import java.io.File;
69 import java.io.FileOutputStream;
70 import java.io.IOException;
71 import java.io.InputStreamReader;
72 import java.io.OutputStreamWriter;
73 import java.io.PrintWriter;
74 import java.net.MalformedURLException;
75 import java.net.URI;
76 import java.net.URISyntaxException;
77 import java.net.URL;
78 import java.security.AllPermission;
79 import java.security.CodeSource;
80 import java.security.PermissionCollection;
81 import java.security.Permissions;
82 import java.security.Policy;
83 import java.util.HashMap;
84 import java.util.Hashtable;
85 import java.util.Map;
86 import java.util.Vector;
87
88 import javax.swing.LookAndFeel;
89 import javax.swing.UIManager;
90
91 import groovy.lang.Binding;
92 import groovy.util.GroovyScriptEngine;
93 import netscape.javascript.JSObject;
94
95 /**
96  * Main class for Jalview Application <br>
97  * <br>
98  * start with: java -classpath "$PATH_TO_LIB$/*:$PATH_TO_CLASSES$" \
99  * jalview.bin.Jalview
100  * 
101  * or on Windows: java -classpath "$PATH_TO_LIB$/*;$PATH_TO_CLASSES$" \
102  * jalview.bin.Jalview jalview.bin.Jalview
103  * 
104  * (ensure -classpath arg is quoted to avoid shell expansion of '*' and do not
105  * embellish '*' to e.g. '*.jar')
106  * 
107  * @author $author$
108  * @version $Revision$
109  */
110 public class Jalview implements ApplicationSingletonI, JalviewJSApi
111 {
112
113   public static Jalview getInstance()
114   {
115     return (Jalview) ApplicationSingletonProvider
116             .getInstance(Jalview.class);
117   }
118
119   private Jalview()
120   {
121   }
122
123   static
124   {
125     Platform.getURLCommandArguments();
126   }
127
128   private boolean headless;
129
130   public static boolean isHeadlessMode()
131   {
132     return getInstance().headless;
133   }
134
135   private Desktop desktop;
136
137   private AlignFrame currentAlignFrame;
138
139   public boolean isJavaAppletTag;
140
141   public String appletResourcePath;
142
143   JalviewAppLoader appLoader;
144
145   protected JSFunctionExec jsFunctionExec;
146
147   private boolean noCalculation, noMenuBar, noStatus;
148
149   private boolean noAnnotation;
150
151   public boolean getStartCalculations()
152   {
153     return !noCalculation;
154   }
155
156   public boolean getAllowMenuBar()
157   {
158     return !noMenuBar;
159   }
160
161   public boolean getShowStatus()
162   {
163     return !noStatus;
164   }
165
166   public boolean getShowAnnotation()
167   {
168     return !noAnnotation;
169   }
170
171   public static AlignFrame getCurrentAlignFrame()
172   {
173     return getInstance().currentAlignFrame;
174   }
175
176   public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
177   {
178     getInstance().currentAlignFrame = currentAlignFrame;
179   }
180
181   static
182   {
183     if (!Platform.isJS())
184     /**
185      * Java only
186      * 
187      * @j2sIgnore
188      */
189     {
190       // grab all the rights we can for the JVM
191       Policy.setPolicy(new Policy()
192       {
193         @Override
194         public PermissionCollection getPermissions(CodeSource codesource)
195         {
196           Permissions perms = new Permissions();
197           perms.add(new AllPermission());
198           return (perms);
199         }
200
201         @Override
202         public void refresh()
203         {
204         }
205       });
206     }
207   }
208
209   /**
210    * keep track of feature fetching tasks.
211    * 
212    * @author JimP
213    * 
214    */
215   class FeatureFetcher
216   {
217     /*
218      * TODO: generalise to track all jalview events to orchestrate batch
219      * processing events.
220      */
221
222     private int queued = 0;
223
224     private int running = 0;
225
226     public FeatureFetcher()
227     {
228
229     }
230
231     public void addFetcher(final AlignFrame af,
232             final Vector<String> dasSources)
233     {
234       final long id = System.currentTimeMillis();
235       queued++;
236       final FeatureFetcher us = this;
237       new Thread(new Runnable()
238       {
239
240         @Override
241         public void run()
242         {
243           synchronized (us)
244           {
245             queued--;
246             running++;
247           }
248
249           af.setProgressBar(MessageManager
250                   .getString("status.das_features_being_retrived"), id);
251           af.featureSettings_actionPerformed(null);
252           af.setProgressBar(null, id);
253           synchronized (us)
254           {
255             running--;
256           }
257         }
258       }).start();
259     }
260
261     public synchronized boolean allFinished()
262     {
263       return queued == 0 && running == 0;
264     }
265
266   }
267
268   /**
269    * main class for Jalview application
270    * 
271    * @param args
272    *          open <em>filename</em>
273    */
274   public static void main(String[] args)
275   {
276     // Platform.startJavaLogging();
277     getInstance().doMain(args);
278   }
279
280
281   @SuppressWarnings("unused")
282   /**
283    * @param args
284    */
285   void doMain(String[] args)
286   {
287
288     boolean isJS = Platform.isJS();
289     if (isJS)
290     {
291       Platform.setAppClass(this);
292     }
293     else
294     {
295       System.setSecurityManager(null);
296     }
297
298     System.out
299             .println("Java version: " + System.getProperty("java.version"));
300     System.out.println(System.getProperty("os.arch") + " "
301             + System.getProperty("os.name") + " "
302             + System.getProperty("os.version"));
303
304     ArgsParser aparser = new ArgsParser(args);
305
306     String usrPropsFile = aparser.getValue(ArgsParser.PROPS);
307     Cache.loadProperties(usrPropsFile);
308
309     if (aparser.contains(ArgsParser.NODISPLAY)
310             || aparser.contains(ArgsParser.NOGUI)
311             || aparser.contains(ArgsParser.HEADLESS)
312             || "true".equals(System.getProperty("java.awt.headless")))
313     {
314       headless = true;
315     }
316
317     if (isJS)
318     {
319       isJavaAppletTag = aparser.isApplet();
320       if (isJavaAppletTag)
321       {
322         Preferences.setAppletDefaults();
323         Cache.loadProperties(usrPropsFile); // again, because we
324         // might be changing defaults here?
325       }
326       System.out.println(
327               "<Applet> found: " + aparser.getValue("Info.j2sAppletID"));
328       appletResourcePath = aparser.getValue("Info.resourcePath");
329     }
330     else
331     /**
332      * Java only
333      * 
334      * @j2sIgnore
335      */
336     {
337       if (usrPropsFile != null)
338       {
339         System.out.println(
340                 "CMD [-props " + usrPropsFile + "] executed successfully!");
341       }
342
343       if (aparser.contains("help") || aparser.contains("h"))
344       {
345         showUsage();
346         System.exit(0);
347       }
348
349
350       // anything else!
351
352       final String jabawsUrl = aparser.getValue(ArgsParser.JABAWS);
353       if (jabawsUrl != null)
354       {
355         try
356         {
357           Jws2Discoverer.getInstance().setPreferredUrl(jabawsUrl);
358           System.out.println(
359                   "CMD [-jabaws " + jabawsUrl + "] executed successfully!");
360         } catch (MalformedURLException e)
361         {
362           System.err.println(
363                   "Invalid jabaws parameter: " + jabawsUrl + " ignored");
364         }
365       }
366
367     }
368     // check for property setting
369     String defs = aparser.getValue(ArgsParser.SETPROP);
370     while (defs != null)
371     {
372       int p = defs.indexOf('=');
373       if (p == -1)
374       {
375         System.err.println("Ignoring invalid setprop argument : " + defs);
376       }
377       else
378       {
379         System.out.println("Executing setprop argument: " + defs);
380         if (isJS)
381         {
382           Cache.setProperty(defs.substring(0, p), defs.substring(p + 1));
383         }
384       }
385       defs = aparser.getValue(ArgsParser.SETPROP);
386     }
387     System.setProperty("http.agent",
388             "Jalview Desktop/" + Cache.getDefault("VERSION", "Unknown"));
389     try
390     {
391       Cache.initLogger();
392     } catch (NoClassDefFoundError error)
393     {
394       error.printStackTrace();
395       System.out.println("\nEssential logging libraries not found."
396               + "\nUse: java -classpath \"$PATH_TO_LIB$/*:$PATH_TO_CLASSES$\" jalview.bin.Jalview");
397       System.exit(0);
398     }
399
400     desktop = null;
401
402     try
403     {
404       if (!isJS && Platform.isWin())
405        {
406         UIManager.setLookAndFeel(
407                 headless ? "javax.swing.plaf.metal.MetalLookAndFeel"
408                         : UIManager.getSystemLookAndFeelClassName());
409 //      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
410       }
411     } catch (Exception ex)
412     {
413       System.err.println("Unexpected Look and Feel Exception");
414       ex.printStackTrace();
415     }
416     if (Platform.isAMacAndNotJS())
417     {
418
419       LookAndFeel lookAndFeel = ch.randelshofer.quaqua.QuaquaManager
420               .getLookAndFeel();
421       System.setProperty("com.apple.mrj.application.apple.menu.about.name",
422               "Jalview");
423       System.setProperty("apple.laf.useScreenMenuBar", "true");
424       if (lookAndFeel != null)
425       {
426         try
427         {
428           UIManager.setLookAndFeel(lookAndFeel);
429         } catch (Throwable e)
430         {
431           System.err.println(
432                   "Failed to set QuaQua look and feel: " + e.toString());
433         }
434       }
435       if (lookAndFeel == null
436               || !(lookAndFeel.getClass().isAssignableFrom(
437                       UIManager.getLookAndFeel().getClass()))
438               || !UIManager.getLookAndFeel().getClass().toString()
439                       .toLowerCase().contains("quaqua"))
440       {
441         try
442         {
443           System.err.println(
444                   "Quaqua LaF not available on this plaform. Using VAqua(4).\nSee https://issues.jalview.org/browse/JAL-2976");
445           UIManager.setLookAndFeel("org.violetlib.aqua.AquaLookAndFeel");
446         } catch (Throwable e)
447         {
448           System.err.println(
449                   "Failed to reset look and feel: " + e.toString());
450         }
451       }
452     }
453
454     /*
455      * configure 'full' SO model if preferences say to, 
456      * else use the default (SO Lite)
457      */
458     if (Cache.getDefault(Preferences.USE_FULL_SO, false))
459     {
460       SequenceOntologyFactory.setSequenceOntology(new SequenceOntology());
461     }
462
463     if (!headless)
464     {
465       desktop = Desktop.getInstance();
466       desktop.setInBatchMode(true); // indicate we are starting up
467       desktop.setVisible(true);
468
469       if (!isJS)
470       /**
471        * Java only
472        * 
473        * @j2sIgnore
474        */
475       {
476         desktop.startServiceDiscovery();
477         if (!aparser.contains(ArgsParser.NOUSAGESTATS))
478         {
479           startUsageStats(desktop);
480         }
481         else
482         {
483           System.err.println("CMD [-nousagestats] executed successfully!");
484         }
485
486         if (!aparser.contains(ArgsParser.NOQUESTIONNAIRE))
487         {
488           String url = aparser.getValue(ArgsParser.QUESTIONNAIRE);
489           if (url != null)
490           {
491             // Start the desktop questionnaire prompter with the specified
492             // questionnaire
493             Cache.log.debug("Starting questionnaire url at " + url);
494             desktop.checkForQuestionnaire(url);
495             System.out.println("CMD questionnaire[-" + url
496                     + "] executed successfully!");
497           }
498           else
499           {
500             if (Cache.getProperty(Preferences.NOQUESTIONNAIRES) == null)
501             {
502               // Start the desktop questionnaire prompter with the specified
503               // questionnaire
504               // String defurl =
505               // "http://anaplog.compbio.dundee.ac.uk/cgi-bin/questionnaire.pl";
506               // //
507               String defurl = "http://www.jalview.org/cgi-bin/questionnaire.pl";
508               Cache.log.debug(
509                       "Starting questionnaire with default url: " + defurl);
510               desktop.checkForQuestionnaire(defurl);
511             }
512           }
513         }
514         else
515         {
516           System.err
517                   .println("CMD [-noquestionnaire] executed successfully!");
518         }
519
520         if (!aparser.contains(ArgsParser.NONEWS))
521         {
522           desktop.checkForNews();
523         }
524
525         BioJsHTMLOutput.updateBioJS();
526       }
527     }
528
529     parseArguments(aparser, true);
530   }
531
532   /**
533    * Allow an outside entity to initiate the second half of argument parsing
534    * (only).
535    * 
536    * @param args
537    * @return null is good
538    */
539   @Override
540   public Object parseArguments(String[] args)
541   {
542
543     try
544     {
545       ArgsParser aparser = new ArgsParser(args);
546       return parseArguments(aparser, false);
547     } catch (Throwable t)
548     {
549       return t;
550     }
551   }
552
553   /**
554    * 
555    * @param aparser
556    * @param isStartup
557    * @return
558    */
559   private Object parseArguments(ArgsParser aparser, boolean isStartup)
560   {
561     boolean isJS = Platform.isJS();
562
563     Desktop desktop = (headless ? null : Desktop.getInstance());
564     // script to execute after all loading is
565     // completed one way or another
566     // extract groovy argument and execute if necessary
567     String groovyscript = (isJS ? null
568             : aparser.getValue(ArgsParser.GROOVY, true));
569     String file = aparser.getValue(ArgsParser.OPEN, true);
570     // BH this here to allow split frame; not working as of 5/17/2019
571     String file2 = aparser.getValue(ArgsParser.OPEN2, true);
572     String fileFormat = (isJavaAppletTag
573             ? aparser.getAppletValue("format", null)
574             : null);
575     FileFormatI format = null;
576     DataSourceType protocol = null;
577
578     if (file == null && desktop == null)
579     {
580       System.out.println("No files to open!");
581       System.exit(1);
582     }
583     boolean haveImport = checkStartVamas(aparser);
584     // Finally, deal with the remaining input data.
585     long progress = -1;
586     if (file == null && isJavaAppletTag)
587     {
588       // Maybe the sequences are added as parameters
589       StringBuffer data = new StringBuffer("PASTE");
590       int i = 1;
591       while ((file = aparser.getAppletValue("sequence" + i, null)) != null)
592       {
593         data.append(file.toString() + "\n");
594         i++;
595       }
596       if (data.length() > 5)
597       {
598         file = data.toString();
599       }
600     }
601
602     String data;
603
604     if (file != null)
605     {
606
607       if (!headless)
608       {
609         desktop.setProgressBar(
610                 MessageManager
611                         .getString("status.processing_commandline_args"),
612                 progress = System.currentTimeMillis());
613       }
614
615       if (!isJS)
616       /**
617        * ignore in JavaScript -- can't just check file existence - could load
618        * it?
619        * 
620        * @j2sIgnore
621        */
622       {
623         if (!file.startsWith("http://") && !file.startsWith("https://"))
624         // BH 2019 added https check for Java
625         {
626           if (!(new File(file)).exists())
627           {
628             System.out.println("Can't find " + file);
629             if (headless)
630             {
631               System.exit(1);
632             }
633           }
634         }
635       }
636
637       protocol = AppletFormatAdapter.checkProtocol(file);
638
639       try
640       {
641         format = (isJavaAppletTag && fileFormat != null
642                 ? FileFormats.getInstance().forName(fileFormat)
643                 : null);
644         if (format == null)
645         {
646           format = new IdentifyFile().identify(file, protocol);
647         }
648       } catch (FileFormatException e1)
649       {
650         // TODO ?
651       }
652
653       if (aparser.contains(ArgsParser.NOMENUBAR))
654       {
655         noMenuBar = true;
656         System.out.println("CMD [nomenu] executed successfully!");
657       }
658
659       if (aparser.contains(ArgsParser.NOSTATUS))
660       {
661         noStatus = true;
662         System.out.println("CMD [nostatus] executed successfully!");
663       }
664
665       if (aparser.contains(ArgsParser.NOANNOTATION)
666               || aparser.contains(ArgsParser.NOANNOTATION2))
667       {
668         noAnnotation = true;
669         System.out.println("CMD no-annotation executed successfully!");
670       }
671       if (aparser.contains(ArgsParser.NOCALCULATION))
672       {
673         noCalculation = true;
674         System.out.println("CMD [nocalculation] executed successfully!");
675       }
676
677       AlignFrame af = new FileLoader(!headless).loadFileWaitTillLoaded(file,
678               protocol, format);
679       if (af == null)
680       {
681         System.out.println("error");
682       }
683       else
684       {
685         System.out
686                 .println("CMD [-open " + file + "] executed successfully!");
687         if (file2 != null)
688         {
689           protocol = AppletFormatAdapter.checkProtocol(file2);
690           try
691           {
692             format = new IdentifyFile().identify(file2, protocol);
693           } catch (FileFormatException e1)
694           {
695             // TODO ?
696           }
697           AlignFrame af2 = new FileLoader(!headless)
698                   .loadFileWaitTillLoaded(file2, protocol, format);
699           if (af2 == null)
700           {
701             System.out.println("error");
702           }
703           else
704           {
705             AlignViewport.openLinkedAlignmentAs(af,
706                     af.getViewport().getAlignment(),
707                     af2.getViewport().getAlignment(), "",
708                     AlignViewport.SPLIT_FRAME);
709             System.out.println(
710                     "CMD [-open2 " + file2 + "] executed successfully!");
711           }
712         }
713
714         setCurrentAlignFrame(af);
715
716         // TODO: file2 How to implement file2 for the applet spit screen?
717
718         data = aparser.getValue(ArgsParser.COLOUR, true);
719         if (data != null)
720         {
721           data.replaceAll("%20", " ");
722
723           ColourSchemeI cs = ColourSchemeProperty.getColourScheme(
724                   af.getViewport(), af.getViewport().getAlignment(), data);
725
726           if (cs != null)
727           {
728             System.out.println(
729                     "CMD [-color " + data + "] executed successfully!");
730           }
731           af.changeColour(cs);
732         }
733
734         // Must maintain ability to use the groups flag
735         data = aparser.getValue(ArgsParser.GROUPS, true);
736         if (data != null)
737         {
738           af.parseFeaturesFile(data,
739                   AppletFormatAdapter.checkProtocol(data));
740           // System.out.println("Added " + data);
741           System.out.println(
742                   "CMD groups[-" + data + "]  executed successfully!");
743         }
744         data = aparser.getValue(ArgsParser.FEATURES, true);
745         if (data != null)
746         {
747           af.parseFeaturesFile(data,
748                   AppletFormatAdapter.checkProtocol(data));
749           // System.out.println("Added " + data);
750           System.out.println(
751                   "CMD [-features " + data + "]  executed successfully!");
752         }
753
754         data = aparser.getValue(ArgsParser.ANNOTATIONS, true);
755         if (data != null)
756         {
757           af.loadJalviewDataFile(data, null, null, null);
758           // System.out.println("Added " + data);
759           System.out.println(
760                   "CMD [-annotations " + data + "] executed successfully!");
761         }
762
763         if (aparser.contains(ArgsParser.SHOWOVERVIEW))
764         {
765           af.overviewMenuItem_actionPerformed(null);
766           System.out.println("CMD [showoverview] executed successfully!");
767         }
768
769         // set or clear the sortbytree flag.
770         if (aparser.contains(ArgsParser.SORTBYTREE))
771         {
772           af.getViewport().setSortByTree(true);
773           if (af.getViewport().getSortByTree())
774           {
775             System.out.println("CMD [-sortbytree] executed successfully!");
776           }
777         }
778
779         boolean doUpdateAnnotation = false;
780
781         /**
782          * we do this earlier in JalviewJS because of a complication with
783          * SHOWOVERVIEW
784          * 
785          * For now, just fixing this in JalviewJS.
786          *
787          * 
788          * @j2sIgnore
789          * 
790          */
791         {
792           if (aparser.contains(ArgsParser.NOANNOTATION)
793                   || aparser.contains(ArgsParser.NOANNOTATION2))
794           {
795             af.getViewport().setShowAnnotation(false);
796             if (!af.getViewport().isShowAnnotation())
797             {
798               doUpdateAnnotation = true;
799               System.out
800                       .println("CMD no-annotation executed successfully!");
801             }
802           }
803         }
804         if (aparser.contains(ArgsParser.NOSORTBYTREE))
805         {
806           af.getViewport().setSortByTree(false);
807           if (!af.getViewport().getSortByTree())
808           {
809             doUpdateAnnotation = true;
810             System.out
811                     .println("CMD [-nosortbytree] executed successfully!");
812           }
813         }
814         if (doUpdateAnnotation)
815         { // BH 2019.07.24
816           af.setMenusForViewport();
817           af.alignPanel.updateLayout();
818         }
819         data = aparser.getValue(ArgsParser.TREE, true);
820         if (data != null)
821         {
822           try
823           {
824             System.out.println(
825                     "CMD [-tree " + data + "] executed successfully!");
826             NewickFile nf = new NewickFile(data,
827                     AppletFormatAdapter.checkProtocol(data));
828             af.getViewport()
829                     .setCurrentTree(af.showNewickTree(nf, data).getTree());
830           } catch (IOException ex)
831           {
832             System.err.println("Couldn't add tree " + data);
833             ex.printStackTrace(System.err);
834           }
835         }
836         // TODO - load PDB structure(s) to alignment JAL-629
837         // (associate with identical sequence in alignment, or a specified
838         // sequence)
839         if (isJavaAppletTag)
840         {
841           loadAppletParams(aparser, af);
842         }
843         else if (!isJS)
844         /**
845          * Java only
846          * 
847          * @j2sIgnore
848          */
849         {
850           if (groovyscript != null)
851           {
852             // Execute the groovy script after we've done all the rendering
853             // stuff
854             // and before any images or figures are generated.
855             System.out.println("Executing script " + groovyscript);
856             executeGroovyScript(groovyscript, af);
857             System.out.println("CMD groovy[" + groovyscript
858                     + "] executed successfully!");
859             groovyscript = null;
860           }
861         }
862         checkOutputFile(aparser, af, format);
863         while (aparser.getSize() > 0)
864         {
865           System.out.println("Unknown arg: " + aparser.nextValue());
866         }
867       }
868     }
869     AlignFrame startUpAlframe = null;
870     // We'll only open the default file if the desktop is visible.
871     // And the user
872     // ////////////////////
873
874     if (!isJS && !headless && file == null && !haveImport
875             && jalview.bin.Cache.getDefault("SHOW_STARTUP_FILE", true))
876     /**
877      * Java only
878      * 
879      * @j2sIgnore
880      */
881     {
882       file = jalview.bin.Cache.getDefault("STARTUP_FILE",
883               jalview.bin.Cache.getDefault("www.jalview.org",
884                       "http://www.jalview.org")
885                       + "/examples/exampleFile_2_7.jar");
886       if (file.equals(
887               "http://www.jalview.org/examples/exampleFile_2_3.jar"))
888       {
889         // hardwire upgrade of the startup file
890         file.replace("_2_3.jar", "_2_7.jar");
891         // and remove the stale setting
892         jalview.bin.Cache.removeProperty("STARTUP_FILE");
893       }
894
895       protocol = DataSourceType.FILE;
896
897       if (file.indexOf("http:") > -1)
898       {
899         protocol = DataSourceType.URL;
900       }
901
902       if (file.endsWith(".jar"))
903       {
904         format = FileFormat.Jalview;
905       }
906       else
907       {
908         try
909         {
910           format = new IdentifyFile().identify(file, protocol);
911         } catch (FileFormatException e)
912         {
913           // TODO what?
914         }
915       }
916
917       startUpAlframe = new FileLoader(!headless)
918               .loadFileWaitTillLoaded(file, protocol, format);
919       // extract groovy arguments before anything else.
920     }
921
922     // Once all other stuff is done, execute any groovy scripts (in order)
923     if (groovyscript != null)
924     {
925       if (Cache.groovyJarsPresent())
926       {
927         System.out.println("Executing script " + groovyscript);
928         executeGroovyScript(groovyscript, startUpAlframe);
929       }
930       else
931       {
932         System.err.println(
933                 "Sorry. Groovy Support is not available, so ignoring the provided groovy script "
934                         + groovyscript);
935       }
936     }
937     // and finally, turn off batch mode indicator - if the desktop still exists
938     if (desktop != null)
939     {
940       if (progress != -1)
941       {
942         desktop.setProgressBar(null, progress);
943       }
944       desktop.setInBatchMode(false);
945     }
946
947     return null;
948   }
949
950   private boolean checkStartVamas(ArgsParser aparser)
951   {
952     String vamsasImport = aparser.getValue(ArgsParser.VDOC);
953     String vamsasSession = aparser.getValue(ArgsParser.VSESS);
954     if (vamsasImport == null && vamsasSession == null)
955     {
956       return false;
957     }
958     if (desktop == null || headless)
959     {
960       System.out.println(
961               "Headless vamsas sessions not yet supported. Sorry.");
962       System.exit(1);
963     }
964     boolean haveImport = (vamsasImport != null);
965     if (haveImport)
966     {
967       // if we have a file, start a new session and import it.
968       boolean inSession = false;
969       try
970       {
971         DataSourceType viprotocol = AppletFormatAdapter
972                 .checkProtocol(vamsasImport);
973         if (viprotocol == DataSourceType.FILE)
974         {
975           inSession = desktop.vamsasImport(new File(vamsasImport));
976         }
977         else if (viprotocol == DataSourceType.URL)
978         {
979           inSession = desktop.vamsasImport(new URL(vamsasImport));
980         }
981
982       } catch (Exception e)
983       {
984         System.err.println("Exeption when importing " + vamsasImport
985                 + " as a vamsas document.");
986         e.printStackTrace();
987       }
988       if (!inSession)
989       {
990         System.err.println("Failed to import " + vamsasImport
991                 + " as a vamsas document.");
992       }
993       else
994       {
995         System.out.println("Imported Successfully into new session "
996                 + desktop.getVamsasApplication().getCurrentSession());
997       }
998     }
999     if (vamsasSession != null)
1000     {
1001       if (vamsasImport != null)
1002       {
1003         // close the newly imported session and import the Jalview specific
1004         // remnants into the new session later on.
1005         desktop.vamsasStop_actionPerformed(null);
1006       }
1007       // now join the new session
1008       try
1009       {
1010         if (desktop.joinVamsasSession(vamsasSession))
1011         {
1012           System.out.println(
1013                   "Successfully joined vamsas session " + vamsasSession);
1014         }
1015         else
1016         {
1017           System.err.println("WARNING: Failed to join vamsas session "
1018                   + vamsasSession);
1019         }
1020       } catch (Exception e)
1021       {
1022         System.err.println(
1023                 "ERROR: Failed to join vamsas session " + vamsasSession);
1024         e.printStackTrace();
1025       }
1026       if (vamsasImport != null)
1027       {
1028         // the Jalview specific remnants can now be imported into the new
1029         // session at the user's leisure.
1030         Cache.log.info(
1031                 "Skipping Push for import of data into existing vamsas session.");
1032         // TODO:
1033         // enable
1034         // this
1035         // when
1036         // debugged
1037         // desktop.getVamsasApplication().push_update();
1038       }
1039     }
1040     return haveImport;
1041   }
1042
1043   private void checkOutputFile(ArgsParser aparser, AlignFrame af,
1044           FileFormatI format)
1045   {
1046     String imageName = "unnamed.png";
1047     while (aparser.getSize() > 1)
1048     {
1049       // PNG filename
1050       // SVG filename
1051       // HTML filename
1052       // biojsmsa filename
1053       String outputFormat = aparser.nextValue();
1054       String file = aparser.nextValue();
1055       System.out.println("format " + outputFormat);
1056
1057       if (outputFormat.equalsIgnoreCase("png"))
1058       {
1059         af.createPNG(new File(file));
1060         imageName = (new File(file)).getName();
1061         System.out.println("Creating PNG image: " + file);
1062         continue;
1063       }
1064       else if (outputFormat.equalsIgnoreCase("svg"))
1065       {
1066         File imageFile = new File(file);
1067         imageName = imageFile.getName();
1068         af.createSVG(imageFile);
1069         System.out.println("Creating SVG image: " + file);
1070         continue;
1071       }
1072       else if (outputFormat.equalsIgnoreCase("html"))
1073       {
1074         File imageFile = new File(file);
1075         imageName = imageFile.getName();
1076         HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
1077         htmlSVG.exportHTML(file);
1078
1079         System.out.println("Creating HTML image: " + file);
1080         continue;
1081       }
1082       else if (outputFormat.equalsIgnoreCase("biojsmsa"))
1083       {
1084         if (file == null)
1085         {
1086           System.err.println("The output html file must not be null");
1087           return;
1088         }
1089         try
1090         {
1091           BioJsHTMLOutput.refreshVersionInfo(
1092                   BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY);
1093         } catch (URISyntaxException e)
1094         {
1095           e.printStackTrace();
1096         }
1097         BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel);
1098         bjs.exportHTML(file);
1099         System.out.println("Creating BioJS MSA Viwer HTML file: " + file);
1100         continue;
1101       }
1102       else if (outputFormat.equalsIgnoreCase("imgMap"))
1103       {
1104         af.createImageMap(new File(file), imageName);
1105         System.out.println("Creating image map: " + file);
1106         continue;
1107       }
1108       else if (outputFormat.equalsIgnoreCase("eps"))
1109       {
1110         File outputFile = new File(file);
1111         System.out.println(
1112                 "Creating EPS file: " + outputFile.getAbsolutePath());
1113         af.createEPS(outputFile);
1114         continue;
1115       }
1116
1117       af.saveAlignment(file, format);
1118       if (af.isSaveAlignmentSuccessful())
1119       {
1120         System.out.println(
1121                 "Written alignment in " + format + " format to " + file);
1122       }
1123       else
1124       {
1125         System.out.println("Error writing file " + file + " in " + format
1126                 + " format!!");
1127       }
1128
1129     }
1130   }
1131
1132   private static void showUsage()
1133   {
1134     System.out.println(
1135             "Usage: jalview -open [FILE] [OUTPUT_FORMAT] [OUTPUT_FILE]\n\n"
1136                     + "-nodisplay\tRun Jalview without User Interface.\n"
1137                     + "-props FILE\tUse the given Jalview properties file instead of users default.\n"
1138                     + "-colour COLOURSCHEME\tThe colourscheme to be applied to the alignment\n"
1139                     + "-annotations FILE\tAdd precalculated annotations to the alignment.\n"
1140                     + "-tree FILE\tLoad the given newick format tree file onto the alignment\n"
1141                     + "-features FILE\tUse the given file to mark features on the alignment.\n"
1142                     + "-fasta FILE\tCreate alignment file FILE in Fasta format.\n"
1143                     + "-clustal FILE\tCreate alignment file FILE in Clustal format.\n"
1144                     + "-pfam FILE\tCreate alignment file FILE in PFAM format.\n"
1145                     + "-msf FILE\tCreate alignment file FILE in MSF format.\n"
1146                     + "-pileup FILE\tCreate alignment file FILE in Pileup format\n"
1147                     + "-pir FILE\tCreate alignment file FILE in PIR format.\n"
1148                     + "-blc FILE\tCreate alignment file FILE in BLC format.\n"
1149                     + "-json FILE\tCreate alignment file FILE in JSON format.\n"
1150                     + "-jalview FILE\tCreate alignment file FILE in Jalview format.\n"
1151                     + "-png FILE\tCreate PNG image FILE from alignment.\n"
1152                     + "-svg FILE\tCreate SVG image FILE from alignment.\n"
1153                     + "-html FILE\tCreate HTML file from alignment.\n"
1154                     + "-biojsMSA FILE\tCreate BioJS MSA Viewer HTML file from alignment.\n"
1155                     + "-imgMap FILE\tCreate HTML file FILE with image map of PNG image.\n"
1156                     + "-eps FILE\tCreate EPS file FILE from alignment.\n"
1157                     + "-questionnaire URL\tQueries the given URL for information about any Jalview user questionnaires.\n"
1158                     + "-noquestionnaire\tTurn off questionnaire check.\n"
1159                     + "-nonews\tTurn off check for Jalview news.\n"
1160                     + "-nousagestats\tTurn off google analytics tracking for this session.\n"
1161                     + "-sortbytree OR -nosortbytree\tEnable or disable sorting of the given alignment by the given tree\n"
1162                     // +
1163                     // "-setprop PROPERTY=VALUE\tSet the given Jalview property,
1164                     // after all other properties files have been read\n\t
1165                     // (quote the 'PROPERTY=VALUE' pair to ensure spaces are
1166                     // passed in correctly)"
1167                     + "-jabaws URL\tSpecify URL for Jabaws services (e.g. for a local installation).\n"
1168                     + "-fetchfrom nickname\tQuery nickname for features for the alignments and display them.\n"
1169                     // +
1170                     // "-vdoc vamsas-document\tImport vamsas document into new
1171                     // session or join existing session with same URN\n"
1172                     // + "-vses vamsas-session\tJoin session with given URN\n"
1173                     + "-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"
1174                     + "\n~Read documentation in Application or visit http://www.jalview.org for description of Features and Annotations file~\n\n");
1175   }
1176
1177   private static void startUsageStats(final Desktop desktop)
1178   {
1179     /**
1180      * start a User Config prompt asking if we can log usage statistics.
1181      */
1182     PromptUserConfig prompter = new PromptUserConfig(
1183             Desktop.getDesktopPane(), "USAGESTATS",
1184             "Jalview Usage Statistics",
1185             "Do you want to help make Jalview better by enabling "
1186                     + "the collection of usage statistics with Google Analytics ?"
1187                     + "\n\n(you can enable or disable usage tracking in the preferences)",
1188             new Runnable()
1189             {
1190               @Override
1191               public void run()
1192               {
1193                 Cache.log.debug(
1194                         "Initialising googletracker for usage stats.");
1195                 Cache.initGoogleTracker();
1196                 Cache.log.debug("Tracking enabled.");
1197               }
1198             }, new Runnable()
1199             {
1200               @Override
1201               public void run()
1202               {
1203                 Cache.log.debug("Not enabling Google Tracking.");
1204               }
1205             }, null, true);
1206     desktop.addDialogThread(prompter);
1207   }
1208
1209   /**
1210    * Locate the given string as a file and pass it to the groovy interpreter.
1211    * 
1212    * @param groovyscript
1213    *          the script to execute
1214    * @param jalviewContext
1215    *          the Jalview Desktop object passed in to the groovy binding as the
1216    *          'Jalview' object.
1217    */
1218   private void executeGroovyScript(String groovyscript, AlignFrame af)
1219   {
1220     /**
1221      * for scripts contained in files
1222      */
1223     File tfile = null;
1224     /**
1225      * script's URI
1226      */
1227     URL sfile = null;
1228     if (groovyscript.trim().equals("STDIN"))
1229     {
1230       // read from stdin into a tempfile and execute it
1231       try
1232       {
1233         tfile = File.createTempFile("jalview", "groovy");
1234         PrintWriter outfile = new PrintWriter(
1235                 new OutputStreamWriter(new FileOutputStream(tfile)));
1236         BufferedReader br = new BufferedReader(
1237                 new InputStreamReader(System.in));
1238         String line = null;
1239         while ((line = br.readLine()) != null)
1240         {
1241           outfile.write(line + "\n");
1242         }
1243         br.close();
1244         outfile.flush();
1245         outfile.close();
1246
1247       } catch (Exception ex)
1248       {
1249         System.err.println("Failed to read from STDIN into tempfile "
1250                 + ((tfile == null) ? "(tempfile wasn't created)"
1251                         : tfile.toString()));
1252         ex.printStackTrace();
1253         return;
1254       }
1255       try
1256       {
1257         sfile = tfile.toURI().toURL();
1258       } catch (Exception x)
1259       {
1260         System.err.println(
1261                 "Unexpected Malformed URL Exception for temporary file created from STDIN: "
1262                         + tfile.toURI());
1263         x.printStackTrace();
1264         return;
1265       }
1266     }
1267     else
1268     {
1269       try
1270       {
1271         sfile = new URI(groovyscript).toURL();
1272       } catch (Exception x)
1273       {
1274         tfile = new File(groovyscript);
1275         if (!tfile.exists())
1276         {
1277           System.err.println("File '" + groovyscript + "' does not exist.");
1278           return;
1279         }
1280         if (!tfile.canRead())
1281         {
1282           System.err.println("File '" + groovyscript + "' cannot be read.");
1283           return;
1284         }
1285         if (tfile.length() < 1)
1286         {
1287           System.err.println("File '" + groovyscript + "' is empty.");
1288           return;
1289         }
1290         try
1291         {
1292           sfile = tfile.getAbsoluteFile().toURI().toURL();
1293         } catch (Exception ex)
1294         {
1295           System.err.println("Failed to create a file URL for "
1296                   + tfile.getAbsoluteFile());
1297           return;
1298         }
1299       }
1300     }
1301     try
1302     {
1303       Map<String, Object> vbinding = new HashMap<>();
1304       vbinding.put("Jalview", this);
1305       if (af != null)
1306       {
1307         vbinding.put("currentAlFrame", af);
1308       }
1309       Binding gbinding = new Binding(vbinding);
1310       GroovyScriptEngine gse = new GroovyScriptEngine(new URL[] { sfile });
1311       gse.run(sfile.toString(), gbinding);
1312       if ("STDIN".equals(groovyscript))
1313       {
1314         // delete temp file that we made -
1315         // only if it was successfully executed
1316         tfile.delete();
1317       }
1318     } catch (Exception e)
1319     {
1320       System.err.println("Exception Whilst trying to execute file " + sfile
1321               + " as a groovy script.");
1322       e.printStackTrace(System.err);
1323
1324     }
1325   }
1326
1327   public AlignFrame[] getAlignFrames()
1328   {
1329     return desktop == null ? new AlignFrame[] { getCurrentAlignFrame() }
1330             : Desktop.getAlignFrames();
1331
1332   }
1333
1334   /**
1335    * Quit method delegates to Desktop.quit - unless running in headless mode
1336    * when it just ends the JVM
1337    */
1338   public void quit()
1339   {
1340     if (jsFunctionExec != null)
1341     {
1342       jsFunctionExec.tidyUp();
1343       jsFunctionExec = null;
1344     }
1345
1346     if (desktop != null)
1347     {
1348       desktop.quit();
1349     }
1350     else
1351     {
1352       System.exit(0);
1353     }
1354   }
1355
1356   /**
1357    * Get the SwingJS applet ID and combine that with the frameType
1358    * 
1359    * @param frameType
1360    *          "alignment", "desktop", etc., or null
1361    * @return
1362    */
1363   public static String getAppID(String frameType)
1364   {
1365     String id = Cache.getProperty("Info.j2sAppletID");
1366     if (id == null)
1367     {
1368       id = "jalview";
1369     }
1370     return id + (frameType == null ? "" : "-" + frameType);
1371   }
1372
1373   /**
1374    * Handle all JalviewLite applet parameters
1375    * 
1376    * @param aparser
1377    * @param af
1378    */
1379   private void loadAppletParams(ArgsParser aparser, AlignFrame af)
1380   {
1381     JalviewApp app = new JalviewApp()
1382     {
1383
1384       // TODO BH 2019
1385       //
1386       // These are methods that are in JalviewLite that various classes call
1387       // but are not in JalviewLiteJsApi. Or, even if they are, other classes
1388       // call
1389       // them to JalviewLite directly. Some may not be necessary, but they have
1390       // to
1391       // be at least mentioned here, or the classes calling them should
1392       // reference
1393       // JalviewLite itself.
1394
1395       private boolean alignPDBStructures; // From JalviewLite; not implemented
1396
1397       private Hashtable<String, Hashtable<String, String[]>> jsmessages;
1398
1399       private Hashtable<String, int[]> jshashes;
1400
1401       @Override
1402       public String getParameter(String name)
1403       {
1404         return aparser.getAppletValue(name, null);
1405       }
1406
1407       @Override
1408       public boolean getDefaultParameter(String name, boolean def)
1409       {
1410         String stn;
1411         return ((stn = getParameter(name)) == null ? def
1412                 : "true".equalsIgnoreCase(stn));
1413       }
1414
1415       /**
1416        * Get the applet-like document base even though this is an application.
1417        */
1418       @Override
1419       public URL getDocumentBase()
1420       {
1421         return Platform.getDocumentBase();
1422       }
1423
1424       /**
1425        * Get the applet-like code base even though this is an application.
1426        */
1427       @Override
1428       public URL getCodeBase()
1429       {
1430         return Platform.getCodeBase();
1431       }
1432
1433       @Override
1434       public AlignViewportI getViewport()
1435       {
1436         return af.getViewport();
1437       }
1438
1439       /**
1440        * features
1441        * 
1442        */
1443       @Override
1444       public boolean parseFeaturesFile(String filename,
1445               DataSourceType protocol)
1446       {
1447         return af.parseFeaturesFile(filename, protocol);
1448       }
1449
1450       /**
1451        * scorefile
1452        * 
1453        */
1454       @Override
1455       public boolean loadScoreFile(String sScoreFile) throws IOException
1456       {
1457         af.loadJalviewDataFile(sScoreFile, null, null, null);
1458         return true;
1459       }
1460
1461       /**
1462        * annotations, jpredfile, jnetfile
1463        * 
1464        */
1465       @Override
1466       public void updateForAnnotations()
1467       {
1468         af.updateForAnnotations();
1469       }
1470
1471       @Override
1472       public void loadTree(NewickFile fin, String treeFile)
1473               throws IOException
1474       {
1475         // n/a -- already done by standard Jalview command line processing
1476       }
1477
1478       @Override
1479       public void setAlignPdbStructures(boolean defaultParameter)
1480       {
1481         alignPDBStructures = true;
1482       }
1483
1484       @Override
1485       public void newStructureView(PDBEntry pdb, SequenceI[] seqs,
1486               String[] chains, DataSourceType protocol)
1487       {
1488         StructureViewer.launchStructureViewer(af.alignPanel, pdb, seqs);
1489       }
1490
1491       @Override
1492       public void setFeatureGroupState(String[] groups, boolean state)
1493       {
1494         af.setFeatureGroupState(groups, state);
1495       }
1496
1497       @Override
1498       public void alignedStructureView(PDBEntry[] pdb, SequenceI[][] seqs,
1499               String[][] chains, String[] protocols)
1500       {
1501         System.err.println(
1502                 "Jalview applet interface alignedStructureView not implemented");
1503       }
1504
1505       @Override
1506       public void newFeatureSettings()
1507       {
1508         System.err.println(
1509                 "Jalview applet interface newFeatureSettings not implemented");
1510       }
1511
1512       private Vector<Runnable> jsExecQueue;
1513
1514       @Override
1515       public Vector<Runnable> getJsExecQueue(JSFunctionExec exec)
1516       {
1517         jsFunctionExec = exec;
1518         return (jsExecQueue == null ? (jsExecQueue = new Vector<>())
1519                 : jsExecQueue);
1520       }
1521
1522       @Override
1523       public AppletContext getAppletContext()
1524       {
1525         // TODO Auto-generated method stub
1526         return null;
1527       }
1528
1529       @Override
1530       public boolean isJsfallbackEnabled()
1531       {
1532         // TODO Auto-generated method stub
1533         return false;
1534       }
1535
1536       @Override
1537       public JSObject getJSObject()
1538       {
1539         // TODO Auto-generated method stub
1540         return null;
1541       }
1542
1543       @Override
1544       public StructureSelectionManagerProvider getStructureSelectionManagerProvider()
1545       {
1546         // TODO Q: what exactly is this? BH
1547         return null;
1548       }
1549
1550       @Override
1551       public void updateColoursFromMouseOver(Object source,
1552               MouseOverStructureListener mouseOverStructureListener)
1553       {
1554         // TODO Auto-generated method stub
1555
1556       }
1557
1558       @Override
1559       public Object[] getSelectionForListener(SequenceGroup seqsel,
1560               ColumnSelection colsel, HiddenColumns hidden,
1561               SelectionSource source, Object alignFrame)
1562       {
1563         return appLoader.getSelectionForListener(getCurrentAlignFrame(),
1564                 seqsel, colsel, hidden, source, alignFrame);
1565       }
1566
1567       @Override
1568       public String arrayToSeparatorList(String[] array)
1569       {
1570         return appLoader.arrayToSeparatorList(array);
1571       }
1572
1573       @Override
1574       public Hashtable<String, int[]> getJSHashes()
1575       {
1576         return (jshashes == null ? (jshashes = new Hashtable<>())
1577                 : jshashes);
1578       }
1579
1580       @Override
1581       public Hashtable<String, Hashtable<String, String[]>> getJSMessages()
1582       {
1583         return (jsmessages == null ? (jsmessages = new Hashtable<>())
1584                 : jsmessages);
1585       }
1586
1587       @Override
1588       public Object getFrameForSource(VamsasSource source)
1589       {
1590         if (source != null)
1591         {
1592           AlignFrame af;
1593           if (source instanceof jalview.gui.AlignViewport
1594                   && source == (af = getCurrentAlignFrame()).getViewport())
1595           {
1596             // should be valid if it just generated an event!
1597             return af;
1598           }
1599           // TODO: ensure that if '_af' is specified along with a handler
1600           // function, then only events from that alignFrame are sent to that
1601           // function
1602         }
1603         return null;
1604       }
1605
1606       @Override
1607       public FeatureRenderer getNewFeatureRenderer(AlignViewportI vp)
1608       {
1609         return new jalview.gui.FeatureRenderer((AlignmentPanel) vp);
1610       }
1611
1612     };
1613
1614     appLoader = new JalviewAppLoader(true);
1615     appLoader.load(app);
1616   }
1617
1618   /**
1619    * 
1620    * @see jalview.bin.JalviewLiteJsApi#getSelectedSequences()
1621    */
1622   @Override
1623   public String getSelectedSequences()
1624   {
1625     return getSelectedSequencesFrom(getCurrentAlignFrame());
1626   }
1627
1628   /**
1629    * 
1630    * @see jalview.bin.JalviewLiteJsApi#getSelectedSequences(java.lang.String)
1631    */
1632   @Override
1633   public String getSelectedSequences(String sep)
1634   {
1635     return getSelectedSequencesFrom(getCurrentAlignFrame(), sep);
1636   }
1637
1638   /**
1639    * 
1640    * @see jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui
1641    *      .AlignFrame)
1642    */
1643   @Override
1644   public String getSelectedSequencesFrom(AlignFrameI alf)
1645   {
1646     if (alf == null)
1647     {
1648       alf = getCurrentAlignFrame();
1649     }
1650     return getSelectedSequencesFrom(alf, null);
1651   }
1652
1653   /**
1654    * 
1655    * @see jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui
1656    *      .AlignFrame, java.lang.String)
1657    */
1658   @Override
1659   public String getSelectedSequencesFrom(AlignFrameI alf, String sep)
1660   {
1661     if (alf == null)
1662     {
1663       alf = getCurrentAlignFrame();
1664     }
1665     return appLoader.getSelectedSequencesFrom(alf, sep);
1666   }
1667
1668   /**
1669    * 
1670    * @see jalview.bin.JalviewLiteJsApi#getSelectedSequencesFrom(jalview.appletgui
1671    *      .AlignFrame, java.lang.String)
1672    */
1673   @Override
1674   public void highlight(String sequenceId, String position,
1675           String alignedPosition)
1676   {
1677     highlightIn(null, sequenceId, position,
1678             alignedPosition);
1679   }
1680
1681   @Override
1682   public void highlightIn(AlignFrameI alf, String sequenceId,
1683           String position, String alignedPosition)
1684   {
1685     if (alf == null)
1686     {
1687       alf = getCurrentAlignFrame();
1688     }
1689     appLoader.highlightIn(alf, sequenceId, position, alignedPosition);
1690   }
1691
1692   @Override
1693   public void select(String sequenceIds, String columns)
1694   {
1695     selectIn(getCurrentAlignFrame(), sequenceIds, columns, null);
1696   }
1697
1698   @Override
1699   public void select(String sequenceIds, String columns, String sep)
1700   {
1701     selectIn(null, sequenceIds, columns, sep);
1702   }
1703
1704   @Override
1705   public void selectIn(AlignFrameI alf, String sequenceIds, String columns)
1706   {
1707     selectIn(alf, sequenceIds, columns, null);
1708   }
1709
1710   @Override
1711   public void selectIn(AlignFrameI alf, String sequenceIds, String columns,
1712           String sep)
1713   {
1714     if (alf == null)
1715     {
1716       alf = getCurrentAlignFrame();
1717     }
1718     appLoader.selectIn(alf, sequenceIds, columns, sep);
1719   }
1720
1721   @Override
1722   public String getSelectedSequencesAsAlignment(String format,
1723           String suffix)
1724   {
1725     return getSelectedSequencesAsAlignmentFrom(null,
1726             format, suffix);
1727   }
1728
1729   @Override
1730   public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf,
1731           String format, String sep)
1732   {
1733     if (alf == null)
1734     {
1735       alf = getCurrentAlignFrame();
1736     }
1737     return appLoader.getSelectedSequencesAsAlignmentFrom(alf, format, sep);
1738   }
1739
1740   @Override
1741   public String getAlignmentOrder()
1742   {
1743     return getAlignmentFrom(getCurrentAlignFrame(), null);
1744   }
1745
1746   @Override
1747   public String getAlignmentOrderFrom(AlignFrameI alf)
1748   {
1749     return getAlignmentFrom(alf, null);
1750   }
1751
1752   @Override
1753   public String getAlignmentOrderFrom(AlignFrameI alf, String sep)
1754   {
1755     if (alf == null)
1756     {
1757       alf = getCurrentAlignFrame();
1758     }
1759     return appLoader.getAlignmentOrderFrom(alf, sep);
1760   }
1761
1762   @Override
1763   public String orderBy(String order, String undoName)
1764   {
1765     return orderBy(order, undoName, null);
1766   }
1767
1768   @Override
1769   public String orderBy(String order, String undoName, String sep)
1770   {
1771     return orderAlignmentBy(getCurrentAlignFrame(), order, undoName, sep);
1772   }
1773
1774   @Override
1775   public String orderAlignmentBy(AlignFrameI alf, String order,
1776           String undoName, String sep)
1777   {
1778     if (alf == null)
1779     {
1780       alf = getCurrentAlignFrame();
1781     }
1782     return appLoader.orderAlignmentBy(alf, order, undoName, sep);
1783   }
1784
1785   @Override
1786   public String getAlignment(String format)
1787   {
1788     return getAlignmentFrom(null, format, null);
1789   }
1790
1791   @Override
1792   public String getAlignmentFrom(AlignFrameI alf, String format)
1793   {
1794     return getAlignmentFrom(alf, format, null);
1795   }
1796
1797   @Override
1798   public String getAlignment(String format, String suffix)
1799   {
1800     return getAlignmentFrom(getCurrentAlignFrame(), format, suffix);
1801   }
1802
1803   @Override
1804   public String getAlignmentFrom(AlignFrameI alf, String format,
1805           String suffix)
1806   {
1807     return appLoader.getAlignmentFrom(alf, format, suffix);
1808   }
1809
1810   @Override
1811   public void loadAnnotation(String annotation)
1812   {
1813     loadAnnotationFrom(getCurrentAlignFrame(), annotation);
1814   }
1815
1816   @Override
1817   public void loadAnnotationFrom(AlignFrameI alf, String annotation)
1818   {
1819     if (alf == null)
1820     {
1821       alf = getCurrentAlignFrame();
1822     }
1823     appLoader.loadAnnotationFrom(alf, annotation);
1824   }
1825
1826   @Override
1827   public void loadFeatures(String features, boolean autoenabledisplay)
1828   {
1829     loadFeaturesFrom(currentAlignFrame, features, autoenabledisplay);
1830   }
1831
1832   @Override
1833   public boolean loadFeaturesFrom(AlignFrameI alf, String features,
1834           boolean autoenabledisplay)
1835   {
1836     if (alf == null)
1837     {
1838       alf = getCurrentAlignFrame();
1839     }
1840     return appLoader.loadFeaturesFrom(alf, features, autoenabledisplay);
1841   }
1842
1843   @Override
1844   public String getFeatures(String format)
1845   {
1846     return getFeaturesFrom(null, format);
1847   }
1848
1849   @Override
1850   public String getFeaturesFrom(AlignFrameI alf, String format)
1851   {
1852     if (alf == null)
1853     {
1854       alf = getCurrentAlignFrame();
1855     }
1856     return appLoader.getFeaturesFrom(alf, format);
1857   }
1858
1859   @Override
1860   public String getAnnotation()
1861   {
1862     return getAnnotationFrom(null);
1863   }
1864
1865   @Override
1866   public String getAnnotationFrom(AlignFrameI alf)
1867   {
1868     if (alf == null)
1869     {
1870       alf = getCurrentAlignFrame();
1871     }
1872     return appLoader.getAnnotationFrom(alf);
1873   }
1874
1875   @Override
1876   public AlignFrameI newView()
1877   {
1878     return newViewFrom(null, null);
1879   }
1880
1881   @Override
1882   public AlignFrameI newView(String name)
1883   {
1884     return newViewFrom(null, name);
1885   }
1886
1887   @Override
1888   public AlignFrameI newViewFrom(AlignFrameI alf)
1889   {
1890     return newViewFrom(alf, null);
1891   }
1892
1893   @Override
1894   public AlignFrameI newViewFrom(AlignFrameI alf, String name)
1895   {
1896     if (alf == null)
1897     {
1898       alf = getCurrentAlignFrame();
1899     }
1900     return appLoader.newViewFrom(alf, name);
1901   }
1902
1903   @Override
1904   public AlignFrameI loadAlignment(String text, String title)
1905   {
1906     return appLoader.loadAlignment(text, AlignFrame.DEFAULT_WIDTH,
1907             AlignFrame.DEFAULT_HEIGHT, title);
1908   }
1909
1910   @Override
1911   public boolean addPdbFile(AlignFrameI alFrame, String sequenceId,
1912           String pdbEntryString, String pdbFile)
1913   {
1914     if (alFrame == null)
1915     {
1916       alFrame = getCurrentAlignFrame();
1917     }
1918     return appLoader.addPdbFile(alFrame, sequenceId, pdbEntryString,
1919             pdbFile);
1920   }
1921
1922   @Override
1923   public void scrollViewToIn(AlignFrameI alf, String topRow,
1924           String leftHandColumn)
1925   {
1926     if (alf == null)
1927     {
1928       alf = getCurrentAlignFrame();
1929     }
1930     appLoader.scrollViewToIn(alf, topRow, leftHandColumn);
1931   }
1932
1933   @Override
1934   public void scrollViewToRowIn(AlignFrameI alf, String topRow)
1935   {
1936     if (alf == null)
1937     {
1938       alf = getCurrentAlignFrame();
1939     }
1940     appLoader.scrollViewToRowIn(alf, topRow);
1941   }
1942
1943   @Override
1944   public void scrollViewToColumnIn(AlignFrameI alf, String leftHandColumn)
1945   {
1946     if (alf == null)
1947     {
1948       alf = getCurrentAlignFrame();
1949     }
1950     appLoader.scrollViewToColumnIn(alf, leftHandColumn);
1951   }
1952
1953   @Override
1954   public String getFeatureGroups()
1955   {
1956     return getFeatureGroupsOn(null);
1957   }
1958
1959   @Override
1960   public String getFeatureGroupsOn(AlignFrameI alf)
1961   {
1962     if (alf == null)
1963     {
1964       alf = getCurrentAlignFrame();
1965     }
1966     return appLoader.getFeatureGroupsOn(alf);
1967   }
1968
1969   @Override
1970   public String getFeatureGroupsOfState(boolean visible)
1971   {
1972     return getFeatureGroupsOfStateOn(null, visible);
1973   }
1974
1975   @Override
1976   public String getFeatureGroupsOfStateOn(AlignFrameI alf, boolean visible)
1977   {
1978     if (alf == null)
1979     {
1980       alf = getCurrentAlignFrame();
1981     }
1982     return appLoader.getFeatureGroupsOfStateOn(alf, visible);
1983   }
1984
1985   @Override
1986   public void setFeatureGroupState(String groups, boolean state)
1987   { // JalviewLite API
1988     setFeatureGroupStateOn(null, groups, state);
1989   }
1990
1991   @Override
1992   public void setFeatureGroupStateOn(AlignFrameI alf, String groups,
1993           boolean state)
1994   {
1995     if (alf == null)
1996     {
1997       alf = getCurrentAlignFrame();
1998     }
1999     appLoader.setFeatureGroupStateOn(alf, groups, state);
2000   }
2001
2002   @Override
2003   public String getSeparator()
2004   {
2005     return appLoader.getSeparator();
2006   }
2007
2008   @Override
2009   public void setSeparator(String separator)
2010   {
2011     appLoader.setSeparator(separator);
2012   }
2013
2014   @Override
2015   public String getJsMessage(String messageclass, String viewId)
2016   {
2017     // see http://www.jalview.org/examples/jalviewLiteJs.html
2018     return null;
2019   }
2020
2021   /**
2022    * Open a new Tree panel on the desktop statically. Params are standard (not
2023    * set by Groovy). No dialog is opened.
2024    * 
2025    * @param af
2026    * @param treeType
2027    * @param modelName
2028    * @return null, or the string "label.you_need_at_least_n_sequences" if number
2029    *         of sequences selected is inappropriate
2030    */
2031   @Override
2032   public Object openTreePanel(AlignFrame af, String treeType,
2033           String modelName)
2034   { // JalviewJS api
2035     if (af == null)
2036     {
2037       af = getCurrentAlignFrame();
2038     }
2039     return CalculationChooser.openTreePanel(af, treeType, modelName, null);
2040   }
2041
2042   /**
2043    * public static method for JalviewJS API to open a PCAPanel without
2044    * necessarily using a dialog.
2045    * 
2046    * @param af
2047    * @param modelName
2048    * @return the PCAPanel, or the string "label.you_need_at_least_n_sequences"
2049    *         if number of sequences selected is inappropriate
2050    */
2051   @Override
2052   public Object openPcaPanel(AlignFrame af, String modelName)
2053   {
2054     if (af == null)
2055     {
2056       af = getCurrentAlignFrame();
2057     }
2058     return CalculationChooser.openPcaPanel(af, modelName, null);
2059   }
2060
2061   @Override
2062   public String getSelectedSequencesAsAlignment(String format,
2063           boolean suffix)
2064   {
2065     return getSelectedSequencesAsAlignmentFrom(null,
2066             format, suffix);
2067   }
2068
2069   @Override
2070   public String getSelectedSequencesAsAlignmentFrom(AlignFrameI alf,
2071           String format, boolean suffix)
2072   {
2073     if (alf == null)
2074     {
2075       alf = getCurrentAlignFrame();
2076     }
2077     return appLoader.getSelectedSequencesAsAlignmentFrom(alf, format,
2078             "" + suffix);
2079   }
2080
2081   @Override
2082   public String arrayToSeparatorList(String[] array)
2083   {
2084     return appLoader.arrayToSeparatorList(array);
2085   }
2086
2087   @Override
2088   public String[] separatorListToArray(String list)
2089   {
2090     return appLoader.separatorListToArray(list);
2091   }
2092
2093   //// probably not needed in JalviewJS -- From when Jmol and Jalview did not
2094   //// have a direct connection?
2095
2096   @Override
2097   public void setMouseoverListener(String listener)
2098   {
2099     // TODO Auto-generated method stub
2100
2101   }
2102
2103   @Override
2104   public void setMouseoverListener(AlignFrameI af, String listener)
2105   {
2106     // TODO Auto-generated method stub
2107
2108   }
2109
2110   @Override
2111   public void setSelectionListener(String listener)
2112   {
2113     // TODO Auto-generated method stub
2114
2115   }
2116
2117   @Override
2118   public void setSelectionListener(AlignFrameI af, String listener)
2119   {
2120     // TODO Auto-generated method stub
2121
2122   }
2123
2124   @Override
2125   public void setStructureListener(String listener, String modelSet)
2126   {
2127     // TODO Auto-generated method stub
2128
2129   }
2130
2131   @Override
2132   public void removeJavascriptListener(AlignFrameI af, String listener)
2133   {
2134     // TODO Auto-generated method stub
2135
2136   }
2137
2138   @Override
2139   public void mouseOverStructure(String pdbResNum, String chain,
2140           String pdbfile)
2141   {
2142     // TODO Auto-generated method stub
2143
2144   }
2145
2146   @Override
2147   public void showOverview()
2148   {
2149     currentAlignFrame.overviewMenuItem_actionPerformed(null);
2150   }
2151
2152   public void notifyWorker(AlignCalcWorkerI worker, String status)
2153   {
2154     // System.out.println("Jalview worker " + worker.getClass().getSimpleName()
2155     // + " " + status);
2156   }
2157
2158 }
2159