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