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