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